v2.0.1 mega convergence - #295
Closed
0xSero wants to merge 8 commits into
Closed
Conversation
This was referenced Aug 14, 2026
…kip mobile-release] LitterTests (full unit target): 223 executed, 0 failures, 2.488s. xcresult: /Users/sero/Library/Developer/Xcode/DerivedData/Litter-eildsnwjlgvfboarwgrqgegwowll/Logs/Test/Test-Litter-2026.08.13_23-44-48--0400.xcresult UI tests (individual, iPhone 17 Pro / iOS 26.0 simulator): - UI1 testBodyEvaluationCountAt1500: PASS (87s) - UI2 testConversationScrollPerformanceAt1500: PASS (376s; scroll deceleration avg 1.886s) - UI3 testComposerKeystrokeLatency: PASS (untouched) - UI4 testBackToListPerformanceAt300Sessions: PASS (546s; back/list avg 88.405s) - testMidhistoryToolCompletionRendersResult: PASS (11s; 7-item tool-result visible as static text) Anchor rationale: the canonical seven-item midhistory fixture (mh-u1/a1, mh-u2/a2, mh-tool-K, mh-u3/a3) is the single deterministic anchor shared by the 1500-item scale gates and the 7-item visibility check. When scenario + ITEM_COUNT=N>7 are set, patternItem 0..(N-8) prepends N-7 deterministic items before the canonical seven, yielding exactly N items in stable order. Corpus: perf-0a/corpus/05-tool-file-order.json sha256 c126251a51590d29b0c39530e5899d27a63160ef0d31a87ea0feff2b4c93556a
…obile-release] P1-1a isolation kernel: routes conversation rebinds per-thread with a lossless global fallback on both platforms, with zero Rust/bindings changes. iOS: per-thread @observable ThreadRebindSignal objects (dictionary is @ObservationIgnored so foreign-thread bumps don't fan out). ConversationDestinationScreen .onChange now reads threadRebindSignal(for: key).revision + conversationGlobalRevision instead of the monolithic snapshotRevision. Bump sites: equality-guarded cacheThreadSnapshot choke point, removeThreadSnapshot (entry retained), applySnapshot publish site (change-guarded), activeThreadChanged arm. DEBUG seam _testHandleStoreUpdate for integration tests. Android: new ThreadRevisionLedger (pure Kotlin, JVM-testable) with per-thread MutableStateFlow + global StateFlow. AppModel wires bumpThread/bumpGlobal at the same choke points. ConversationScreen re-derives thread via remember(threadRevision, conversationGlobalRevision, threadKey) instead of remember(snapshot, threadKey). Signal-entry lifetime rule (both platforms): entries are never removed — dropping/re-creating a signal on thread re-add would hand live observers a dead object (iOS) or a stale remember-cached flow (Android, fatal). 23-variant AppStoreUpdateRecord classification: | # | Variant | Route | Carrier | |---|---|---|---| | 1 | fullResync | Global (+ scoped for changed threads via bulk cache) | refreshSnapshot -> applySnapshot | | 2 | serverChanged | Global | debounced refresh -> applySnapshot | | 3 | serverRemoved | Global | refreshSnapshot -> applySnapshot | | 4 | threadUpserted | Scoped | applyThreadUpsert -> cacheThreadSnapshot | | 5 | threadMetadataChanged | Scoped | direct + batched-flush -> cacheThreadSnapshot | | 6 | threadItemChanged | Scoped (item path); applySessionSummary bumps nothing | item upsert -> cacheThreadSnapshot; summary bypasses choke point | | 7 | threadStreamingDelta | Scoped (identical-delta no-op stays bump-free) | apply -> cacheThreadSnapshot | | 8 | threadRemoved | Scoped (explicit bump; signal entry retained) | removeThreadSnapshot | | 9 | activeThreadChanged | Global (unconditional arm bump) | arm-level | | 10 | pendingApprovalsChanged | Global | refreshSnapshot -> applySnapshot | | 11 | pendingUserInputsChanged | Global | same; double-covered by untouched iOS :1961 / Android :286 | | 12 | voiceSessionChanged | Global | refreshSnapshot -> applySnapshot | | 13 | savedAppsChanged | No bump (intentional) | SavedAppsStore.reload only; no snapshot publish | | 14 | realtimeTranscriptUpdated | No bump (intentional) | no-op arm | | 15 | realtimeHandoffRequested | No bump (intentional) | no-op arm | | 16 | realtimeSpeechStarted | No bump (intentional) | no-op arm | | 17 | realtimeStarted | Global | refreshSnapshot today | | 18 | realtimeSdp | No bump (intentional) | no-op arm | | 19 | realtimeOutputAudioDelta | No bump (intentional) | no-op arm; per-audio-frame bump would regress | | 20 | realtimeError | Global | refreshSnapshot today | | 21 | realtimeClosed | Global | refreshSnapshot today | | 22 | dynamicWidgetStreaming | Scoped | applyStreamingWidget -> cacheThreadSnapshot | | 23 | terminalSessionsChanged | Global | refreshSnapshot -> applySnapshot | Invariant: every variant that publishes a snapshot today maps to scoped and/or global; the six no-bump variants publish nothing today. LOC audit: production net +83 (iOS AppModel.swift +25, LitterApp.swift +3, Android AppModel.kt +10, ConversationScreen.kt +2, ThreadRevisionLedger.kt +43). Tests +138 (iOS AppSnapshotRuntimeTests +85, Android ThreadRevisionLedgerTest +53). Both within budget (prod <=90, tests <=140). iOS test result: 229 tests passed (223 existing + 6 new R1-R6), 0 failures, on iPhone 17 Pro simulator (iOS 26.0), Debug config, 69s build+test. R1 same-thread rebind: streaming delta to A bumps A's signal +1. PASS R2 foreign-thread isolation: delta to B leaves A's signal and global unchanged while snapshotRevision still bumps (proves isolation is real). PASS R3 unkeyed global: pendingApprovals publish bumps global +1, scoped +0. PASS R4 summary-only write: byte-identical item + new summary -> snapshotRevision +1 but scoped +0 and global +0 (summary bypasses choke point). PASS R5 removal semantics: threadRemoved(B) bumps B's signal, retains entry (=== identity), follow-up threadUpserted(B) continues monotonically. PASS R6 active-thread global: activeThreadChanged(nil) bumps global +1, scoped +0. PASS Android test result: authored, CI-pending. JVM toolchain (Java 21, Android SDK 35/36) is present, but the generated Kotlin UniFFI bindings (shared/rust-bridge/generated/kotlin/) are absent in this worktree. Regenerating them requires `make bindings`, which is forbidden in this slice. The :app:compileDebugKotlin task fails on a pre-existing unrelated reference (ActiveTurnWidget.kt:250 HydratedConversationItemContent) before reaching the ledger test. ThreadRevisionLedgerTest.kt is plain JVM (coroutines + StateFlow only) and will run in CI once bindings are generated. Android wiring limitation: JVM tests prove ledger semantics only (L1-L4: scoped bump, global bump, instance stability, N*M concurrency). The AppModel.kt wiring (guard placement, bump-after-publish ordering) cannot run on plain JVM (Context + native bridge); it is verified by line-diff review against the contract, by the iOS twin tests of the identical pattern, and behaviorally by the later CUA stage. Compose-level recomposition scoping has no Android counter channel at this tip (known gap; a later slice). This is an isolation/correctness kernel only. It does NOT claim any measured reduction of the 78.669s back/open mean, 0.632s composer, or 1.990s scroll numbers. Non-regression within CUA bounds is the only speed statement permitted for this slice. Attribution and reduction of those costs belong to measured follow-on slices (P1-1b onward).
…[skip mobile-release] One-line test-only hunk: move .awaitAll() outside the map lambda in L4 so it awaits the List<Deferred> (real N x M contention) instead of invoking awaitAll() on a single Deferred inside the map, which cannot compile (kotlinx.coroutines defines awaitAll only on Collection<Deferred<T>> / vararg, never on Deferred), killing the whole L1-L4 file at compileDebugUnitTestKotlin. Corrects the P1-1a commit body claim 'will run in CI once bindings are generated': missing generated bindings were not the only local blocker — this committed expression was a second blocker until this commit. Per Fable-5 ruling /Users/sero/.claude/plans/you-are-fable-5-the-zesty-stearns.md (verdict: REJECT as-landed, remedy = this bounded corrective commit; production kernel verified correct and byte-frozen). Verification: - gradle narrowest attempt (:app:testDebugUnitTest --tests '...ThreadRevisionLedgerTest') still blocked BEFORE test compilation by the pre-existing :app:compileDebugKotlin failure in ActiveTurnWidget.kt (unresolved UniFFI-generated types; bindings absent in this worktree) — not worked around. - Independent audit with the project's real Kotlin 2.0.21 compiler (kotlin-compiler-embeddable from Gradle cache) against a data-class ThreadKey stub + kotlinx-coroutines-core-jvm 1.8.1 + junit 4.13.2: committed defective line FAILS to compile (type-inference cascade at :50); this line compiles clean (exit 0, zero errors); JUnitCore run: OK (4 tests), L4 asserts exactly n*m = 5000 under 50 coroutines x 100 bumps on Dispatchers.Default. Not a claim of :app:testDebugUnitTest green — CI owns that. Scope: the five production files of 57414ba remain byte-identical (SHA-256 verified); no submodule pointers staged; no history rewrite.
…ndroid) [skip mobile-release] Add DEBUG-only production-path fixture seams, burst attribution ledgers, watchdogs, beacons, trace sections, and deterministic cross-platform contract tests without changing Release behavior. Numstat audit: iOS production +349/-1; Android non-test +270/-6 including the 175-line debug fixture; ComposerBar +11/-5; tests +317 total (iOS +240, Android +77). All hard caps are satisfied. Verification: iOS build-for-testing succeeded; focused AppSnapshotRuntimeTests 30/30; full LitterTests 235/235; git diff --check clean. Android local compilation is blocked only by absent generated Kotlin UniFFI bindings in this checkout, so Mobile CI is the binding compile/JVM gate. Frozen-state audit: shared/rust-bridge tree d4df00c; shared/third_party tree efaf0d6; submodule pointers were not staged. Measurement disclosure: iOS C-1 50 Hz and Android 20 ms DEBUG beacon polling are always-on in debug; C-2 ingress-hook cost must be measured at burst rate during calibration; beacon-bridged video timing carries +/-20 ms quantization. No production performance change is included before PP-B. Release remains gated on Mobile CI, five-gate rerun, xctrace smoke, three-run driver determinism, calibration/shakeout, PP-A, W2 review/CI, and PP-B.
Owner
Author
|
Closing as superseded by #319 (merged as |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sole remaining delivery PR — v2.0.1 mega convergence (IN PROGRESS)
This draft is the single convergence PR for the v2.0.1 delivery chain. It captures the already-green
#293(C1) and#294(C2) content onto the exact base7122dd6e. It is a draft and under active Fable batch review. No perf, simplification, or release-identity work is claimed to be present in this PR yet.Base:
7122dd6eba57e0c6eb923acd642db9396ade1334(origin/maintip at capture time)Head:
codex/v201-mega@12a7cbb1b10045801a22218811d66e4765287c08merge-base(
codex/v201-mega,7122dd6e) =7122dd6e(linear, 3 commits, no extras)Diff: 10 files, +406 / −125
C1/C2 commit → source → patch-id table
--stable)98981fa8c7ab7bcda5b3a899f10d394294e22049b18cd9c2(in#293; standalone origin#276)6b05176b70425697b3d30315ed8a241acf6bdb45d49db8b47e564107ed050bcfb6a28914cb72858192a66e95(in#293; standalone origin#277)6c63280c98b72a9a14bd6a38980af4c5d762918412a7cbb1b10045801a22218811d66e4765287c08f675fb24(#294)95785c21c9cb502d3f8bed97397d27920b084c9dSubjects preserved verbatim (including
[skip mobile-release]), in original order.Content-equivalence proof (10/10 blob match)
Every file at
codex/v201-megamatches its source head byte-for-byte:92a66e95(PR#293head)tools/scripts/list-play-tracks.py==f675fb24(PR#294head)git diff --checkclean (full range, per-commit, and single-file).Evidence
31753697269— terminal success at7122dd6e(Android build/tests + iOS build/LitterTests green).#293/#294: already green (targetedxcodebuild -only-testing13/13;python3 -m py_compile+python3 tools/scripts/list-play-tracks.py --self-testOK).Related PRs being converged
#293— ui: simplify typography and semantic theme defaults (C1 batch)#294— release: add read-only Play status fallback (C2)#276— chat: refine conversation typography (standalone origin of C1a)#277— appearance: make Studio the default theme (standalone origin of C1b)Mega plan
The v2.0.1 delivery is consolidated into this single PR on top of
7122dd6e. Downstream PERF-0a/PERF-0b, PERF-1, composer, adjudicated simplification, testing, release identity, and deployment preparation will be added as later logical commits to this same mega PR (the user requires one mega PR — no separate chain/PR).Open LOC (lines-of-code) user-choice gate — NOT included in this PR
Fable final union certified only P10 −875 / P50 −1,990 / P90 −3,185 versus the required −49,237; the stop-condition is open. The user must choose:
Reference:
FABLE_LOC_UNION_ADJUDICATION_READY.FABLE_MEGA_C1_C2_BATCH_REVIEW_READY