| 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 |