返回 CodeWhale
QA.md
根目录 / pet / QA.md
1 # Pet review packet
2
3 Review the exact commit checked out (`git rev-parse HEAD`). Report the source SHA,
4 OS/toolchain, commands, actual nonzero pass/fail counts, and reproducible findings.
5 Synthetic fixtures prove local contracts, not provider or customer acceptance.
6
7 ## Shared pet acceptance
8
9 See [Shared habitat](SHARED.md) for the ownership diagram, commands and bounded
10 local transport. Live terminal, browser, macOS, iOS and Android clients attach
11 to one companion; file studies, isolated worlds and replay remain explicit.
12 The companion is a presentation process and does not create an Engine turn.
13
14 `check-shared.py` starts only disposable loopback owners and checks ten contracts:
15 common identity and immutable frame, competing-owner exclusion, authorization and
16 origin validation, durable interaction deduplication, producer gaps and atomic
17 validation, source changes and view closure, one sound lease, crash restoration,
18 storage conflicts, and appearance persistence without simulation inputs. No provider is used by these checks.
19
20 For Android, the twelfth instrumentation test is opt-in. Put a companion's
21 private `connection.json` in the debug app's private files as
22 `shared-test-connection.json` and use `adb reverse` for that port. It verifies
23 two mobile clients against the real owner, a durable interaction and continued
24 clock after detachment. Without this explicit fixture it is reported skipped.
25 Do not publish the descriptor or include it in logs.
26
27 Visual acceptance requires the actual Ratatui application in a terminal that
28 answers the existing Kitty probe successfully, plus a fallback terminal. Inspect
29 `/pet`, `/pet on`, F6/F8/F9, Escape, resize, hidden
30 composer/history/selection, approvals, reduced motion, and image cleanup. Compare the
31 browser and normal native window to the same identity and checkpoint. A CPU
32 raster benchmark or PTY byte stream does not prove terminal appearance or input
33 latency. Record measured FPS, CPU/RSS and output bandwidth separately from the
34 60 fps presentation target. The canonical world remains fixed at 30 Hz.
35
36 The CI macOS artifact bundles its own companion executable. It can open a
37 normal detached window and start the owner without replacing an installed CLI.
38 It remains a locally signed review artifact, not a notarized release.
39
40 ## Fast Linux or macOS review
41
42 ```sh
43 npm --prefix pet ci --ignore-scripts
44 npm --prefix pet run check
45 npm --prefix pet run sync
46 git diff --exit-code -- crates/tui/src/tui/pet_watch/pet-native.js pet/ios/Resources
47 cargo fetch --locked --manifest-path pet/tui/Cargo.toml
48 ./pet/verify.sh --no-swift
49 npm test
50 npm run check:web
51 ```
52
53 The pet suite currently contains 66 tests: event occupancy/unknown coverage,
54 late failures, human request pairing, read-only local SSE reconnect/cursor
55 recovery, replay readiness and cancellation after garbage collection, bounded
56 long sessions and recorder process restart, deterministic world/score/PCM,
57 checkpoint integrity and continuation, immutable segment boundaries, pending input
58 retention, browser saves overlapping source changes, live-file freshness/restarts,
59 delayed browser reads crossing suspension, expression-version validation and legacy replay.
60 The standalone verifier compares 380 checkpoints across baseline and edge tapes,
61 each animated and still, under expression versions 1 and 2. Version 1 must also
62 match pinned pre-transformation golden digests. Omission of Swift is explicit in its output.
63 `npm test` requires the root and web dependencies described by the product.
64 `check:web` fetches public GitHub release metadata and requires network access.
65
66 For the full terminal, start with one build job on memory-limited machines:
67
68 ```sh
69 cargo build --locked -j 1 -p codewhale-tui --bin codewhale-tui
70 cargo test --locked -j 1 -p codewhale-tui --lib tui::pet_watch::
71 python3 pet/scripts/check-shared.py target/debug/codewhale-tui
72 ```
73
74 Do not rerun a full library test link that is already exhausting the machine.
75 Report build/resource blockers and continue independent source/browser QA.
76 Manually inspect `/pet`, narrow layouts, paste/Enter focus, session
77 save/reopen, immutable `/pet export`, and import that exported JSON in
78 the browser. Unknown must remain legible; stale approvals must not resurrect.
79 Use a disposable session and synthetic/loopback telemetry for this assignment.
80
81 With FFmpeg's `ffplay` on PATH, explicitly enable `/pet sound on`.
82 Check sound off/on, switching away from Watch and back, quiet mode, and a missing
83 or failed player. These must not stop the world or its checkpoint. No historical
84 sound should play after resuming. Unit tests use a capture sink or a disposable
85 child process; they never open an audio device. Actual output and listening
86 quality need separate manual evidence.
87
88 ## Apple and Kotlin
89
90 ```sh
91 ./pet/verify.sh
92 ./pet/scripts/check-apple.sh
93 ./pet/ios/build.sh
94 PET_KOTLIN_LIB=/path/to/gradle/lib ./pet/android/verify.sh
95 ```
96
97 The macOS recorder job also runs `check-apple.sh` and uploads the resulting
98 locally signed app as `codewhale-pet-macos`. Android uploads its debug APK and
99 reports separately. These are CI review artifacts, not notarized releases.
100
101 Apple requires macOS, Xcode command-line tools, and XcodeGen for iOS. The iOS
102 script generates and builds the Simulator project directly from the shared
103 source, without first building macOS. Open `pet/ios/CodewhalePet.xcodeproj` to run.
104 `check-apple.sh` compiles the actual host and runs checkpoint/storage/recovery
105 workflows, including a generated two-hour synthetic unknown recording, segment
106 publication, a save conflict that must preserve the running world, and actual
107 live-file appends, pause/resume, in-place restarts, replacement and recreation. It writes
108 only disposable fixtures under ignored conformance results and temporary storage.
109 The same executable checks 27 tone/noise/long-clock PCM ranges at three sample
110 rates through the actual JavaScriptCore Float32 boundary, comparing sample bits
111 with the retained JSON path and rejecting malformed or nonfinite buffers.
112 Kotlin 2.3.0 can instead be on PATH; its verifier builds only the particle core
113 and conformance runner. The actual Compose application is a separate Gradle build:
114
115 ```sh
116 cd pet/android
117 ./gradlew --no-daemon assembleDebug lintDebug
118 ./gradlew --no-daemon connectedDebugAndroidTest
119 ```
120
121 Use JDK 17 and Android SDK 35; connect a device/emulator for the second command.
122 Eleven instrumentation tests run the real QuickJS binding, Kotlin renderer,
123 PCM cursor, storage/recovery, immutable segments and Compose lifecycle. A test-only
124 document provider delivers synthetic bytes through real descriptor IO; live pause,
125 background, restart and malformed input reach the actual ViewModel. See [Android](android/README.md).
126
127 ## Review direction
128
129 Codewhale is a whale living in code. The dots can reorganize to show the work;
130 the whale is its home form, not a permanent silhouette restriction. Avoid the
131 old framing of a needy creature turning toward its owner. Evaluate readable,
132 causal transformations, continuity of particle identity, accessibility and
133 honest uncertainty. Version 2 supplies work-driven knots, strands, branches, layers, circulation and
134 open junctions; the same particle identities return to the whale at rest.
135
136 ## Local evidence before publication (2026-09-12)
137
138 - Packaged pet: 57 tests passed; existing Whalesong consumers: 310 passed after
139 the incremental Runtime importer change. These are overlapping suites, not
140 additive coverage.
141 - Product Node gate: 66 package, 12 SDK and 446 web tests passed; production web
142 check subsequently passed with the GitHub release fetch available.
143 - TypeScript/Rust/Swift/Kotlin: 380 identical checkpoints across both expression
144 versions. Legacy golden digests are unchanged.
145 - Actual TUI: bounded worker, persistence/export/reopen/corruption and two-hour
146 continuation exercised in a PTY. Five persistence, eleven paste and nine artifact
147 guard tests passed in the product. The initial hosted macOS suite ran 15,418
148 tests with one outdated Watch-tab golden; that header was corrected. Subsequent
149 hosted product CI on `e69e99b` passed Linux, macOS and Windows tests, Rust lint
150 and the applicable safety/security checks. Each later commit needs its own verdict.
151 - Apple: eleven checkpoint/live-file workflows passed; iOS Simulator exercised two-hour
152 restoration and visible corruption recovery without overwriting the damaged file.
153 - Android: debug APK and lint build pass; nine native tests and both Compose
154 lifecycle tests pass on
155 Android 15 ARM64, including 4,800 frames, checkpoint continuation, exact PCM,
156 lifecycle and storage recovery. The emulator audio sink runs without host
157 speaker output; this does not establish physical listening or power quality.
158 - Recovery exports: the shared 32,000-bucket fixture exceeds the native autosave
159 bound and restores its exact checkpoint. Android also exports 90,000 pending
160 interactions from its real 64 MiB QuickJS heap after the 8 MiB autosave path
161 rejects them. Apple save-conflict recovery preserves the live core, selected
162 source and preference; its exported pose/score restores exactly.
163 - Segment continuation: 3,240,000 fixed ticks (30 synthetic hours in Still) produced
164 263 immutable archives totaling 163.1 MB. Every rotation restored an exact
165 checkpoint; the active file was at most 0.441 MB at sampled saves. Hourly
166 post-GC Node heap samples ranged from 7.89 to 8.59 MB. This is shared-core
167 simulation, not a continuous native-device, provider or listening test.
168 - Native segments: 12 TUI Watch tests pass, including immutable archive ordering
169 and stale-writer rejection. Apple's generated two-hour recording archives
170 5.64 MB and continues from a 0.31 MB active habitat; a failed save keeps the
171 live world intact. Android rotates 4,096 applied inputs, rejects a competing
172 writer, restores exact continuation and detects a changed archive.
173 A constructed long-clock checkpoint also checks the Android renderer's
174 phase/clock/jitter bounds against the shared core and continues in both engines.
175 - Browser: changing sources and reopening an earlier imported recording restores
176 its pose and full future timeline. Earlier recordings remain available after
177 reload. A 30-hour segment seeks from its retained origin through its final
178 checkpoint with Still enabled. iOS Simulator exports an earlier recording
179 through Files and reports a successful save.
180 - Browser save ordering: controller tests defer storage completion while changing
181 worlds and accepting an input. The previous `5c70db4` controller fails by
182 treating the pending save as a failure; the correction waits, archives the new
183 input, and still preserves the source when a real failed save is canceled.
184 - Live freshness: the previous `45a1130` browser controller fails the stale-file
185 attachment regression. Its native core also throws on live resume after normal
186 host ticking because the Engine-only clock has not advanced. The shared resume
187 path now uses the world clock, drops old voices and retains an exact checkpoint.
188 Browser tests also discard a read started before suspension; this is controller
189 evidence, not a claim about a physical device or browser file-picker support.
190 - Runtime fixture timing: the HTTP test now waits for recorded waiting/error
191 coverage before answering, and for two sealed unknown bins before stopping.
192 Its former fixed sleep occasionally stopped the child before those final bins
193 on a busy runner. The receipt assertions and privacy checks remain unchanged.
194 - Continuous recording: the actual watch CLI rotates three replayable files and
195 continues at the original live pathname. File tests cross the 24-hour sequence,
196 count UTF-8 bytes, follow replacement with the real cursor, and preserve
197 existing files on an archive collision or external replacement. History is
198 retained on disk; this does not resume a recorder after process restart.
199 A Grokbot finding also covers errors after successful publication: row/byte
200 accounting now advances at replacement, before fallible cleanup or reporting.
201 The previous `e71be2c` writer fails the new post-publication continuation test.
202 Its first Windows CI run also found open handles preventing file replacement
203 and CRLF point data rejecting the whale body. Rotation now closes both writer
204 handles before replacement; point readers trim each row. The browser controller
205 tests now use CRLF assets and fail against the previous controller. CLI tests
206 use a test-only IPC preload for Windows shutdown-handler coverage because
207 `child.kill('SIGINT')` forcibly terminates a Windows process; POSIX tests retain
208 the real signal. The next Windows run passed 56/57 tests but found intermittent
209 reader contention during replacement. Windows replacement now retries for
210 under two seconds and rechecks destination identity, size and modification
211 time before each attempt. Current Windows CI is required to verify that fix.
212 - Bounded Runtime input: a real local HTTP/SSE fixture supplies 260,001 records
213 spanning nearly 29 hours of event timestamps. The importer retains fewer than
214 512 events and 256 KiB of metadata, including a still-open human request. The
215 published `43e6f02` transport fails the same fixture at record 155,859 when its
216 cumulative raw journal reaches the old limit. These are synthetic timestamps,
217 not a 29-hour provider or native companion run. Smaller fixtures compare recent
218 buckets with full imports through pruning, late failures, shifted origins,
219 request answers, automatic consent and turn completion.
220 - Authenticated read-only attachment to an existing local Runtime 0.9.13 session
221 journal passed. An 18-second recorder run produced 45 contiguous unknown buckets
222 and stopped cleanly in 41 ms after Ctrl+C, without treating historical work as
223 current activity. This does not establish a new active provider turn or native
224 companion acceptance. The old idle-stream shutdown failure is covered by a
225 real HTTP regression fixture that forces garbage collection before closing.
226
227 These chronological receipts describe the source at each milestone; later
228 sections supersede earlier open items. Hosted CI and Grokbot findings are separate
229 evidence on the pull request. Current limits are listed in [README.md](README.md).
230
231
232 ## Recorder process restart — September 12, 2026
233
234 `--resume` restarts a live recorder at its existing watched pathname. It validates
235 and archives the previous complete tape without changing its bytes, continues
236 numbered archives, and starts a fresh unknown segment. The existing host habitat
237 owns world continuation. No outage duration or activity is inferred from mtime.
238 A private empty sidecar uses Node SQLite's OS lock to exclude simultaneous
239 writers and release ownership on close or process death. It stores no events.
240
241 The local pet check passed 61 tests with zero failures. The focused recorder
242 checks cover repeated restarts, archive gaps, baseline/fresh live delivery,
243 invalid and incomplete source preservation, a competing writer, changed locks,
244 same-size external changes, SIGKILL followed by restart, and clean CLI shutdown.
245 Against the previous `6d960525` recorder, resuming rejects with EEXIST and a
246 same-size external rewrite is incorrectly accepted; the new guards reject it.
247 The required `npm test && npm run check:web` gate passed 66 package, 12 SDK and
248 446 web tests, with zero failures and two existing web-check warnings.
249
250 This changes the standalone recorder, its tests and documentation. World, score,
251 TUI and native bundle bytes are unchanged from the previously verified build.
252 Grokbot review and current-head Windows/macOS recorder CI are separate receipts.
253 Native active-session delivery, current macOS popover inspection and device
254 transport remain open. No release or deployment is implied.
255
256
257 The first restart commit `11c6fbfc` passed all 61 tests independently in
258 Codewhalebot on Node 22.19.0 with no remaining concrete source finding. macOS
259 recorder CI also passed. Windows passed 60 tests and canceled one on timeout:
260 the test-only IPC message listener kept a correctly rejected startup alive.
261 The same preload reproduced the hang locally; unreferencing its IPC channel
262 lets the rejected CLI exit with code 1. The process-death/restart test now uses
263 that IPC path on every host, while other POSIX cases still use actual SIGINT.
264 The fixture also waits for CLI readiness before shutdown: the archive link may
265 appear before replacement and before the signal handler is installed. A broad
266 local run exposed this early-stop race after the IPC fix. Production recorder
267 and native bundle bytes are unchanged in this follow-up.
268
269
270 ## Runtime replay-to-live handoff — September 12, 2026
271
272 An old human request must stay unknown while its journal answer is still in the
273 replay backlog. The Runtime event endpoint now offers opt-in `stream.progress`
274 frames and advertises that capability. It declares live observation only after
275 both durable replay and the queued live tail have drained; broadcast lag returns
276 the stream to replaying while durable history catches up. These frames are
277 transport metadata, not journal events, and allocate no new sequence numbers.
278 Default SDK callers keep the existing event-only stream.
279
280 The pet requires that explicit handoff. Journal packets alone cannot establish
281 current observation. An older Runtime or SDK without progress support stops
282 input with a clear diagnostic and leaves the recorder unknown. In particular,
283 the earlier read-only Runtime 0.9.13 receipt above is historical evidence, not
284 compatibility evidence for this new live transport.
285
286 The local pet check passed 63 tests, with zero failures or cancellations. The
287 required `npm test && npm run check:web` gate passed 66 package, 14 SDK and 446
288 web tests; web checks reported zero errors and two existing warnings. Three
289 actual Runtime Rust tests passed for opt-in endpoint negotiation, queued answers
290 at handoff, and broadcast-lag recovery; the existing event-only handoff test also
291 passed. The TypeScript SDK declarations passed their compiler check.
292
293 A real loopback HTTP fixture delays a 60-second-old request's answer. The
294 published `c342329f` transport marks that pending historical request current;
295 the corrected transport keeps it unknown. Further fixtures verify that the old
296 answer arrives before readiness, a fresh request becomes visible, replay reentry
297 suppresses observation, and unsupported streams cancel before accepting input.
298 The 260,001-record bounded-input fixture still passes with readiness markers.
299 These are synthetic event fixtures with real transports, not provider calls.
300
301 World, score and native bundle bytes are unchanged. Hosted CI, independent
302 Codewhalebot QA, and active-session native delivery remain separate evidence.
303
304
305 ## Apple audio and scope audit — September 12, 2026
306
307 Apple now transfers the shared generator's Float32 channels directly from
308 JavaScriptCore. Each channel's type, length and finite samples are checked; its
309 borrowed pointer is copied immediately while the JS value remains rooted.
310 The JSON PCM method remains available to QuickJS consumers. There is one score
311 and sample generator.
312
313 Actual AVAudioEngine playback exposed schedules more than a second in the past
314 after a 750 ms UI stall. Presentation now rebases against the current world and
315 retires stale voices after long gaps. Completion callbacks carry numeric tickets
316 back to the main actor, preventing an old completion from retiring a newer node.
317 A sound failure mutes and persists the sound preference while world ticks and
318 recording exports continue. The previous Apple host stops the world on the same
319 injected PCM failure; the corrected host advances from 400 ms to 933 ms and exports.
320
321 Local final-source receipts:
322
323 - Pet checks: 63 passed, zero failed/canceled. Required product gate: 66 package,
324 14 SDK and 446 web tests passed; web check has zero errors and two existing warnings.
325 - Apple: all 11 checkpoint/live-file/storage workflows and 27 exact PCM ranges
326 pass, plus empty/invalid range and four malformed-buffer checks. macOS builds,
327 signs and verifies; iOS Simulator builds from the same final Swift sources.
328 - Real AVAudioEngine: 150 frames complete with a forced 750 ms stall. All 12
329 scheduled onsets remain in the future (42–118 ms); the prior output drifts
330 down to 1,703 ms late. This proves scheduling, not subjective listening quality.
331 - An 80-second synthetic profile renders 122 voices. Audio-frame p95 falls from
332 70.6 ms on JSON transport to 23.4 ms on final typed transfer, with the same
333 final particle digest and sample peak. An earlier typed-transfer run had zero
334 frames over 33 ms; the final run had six wall-time outliers (worst 738 ms) on
335 the concurrently used machine. This is not a hard frame-time guarantee.
336 - The regenerated bundle passes 12 actual TUI Watch tests and all 11 Android
337 instrumentation tests together, plus APK assembly and lint. The score and
338 particle algorithms are unchanged.
339
340 The original A–F workstreams map to implemented, buildable source:
341
342 | Workstream | Implementation and evidence |
343 | --- | --- |
344 | A — World | Shared seeded behavior state machine, environment, interaction journal, doze/wake, persistent pod identities and versioned forms. Browser/Apple/Android replay and checkpoint workflows; 380 four-port conformance checkpoints. |
345 | B — Audio | One thirteen-category score and PCM generator; browser WebAudio, Apple AVAudioEngine, Android AudioTrack and opt-in TUI ffplay. Deterministic PCM, native cursor tests, Apple output/stall/failure receipts. Listening quality remains a separate human assessment. |
346 | C — TUI | Existing Engine events feed Watch through the canonical bucketer; bounded cameo honors open-water collision, palette and motion rules. Actual product build, PTY interaction and 12 Watch checks. |
347 | D — macOS | Locally signed LSUIElement application, menu-bar controls, launch-at-login option, Still/sound/source settings and DispatchSource live files. Real process persistence and host workflows; current popover inspection is unverified. |
348 | E — Mobile | SwiftUI Simulator app and Compose Android app use the same core and local-file contract. iOS build plus prior Simulator restoration/export/recovery; Android APK/lint plus 11 real-engine/device-lifecycle tests. No automatic phone link is claimed. |
349 | F — Live authority | Existing Engine journal and opt-in Runtime replay progress feed one event-v1 bucketer. Synthetic Engine → actual Runtime/SSE → recorder → native Apple host passes without provider calls or raw prompt capture. |
350
351 Source and build instructions are published on PR #6110. Commit-specific
352 Grokbot review and GitHub checks are recorded there. Shipping, signing for public
353 distribution and subjective audiovisual acceptance are not implied by these
354 local builds or by a prior commit's green CI.
355
355 lines MARKDOWN