diff --git a/authored/audio.json b/authored/audio.json index 909c9dc5..7c480d0e 100644 --- a/authored/audio.json +++ b/authored/audio.json @@ -103,7 +103,7 @@ "loop": "restart", "kind": "measured", "why": "MEASURED, HANDOFF Q10 -- NOT a port choice. `GamePart_Title`'s phase handler `sub_821C5580` plays cue 1103 = `BGM_103`, and `BGM_103.slb`'s two declared waves (3 876 864 / 3 930 112 B) are byte-for-byte the two streams the XMA probe saw decoding at the main menu. Static code, disc census and runtime all agree; see docs/re/menu-audio-cues.md and docs/re/structures/bgm-two-stems.md. The name carries its `.slb` extension because that is what `sound.pak` hashes -- `BGM_103` alone resolves to nothing, which is how the first draft of this file failed.", - "loop_why": "MEASURED, and this field's own history is why it says so first. The bed loops; the loop is a RUNTIME field -- `loop_start`/`loop_end` in the XMA decoder context, set by `XMASetLoopData` and logged by Xenia -- and the cycle was watched directly: three wraps, both contexts wrapping at the same instant every time, mean 61.81 s against the 61.93 s authored in `loop_end_s`, 0.2 % apart from instruments sharing nothing. The export is TRIMMED to that window, because Godot loops a whole file and a loop region therefore has to BE the file. ⚠️ The window's START is not measured and is authored as 0, which is known to be wrong -- see `loop_start_why`. πŸ”΄ EVERY SENTENCE THAT PRECEDED THIS ONE WAS REFUTED, and the previous text survived in the manifest for two days after the corrections were written. It said the loop would be `AUDIBLY WRONG AT THE SEAM`, that `no loop-point field has been identified anywhere`, and that trimming `would INVENT a loop point`. All three are false: the field exists, the 3.4 s of near-silence was the PORT'S loop and not the game's, and the trim is now what the measurement says. The corrections went into `loop_end_why` and `loop_start_why`; this field is the one the exporter concatenates into `manifest.json`, so the export went on telling readers the refuted story. A correction that does not reach the artifact a consumer reads has not been made.", + "loop_why": "MEASURED, and this field's own history is why it says so first. The bed loops; the loop is a RUNTIME field -- `loop_start`/`loop_end` in the XMA decoder context, set by `XMASetLoopData` and logged by Xenia -- and the cycle was watched directly: three wraps, both contexts wrapping at the same instant every time, mean 61.81 s against the 61.93 s authored in `loop_end_s`, 0.2 % apart from instruments sharing nothing. The export is TRIMMED to that window, because Godot loops a whole file and a loop region therefore has to BE the file. ⚠️ The window's START is not measured and is authored as 0, which is known to be wrong -- see `loop_start_why`. πŸ”΄ EVERY SENTENCE THAT PRECEDED THIS ONE WAS REFUTED, and the previous text survived in the manifest for two days after the corrections were written. It said the loop would be `AUDIBLY WRONG AT THE SEAM [refuted]`, that `no loop-point field has been identified [refuted] anywhere`, and that trimming `would INVENT a loop point`. All three are false: the field exists, the 3.4 s of near-silence was the PORT'S loop and not the game's, and the trim is now what the measurement says. The corrections went into `loop_end_why` and `loop_start_why`; this field is the one the exporter concatenates into `manifest.json`, so the export went on telling readers the refuted story. A correction that does not reach the artifact a consumer reads has not been made.", "stems": "sum", "stems_why": "MEASURED, HANDOFF Q10: a bank is exactly TWO waves of identical duration (32/32 banks on the disc), sample-synchronous -- transient correlation peaks at lag 0.00 s over +/-5 s and both stop at the same millisecond. Concatenating them plays the piece twice, the second time as a bass-less stem; that was the previous reading and it is refuted. Emitting two files would be wrong for a second reason: MODDING rule 1 is one logical asset, one file, and handing a modder two stems to line up by hand is the reassembly the exporter exists to have already done. WHAT IS SUMMED IS SETTLED; WHAT WAVE 1 IS, IS NOT -- HANDOFF calls it quieter, far more L/R-decorrelated and almost bass-free, so it reads as a surround-rear pair OR a second intensity layer, and `ChannelMask` is 0x0002 on both so the file will not say. A unity sum is right under either reading; a weighting would only be justified once that is settled.", "loop_start_s": 9.44, diff --git a/crates/sylpheed-export/src/audio.rs b/crates/sylpheed-export/src/audio.rs index cbaf121e..1323f053 100644 --- a/crates/sylpheed-export/src/audio.rs +++ b/crates/sylpheed-export/src/audio.rs @@ -1010,7 +1010,7 @@ pub fn export_voice( " Also dropped: {}. A chunk marked SILENT carries no signal and \ contributes nothing; one of a different duration is not a \ concurrent stream of this take. \u{1f534} THIS SENTENCE USED TO SAY \ - the leading chunk was `the TAIL of the kept stream`, on a sliding \ + the leading chunk was `the TAIL of the kept stream [refuted]`, on a sliding \ envelope correlation of r=0.998. The CORRELATION was sound and the \ INTERPRETATION was refuted: `resolve_movie_voice_region` was \ starting 238 packets inside the first stream, so what matched \ diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index d91f79c1..e21c3839 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -120,7 +120,7 @@ HANDOFF. | ~~P6 BGM β€” the sub-wave count~~ | ~~is a music bank's LEADING REGION a stem, or a decoder artefact?~~ | Q10 | βœ… **CLOSED 2026-08-29 β€” the census was right and the port was summing a bank header into the music.** Decoded and timed, sub-wave 0 of `BGM_103`, `BGM_102` and `BGM_001` is identical: **10 300 B β†’ 0.009 s, peak βˆ’inf**, i.e. digitally silent. 10 300 B is the 10 240-byte bank header (the Decoder's disc-wide census) plus a 60-byte RIFF wrapper. So it is not a stem, and `export_bgm` had been counting it in the divisor β€” putting every real stem at 1/3 instead of 1/2, **3.52 dB of attenuation on all menu music shipped since P6**. Dropping a *silent* input is arithmetic, not a decoding decision, so this closed on the port's side; measured after the fix, `main_menu.ogg` goes βˆ’7.69 β†’ **βˆ’4.20 dBFS**, +3.49 dB against 3.52 predicted. Corroborates the Decoder's `c1f3608` from the other direction. The export now reports 2 sub-waves and the manifest warning is gone. | | ~~P3 β€” the plate's ONSET~~ | ~~visible 2.13 s after settle, or group starts then?~~ | Q2 | βœ… **resolved 2026-08-29, and the answer is AUTHOR NOTHING.** The port's refutation held and produced a better answer than either option it offered. Correction at `5b0a6e6` on `auto/no-disc-and-menu-captures`: **both builds run on one clock, started together**, and the plate arrives at its own declared `t=238`. Checked against this export rather than taken on trust β€” build 4's visible build-in ends at `t=118` (`pteff01`, `pteff02`, `ptlogoall_eff` finish together), `ptbtn00` reaches alpha 255 at `t=238`, difference **120 units = 2.000 s**, against a measured 2.138 / 2.132 s at an emulator presenting 28.1 fps rather than 30. The 2.13 s constant is **deleted**. | | ~~P3/P5 β€” `settle_time()`~~ | ~~`rest.t` is not when a screen settles, and the port's sequencer uses it~~ | β€” | βœ… **MEASURED 2026-08-29 and the row was HALF WRONG β€” mine.** The Decoder took it on a cold profile with no shader cache (`auto/no-disc-and-menu-captures` at `4bd4779`, `docs/re/boot-settle-times-measured.md`). The principle holds: the title's `rest.t` is 251 units = **4.183 s** where its art finishes at ~2 s. **But "everything the sequencer paces off that landmark is therefore late" does not.** Measured the port the way the game was measured β€” visible span, `--film` at 4 fps β€” the publisher wordmark runs **4.25 s** against the game's 4.297/4.604/4.370 and the developer logos **3.50 s** against 3.508/3.503/3.366. Dead on. My earlier reading compared the port's *arrival-to-arrival* timestamps against the game's *visible spans*, which differ by the exit ramp plus the black hold β€” the whole of the discrepancy I was about to chase. `rest.t` is still the wrong landmark; its blast radius is `_script_settled` waiting longer than it needs to, which is a slow test and not a wrong frame. `dwell_seconds` stays `null`, now for a measured reason. πŸ”΄ **Do not author an β’Άβ†’menu dwell**: it measures 3.763 s and contains a 1.53 s guest load stall, third independent reproduction. 🟑 Menu build-in 0.531 s and β’·β†’title 0.482 s rest on one run and are not authored; the port is within ~0.1 s of both from the disc. | -| P4/P7 β€” the voice export | ~~what are the three concurrent streams~~ **what do streams 1 and 3 contribute?** | β€” | 🟑 **HALF ANSWERED BY THE ORACLE, 2026-08-29.** A faithful capture finally exists (`1788022539-4529c72ed7fb`, ALSA tee + `--gpu=null`, 0.35 % silence, passes `check-capture`, header verified here). Fitted with the calibrated correlator against its own controls (present +0.248 / absent +0.005): **the exported voice matches the game's CENTRE channel at r = 0.989, margin +0.305**, while the movie bed matches FL/FR/RL/RR and *not* FC. So the dialogue is in FC, the bed is in the corners, and **the port's exported file is the material the game plays there** β€” measured, where the header (`ChannelMask = 0x0002` on all three) could never have said it. ⚠️ Streams 2 and 3 are indistinguishable to this instrument, as expected from stream 3 being 0.60Γ— stream 2 with 26.8 dB residual; stream 1 is undetectable in a 59.7 s window, consistent with being stream 2's tail. πŸ”΄ **The `1 of 3` warning stays** β€” nothing here says what the other two contribute. Reach: 59.7 s of a 137 s movie, one run, no screen provenance (the `--gpu=null` route costs video; provenance is the XMA probe). **Superseded history, kept because the sequence of wrong readings is what makes this one checkable:** πŸ”΄ Canary's `--xma_param_probe` shows the game decoding **all three streams concurrently** in three XMA contexts, byte sizes matching the disc payloads exactly (1 294 336 / 1 118 208 / 1 171 456 against 1 294 396 / 1 118 268 / 1 171 516). So they are **not** three presentations of one take, there is no "which one" to answer, and the export β€” which ships one β€” is **missing two streams the game plays**. ⚠️ **The failure sounds like success**: one stream is clean audible dialogue. Stated as a top-level manifest warning per movie, on the console, and in `authored/audio.json`. **Behaviour deliberately unchanged**: an equal-gain `1/n` sum of channel pairs is not a downmix either (MISSION Β§6 pins an explicit matrix for exactly this reason) and summing cost `S00A` 6.02 dB when one stream was silence β€” swapping one guess for another is what produced this row twice. 🟑 "They are 5.1" is the Decoder's **hypothesis**: three stereo streams is six channels and N stereo streams is how XMA carries multichannel on the 360, but all three declare `ChannelMask = 0x0002` identically, which argues against distinct roles. πŸ”΄ **NOT OBTAINABLE THIS SESSION β€” both capture routes are closed, and this is now the blocker.** Take 1 (`1788018994-16f9d19d90b8`) was corrupted by a **channel-map remap**: PulseAudio remapping between mismatched maps silently drops and duplicates, proved by a tone control (six tones in, `400 / 3200 / 200 / 800 / 800 / 200` out, two source channels gone). Take 2 (`1788019777-43f27c791bef`) is **starved** β€” verified here independently: **35.6 % of frames silent on all six channels, 10 482 alternating runs, median burst 13.5 ms / gap 3.9 ms, a 17.4 ms period at 57 Hz.** That destroys envelope correlation by construction, so the negative it produced said nothing about the game. ⚠️ **Withdrawn with it: the reading that the game may not play the `.wmv`'s WMA track** β€” neither supported nor refuted by a starved file, and nothing changed on account of it. **The monitor-sink route cannot be fixed by configuration**: it advances at wall-clock rate and substitutes silence, so every moment the emulator runs slow is a hole and deleting them warps the timebase non-uniformly. The route that works is an internal tap at `SDLAudioDriver::SubmitFrame`, needing a **Canary rebuild the Decoder has costed at a whole session** β€” the build root `build-canary` targets does not exist in that container, the warm tree is configured against the same missing path, ~700 MB free, with prior parallel builds OOM-killing the host. **That is the human's call, not an agent's.** `tools/port/check-capture` now catches both failure modes, so no future capture costs an analysis to discover it is unusable. | +| P4/P7 β€” the voice export | ~~what are the three concurrent streams~~ **what do streams 1 and 3 contribute?** | β€” | βœ… **RESOLVED 2026-08-30 β€” and the body below is superseded in three places, which striking the heading did not mark.** The port now ships **all** qualifying streams with **measured positional weights** (`ADV` 3 of 3 at 0.4142 / 0.2929 / 0.2929 for FL/FR, FC, BL/BR). πŸ”΄ Three sentences below still assert in the present tense and are false: **(a)** *"the `1 of 3` warning stays"* β€” it is gone, the export is complete; **(b)** *"stream 1 … consistent with being stream 2's tail"* β€” refuted, it was a **start-truncated simultaneous stream**, the resolver having begun 238 packets inside it; **(c)** *"streams 2 and 3 are indistinguishable to this instrument"* β€” superseded, the assignment is settled by declared `byte_size`. The history is **kept** because the sequence of wrong readings is what makes the right one checkable, but a reader lands on the sentences, not on the heading. See `DECISIONS.md`. Original status follows. 🟑 **HALF ANSWERED BY THE ORACLE, 2026-08-29.** A faithful capture finally exists (`1788022539-4529c72ed7fb`, ALSA tee + `--gpu=null`, 0.35 % silence, passes `check-capture`, header verified here). Fitted with the calibrated correlator against its own controls (present +0.248 / absent +0.005): **the exported voice matches the game's CENTRE channel at r = 0.989, margin +0.305**, while the movie bed matches FL/FR/RL/RR and *not* FC. So the dialogue is in FC, the bed is in the corners, and **the port's exported file is the material the game plays there** β€” measured, where the header (`ChannelMask = 0x0002` on all three) could never have said it. ⚠️ Streams 2 and 3 are indistinguishable to this instrument, as expected from stream 3 being 0.60Γ— stream 2 with 26.8 dB residual; stream 1 is undetectable in a 59.7 s window, consistent with being stream 2's tail. πŸ”΄ **The `1 of 3` warning stays** β€” nothing here says what the other two contribute. Reach: 59.7 s of a 137 s movie, one run, no screen provenance (the `--gpu=null` route costs video; provenance is the XMA probe). **Superseded history, kept because the sequence of wrong readings is what makes this one checkable:** πŸ”΄ Canary's `--xma_param_probe` shows the game decoding **all three streams concurrently** in three XMA contexts, byte sizes matching the disc payloads exactly (1 294 336 / 1 118 208 / 1 171 456 against 1 294 396 / 1 118 268 / 1 171 516). So they are **not** three presentations of one take, there is no "which one" to answer, and the export β€” which ships one β€” is **missing two streams the game plays**. ⚠️ **The failure sounds like success**: one stream is clean audible dialogue. Stated as a top-level manifest warning per movie, on the console, and in `authored/audio.json`. **Behaviour deliberately unchanged**: an equal-gain `1/n` sum of channel pairs is not a downmix either (MISSION Β§6 pins an explicit matrix for exactly this reason) and summing cost `S00A` 6.02 dB when one stream was silence β€” swapping one guess for another is what produced this row twice. 🟑 "They are 5.1" is the Decoder's **hypothesis**: three stereo streams is six channels and N stereo streams is how XMA carries multichannel on the 360, but all three declare `ChannelMask = 0x0002` identically, which argues against distinct roles. πŸ”΄ **NOT OBTAINABLE THIS SESSION β€” both capture routes are closed, and this is now the blocker.** Take 1 (`1788018994-16f9d19d90b8`) was corrupted by a **channel-map remap**: PulseAudio remapping between mismatched maps silently drops and duplicates, proved by a tone control (six tones in, `400 / 3200 / 200 / 800 / 800 / 200` out, two source channels gone). Take 2 (`1788019777-43f27c791bef`) is **starved** β€” verified here independently: **35.6 % of frames silent on all six channels, 10 482 alternating runs, median burst 13.5 ms / gap 3.9 ms, a 17.4 ms period at 57 Hz.** That destroys envelope correlation by construction, so the negative it produced said nothing about the game. ⚠️ **Withdrawn with it: the reading that the game may not play the `.wmv`'s WMA track** β€” neither supported nor refuted by a starved file, and nothing changed on account of it. **The monitor-sink route cannot be fixed by configuration**: it advances at wall-clock rate and substitutes silence, so every moment the emulator runs slow is a hole and deleting them warps the timebase non-uniformly. The route that works is an internal tap at `SDLAudioDriver::SubmitFrame`, needing a **Canary rebuild the Decoder has costed at a whole session** β€” the build root `build-canary` targets does not exist in that container, the warm tree is configured against the same missing path, ~700 MB free, with prior parallel builds OOM-killing the host. **That is the human's call, not an agent's.** `tools/port/check-capture` now catches both failure modes, so no future capture costs an analysis to discover it is unusable. | | ~~P4/P7 β€” `S00A` as a second asset~~ | ~~does a structurally different movie also put dialogue in FC?~~ | β€” | πŸ”΄ **NOT OBTAINABLE IN THIS CONTAINER β€” closed as a route finding, 2026-08-29.** The drive works end to end (main menu +0.999, `newgame-difficulty` +0.999, `newgame-selectdata-crash` +0.997, with the focus detector validated live against a known transition) and then **the guest throws at `PC: 0x82307128` Γ—349**; no `S00A` stream ever decodes. ⚠️ It also refines `title-crash-stl-tree.md` rather than confirming it: the mechanism survives but the container it names, `aab216c3`, is **complete here** β€” the throw is on `1b556564`, which holds one file plus a stray `.tmp`. **So the new-game path builds a different cache container, and the documented remedy does not transfer** β€” it restores a *previously complete* cache, and no complete `1b556564` has ever existed here. **Consequence for the port: the centre-channel result rests on `ADV` alone.** `S00A` was wanted precisely because its second stream is digital silence where `ADV`'s is a 0.60Γ— copy. That corroboration is behind a crash outside menu-port scope and neither agent is chasing it. | | ~~P3/P5 β€” the title plate~~ | ~~does the idle title show `PRESS β’Ά`~~ | Q2 | βœ… **answered and TAKEN at this iteration.** `auto/no-disc-and-menu-captures` at `fb536df`, `docs/re/title-plate-delay-measured.md`, traces in `docs/re/data/plate-timing-run{1,2}.tsv`. It is the third case: build 4 alone, then the plate composited over it. ⚠️ The delay is timed from where build 4 **stops animating**, not from where it first appears β€” measured the other way the two runs differ by 0.48 s against 6 ms. `ScreenView` now draws two builds at once, as a second `ScreenView` in the same `SubViewport` rather than a subordinate screen inside one. The onset question above is what is left. | @@ -547,7 +547,7 @@ what a pulse would need); or it genuinely blinks once and vanishes, in which cas the port is right and this closes βœ…. πŸ”΄ **Correction, 2026-08-30.** This row previously said the looping focus record -was "the only thing making the plate reappear at all". The opposite was true: the +was "the only thing making the plate [refuted] reappear at all". The opposite was true: the entry was the only thing making it **disappear** β€” it drew a dim glow *instead of* the plate's own sprite, max 0 against max 252.5. It has been deleted, and the port now draws the plate from its own decoded fade. See `DECISIONS.md`. @@ -624,7 +624,7 @@ that counts.* `verify-screen` has `title` at **790 pixels** over the bar and `title_jp` at **20 498**, and neither carries a forced-backdrop element β€” so they are not covered by the pinned-tag allowance the other six sit under. I had been reporting -"six expected DIFFERS"; the real count was ten. +"six expected DIFFERS [refuted]"; the real count was ten. πŸ”΄ **The obvious explanation is wrong.** `authored/rendering.json` records that the consistency harness compares against a renderer drawing no `.rat` leaves, so the diff --git a/docs/port/DECISIONS.md b/docs/port/DECISIONS.md index b129fbdd..16fd3a0d 100644 --- a/docs/port/DECISIONS.md +++ b/docs/port/DECISIONS.md @@ -9,7 +9,7 @@ dies, which is what this file is for. -140 sections. Search this before re-deriving anything. +141 sections. Search this before re-deriving anything. * [P0 β€” the exporter, 2026-08-28](#p0--the-exporter-2026-08-28) * [P1 β€” Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28) @@ -98,7 +98,7 @@ dies, which is what this file is for. * [Refutation attempt β€” the forced-backdrop rule's quantifier, and whether it misses a case](#refutation-attempt--the-forced-backdrop-rules-quantifier-and-whether-it-misses-a-case) * [The 256/211 was never a disagreement β€” and my own census had already said so](#the-256211-was-never-a-disagreement--and-my-own-census-had-already-said-so) * [The clock freezes at settle β€” the port's settle window, seen from the other side](#the-clock-freezes-at-settle--the-ports-settle-window-seen-from-the-other-side) -* [πŸ”΄ Withdrawn β€” "the boot is known too fast". The splash dwells are declared, and the port was already playing them](#withdrawn--the-boot-is-known-too-fast-the-splash-dwells-are-declared-and-the-port-was-already-playing-them) +* [πŸ”΄ Withdrawn β€” "the boot is known too fast [refuted]". The splash dwells are declared, and the port was already playing them](#withdrawn--the-boot-is-known-too-fast-refuted-the-splash-dwells-are-declared-and-the-port-was-already-playing-them) * [Refutation attempt β€” their two splash boundaries are not anchored the same way](#refutation-attempt--their-two-splash-boundaries-are-not-anchored-the-same-way) * [Their corrected boundaries check out against the file β€” all six, exactly](#their-corrected-boundaries-check-out-against-the-file--all-six-exactly) * [The n=1 disclosure, and the one port constant that rests on a single run](#the-n1-disclosure-and-the-one-port-constant-that-rests-on-a-single-run) @@ -151,6 +151,7 @@ dies, which is what this file is for. * [The duration is confirmed and the window is wrong β€” and the start is now a visible field](#the-duration-is-confirmed-and-the-window-is-wrong--and-the-start-is-now-a-visible-field) * [The loop window is measured β€” `-ss 9.44 -t 61.87` β€” and the near-silence count tracked the error](#the-loop-window-is-measured---ss-944--t-6187--and-the-near-silence-count-tracked-the-error) * [Applying "grep the corpus for the claim" to my own corpus](#applying-grep-the-corpus-for-the-claim-to-my-own-corpus) +* [A refuted-claim register, because the audit found what the audit found](#a-refuted-claim-register-because-the-audit-found-what-the-audit-found) ## P0 β€” the exporter, 2026-08-28 @@ -3254,7 +3255,7 @@ is what produced this entry twice already. success*: a single stream decodes to clean, audible dialogue, so nothing a listener hears reveals that two streams are missing. So it is stated in three places a reader cannot miss β€” a top-level `manifest.json` warning per movie, the -console line (`1 of 3 streams -- KNOWN INCOMPLETE`), and the entry's own `why` β€” +console line (`1 of 3 streams [refuted] -- KNOWN INCOMPLETE`), and the entry's own `why` β€” and 🟑 became πŸ”΄ in `authored/audio.json` and `BLOCKED.md`. 🟑 **"They are 5.1" is the Decoder's hypothesis and is not established.** Three @@ -3760,7 +3761,7 @@ correlate identically with everything. **This does not say `loudest` picked the with it being the tail of stream 2 (measured earlier at r = 0.998) and with a 59.7 s window that starts before the tail. -πŸ”΄ **The `1 of 3 streams` warning stays.** Nothing here explains what the other +πŸ”΄ **The `1 of 3 streams [refuted]` warning stays.** Nothing here explains what the other two contribute to the game's output, and the export still ships one. What changed is its character: it is no longer *"one of three, contents unknown"* but *"the centre-channel dialogue, plus two streams whose relationship to it is measured @@ -5312,7 +5313,7 @@ reason and its absence is now doubly justified. ⚠️ **Only build 4 is measured, and build 4 is the one screen where the port is unaffected** β€” it is the boot's end state and holds indefinitely. The two screens this actually governs, `publisher_logo` and `developer_logos`, have no measured -dwell at all. The port's boot is **known too fast on both, by an unmeasured +dwell at all. The port's boot is **known too fast [refuted] on both, by an unmeasured amount**. Nothing here is a number for them. > πŸ”΄ **WITHDRAWN, and this paragraph stood for days after the withdrawal was @@ -5320,7 +5321,7 @@ amount**. Nothing here is a number for them. > on the disc** β€” publisher t=0…255, developer t=0…210 β€” corroborated over three > cold boots to 1.1 %, and the port was already emitting each declared value plus > the 9-unit black hold, *exactly*. See -> [Withdrawn β€” "the boot is known too fast"](#-withdrawn--the-boot-is-known-too-fast-the-splash-dwells-are-declared-and-the-port-was-already-playing-them). +> [Withdrawn β€” "the boot is known too fast [refuted]"](#-withdrawn--the-boot-is-known-too-fast-the-splash-dwells-are-declared-and-the-port-was-already-playing-them). > > Found 2026-08-30 by the Decoder's rule: **grep the corpus for the claim, not > for the file you were working in.** I wrote the withdrawal as a new section and @@ -5328,11 +5329,11 @@ amount**. Nothing here is a number for them. > dead answer with nothing to warn them β€” the same failure as a correction that > never reaches the manifest, one layer up. -## πŸ”΄ Withdrawn β€” "the boot is known too fast". The splash dwells are declared, and the port was already playing them +## πŸ”΄ Withdrawn β€” "the boot is known too fast [refuted]". The splash dwells are declared, and the port was already playing them Last iteration I took the Decoder's build-4 measurement β€” declared ~120 presented frames, dwelled ~1 100 β€” and wrote into three files that the port's boot is -**"known too fast on both splashes, by an unmeasured amount"**. That is +**"known too fast [refuted] on both splashes, by an unmeasured amount"**. That is **withdrawn**. It was wrong, and the way it was wrong is the interesting part. They then measured the splashes directly, over 3 cold boots: @@ -6539,7 +6540,7 @@ frames that are equivalent at the bar. of being lumped in with a real disagreement. Tenth instance: the fix was implemented, documented, and never wired to the thing it was for. -### πŸ”΄ And "six expected DIFFERS" β€” which I have told the Decoder more than once β€” was wrong +### πŸ”΄ And "six expected DIFFERS [refuted]" β€” which I have told the Decoder more than once β€” was wrong The true count was **ten**, now **eight** after the rounding fix: @@ -7484,7 +7485,7 @@ regions are fine and **8 of 10 three-chunk regions start mid-stream**. ### πŸ”΄ Which re-reads a measurement of mine, without touching the measurement -This port measured the leading chunk as *"the TAIL of the kept stream"* β€” +This port measured the leading chunk as *"the TAIL of the kept stream [refuted]"* β€” envelope correlation r=0.998, lag flush against that stream's end β€” and dropped it as an understood duplicate. @@ -8019,7 +8020,7 @@ count discriminated where the *step* count could not. Correcting `loop_end_why` and `loop_start_why` left `loop_why` β€” **the field the exporter concatenates into `manifest.json`** β€” still asserting that the loop would -be *"AUDIBLY WRONG AT THE SEAM"*, that *"no loop-point field has been identified +be *"AUDIBLY WRONG AT THE SEAM [refuted]"*, that *"no loop-point field has been identified [refuted] anywhere"*, and that trimming *"would INVENT a loop point"*. All three refuted; all three shipped to any consumer reading the export. @@ -8051,14 +8052,14 @@ you were working in.** Run against mine, on four claims I refuted this fortnight | claim | where | state | |---|---|---| | "the leading chunk is the **TAIL** of the kept stream" | `audio.rs` β†’ **`manifest.json`** | πŸ”΄ **still shipping** | -| "six expected DIFFERS" | `BLOCKED`, `DECISIONS` | marked | -| "the boot is **known too fast** on both" | `DECISIONS` | πŸ”΄ **standing, unmarked** | +| "six expected DIFFERS [refuted]" | `BLOCKED`, `DECISIONS` | marked | +| "the boot is **known too fast [refuted]** on both" | `DECISIONS` | πŸ”΄ **standing, unmarked** | | "the **only thing** making the plate reappear" | `BLOCKED` | marked | ### The one that shipped The dropped-chunk explanation in the exported `why` still told readers the leading -chunk *"IS understood: the TAIL of the kept stream"*. That interpretation was +chunk *"IS understood: the TAIL of the kept stream [refuted]"*. That interpretation was refuted β€” the correlation was sound, but what matched end-flush was a **start-truncated simultaneous stream**, because the resolver began 238 packets inside it. @@ -8073,7 +8074,7 @@ Replaced with a per-case account that names the refutation rather than deleting ### The one that was standing -*"The port's boot is known too fast on both, by an unmeasured amount"* β€” withdrawn +*"The port's boot is known too fast [refuted] on both, by an unmeasured amount"* β€” withdrawn days later, when the splash dwells turned out to be **declared on the disc** and the port already exact. I wrote the withdrawal as a **new section** and left the original untouched, so a reader arriving at the older paragraph got the dead @@ -8081,7 +8082,7 @@ answer. Annotated in place, pointing at the withdrawal. ### And a false positive that is its own lesson -`BLOCKED.md` matched *"the only thing making the plate reappear"* β€” inside **my own +`BLOCKED.md` matched *"the only thing making the plate [refuted] reappear"* β€” inside **my own correction**, which quotes the refuted claim in order to name it. That is the grep trap I documented two days ago, caught by the very audit that trap exists to complicate. **Naming a refuted sentence keeps it greppable**, which is the price of @@ -8093,3 +8094,58 @@ reads correctly, a delivery check proves the experiment happened at all.* Their second β’Ά was never delivered β€” 2 pad lines is one press β€” and *"the press did nothing"* and *"there was no press"* are identical from the screen. My equivalent is that a correction can be written, be accurate, and never arrive. + +## A refuted-claim register, because the audit found what the audit found + +The Decoder ran my corpus audit against theirs and found **four** refuted claims +still standing β€” including one they had corrected in a message to me, agreed with, +and written a METHOD entry about, **without landing the correction for a full +iteration**. Their sharpening: *acknowledging a correction in conversation feels +like making it and isn't.* + +A hand audit finds the instances present on the day it runs. It does not stop the +next one. So `tools/port/check-claims` is a **register**: each row is a claim this +corpus has refuted, and every occurrence must carry an explicit `[refuted]` +sentinel within 400 characters. `check-all` runs it. + +### πŸ”΄ It found four more than my hand audit did + +My manual pass checked four claims and found two problems. The check, on the same +four, found **four further unmarked occurrences** I had read past β€” including one +in `authored/audio.json` and one in the very table where I had written *"standing, +unmarked"* about a different claim. + +### The marker is a sentinel, not a keyword, and that mattered + +The first version matched a per-claim keyword near the hit β€” "refuted", +"WITHDRAWN". **Every one of its failures was a quotation sitting inside a +correction whose wording happened not to contain the keyword**: a table cell +reading *"standing, unmarked"*, a sentence reading *"the real count was ten"*. + +⚠️ The temptation was to widen the window or add synonyms until those passed. +**That is tuning a threshold until the answer comes out right** β€” the failure this +corpus has spent a fortnight cataloguing, arriving in the tool built to catch it. +So the marker became a token the author must place. It cannot be satisfied by +phrasing, and its absence means exactly one thing. + +The cost is honest and is the point: 21 existing quotations had to be marked by +hand, and a new refuted claim means a new row plus marking what already quotes it. + +βœ… Proved it fails: removing one sentinel makes the run report that claim unmarked +and exit non-zero. + +### What the register cannot do + +⚠️ It only knows claims **someone has entered**. A refuted claim nobody registers +is invisible to it, so this is a ratchet on known corrections and not a search for +unknown ones β€” the audit still has to happen first. And it enforces *marking*, not +*correctness*: a sentinel next to a sentence that was never really refuted would +pass and be wrong in a new way. + +πŸ“Œ Their other finding is the one I acted on separately: **a "kept for the record" +block still asserts.** `BLOCKED.md`'s voice row had a struck heading and three +sentences below it asserting in the present tense β€” that the `1 of 3` warning +stays, that stream 1 is *"consistent with being stream 2's tail"*, that streams 2 +and 3 are indistinguishable. All three resolved days earlier. Marking a heading +superseded does not mark the sentence a reader lands on, so the resolution now +sits at the top of the cell and names each superseded sentence. diff --git a/tools/port/check-all b/tools/port/check-all index 0f9755c2..4ff256e7 100755 --- a/tools/port/check-all +++ b/tools/port/check-all @@ -42,6 +42,9 @@ step menu-audio must-pass env OUT="$OUT/audio" tools/port/verify-menu-audi # A stale index is worse than none: it answers "is this already decided?" with a # confident no. That is not hypothetical -- see the entry it was built after. step decisions-index must-pass tools/port/index-decisions --check +# A refuted claim asserted outside its correction is a lie the corpus tells a +# reader who greps for it. Registered claims must carry an explicit `[refuted]`. +step refuted-claims must-pass tools/port/check-claims echo echo "reported, not asserted:" step oracle-captures report-only env OUT="$OUT/oracle" tools/port/verify-capture diff --git a/tools/port/check-claims b/tools/port/check-claims new file mode 100755 index 00000000..4f3e4fad --- /dev/null +++ b/tools/port/check-claims @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Every refuted claim must appear only inside its own correction. +# +# tools/port/check-claims +# +# πŸ”΄ WHY THIS IS A CHECK AND NOT AN AUDIT. The Decoder's rule -- *grep the corpus +# for the claim, not for the file you were working in* -- found a refuted sentence +# still shipping in this port's `manifest.json`, and a withdrawn one still +# standing in `DECISIONS.md`. Running that by hand finds the instances present on +# the day it is run. It does not stop the next one. +# +# So: a REGISTER. Each row is a claim this corpus has refuted, plus a marker that +# must appear near every occurrence. A hit without its marker fails the run. +# +# ⚠️ Two things learned building it, both from the other agent: +# +# * a "kept for the record" block STILL ASSERTS. Marking the heading superseded +# does not mark the sentence a reader lands on, so the marker must sit near +# the CLAIM, not at the top of the section. +# * naming a refuted claim keeps it greppable, so this check returns its own +# corrections as hits -- which is the point. The marker is what distinguishes +# "quoted while being refuted" from "still asserted". +set -euo pipefail +cd "${PROJECT_DIR:-/work}" +WINDOW=400 # characters either side of a hit in which the marker must appear +fail=0 + +# πŸ”΄ THE MARKER IS AN EXPLICIT SENTINEL, NOT A KEYWORD. +# +# The first version matched a per-claim keyword -- "refuted", "WITHDRAWN" -- near +# the hit. Every one of its four failures was a quotation sitting INSIDE a +# correction whose wording happened not to contain the keyword: a table cell +# reading "standing, unmarked", a sentence reading "the real count was ten". +# +# Widening the window or adding synonyms until those passed would have been +# tuning a threshold until the answer came out right, which is the failure this +# corpus has spent a fortnight cataloguing. So the marker is a TOKEN THE AUTHOR +# PLACES: `[refuted]` near any quotation of a registered claim. It cannot be +# satisfied by phrasing, and its absence means exactly one thing. +# +# ⚠️ The cost is honest: every quotation must be marked by hand, and a new +# refuted claim means a new row plus marking its existing quotations. That work +# is the check. +MARKER='[refuted]' +REGISTER=$(cat <<'ROWS' +TAIL of the kept stream +known too fast +only thing making the plate +no loop-point field has been identified +AUDIBLY WRONG AT THE SEAM +1 of 3 streams +six expected DIFFERS +ROWS +) + +while IFS= read -r claim; do + [ -z "$claim" ] && continue + hits=0; bad=0 + while IFS= read -r loc; do + [ -z "$loc" ] && continue + f=${loc%%:*} + hits=$((hits+1)) + python3 - "$f" "$claim" "$MARKER" "$WINDOW" <<'PY' || bad=$((bad+1)) +import sys +f, claim, marker, w = sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4]) +s = open(f, encoding="utf-8", errors="ignore").read() +i = 0 +while True: + i = s.find(claim, i) + if i < 0: + break + if marker.lower() not in s[max(0, i-w):i+w+len(claim)].lower(): + print(" unmarked in %s at char %d" % (f, i)) + sys.exit(1) + i += len(claim) +sys.exit(0) +PY + done < <(grep -rl -- "$claim" docs/ crates/ port/ tools/ authored/ 2>/dev/null || true) + if [ "$bad" -eq 0 ]; then + printf ' %-42s %d file(s), all marked\n' "$claim" "$hits" + else + printf ' %-42s πŸ”΄ %d file(s) assert it unmarked\n' "$claim" "$bad"; fail=1 + fi +done <<< "$REGISTER" + +echo +[ $fail -eq 0 ] && echo "every refuted claim appears only inside its correction" \ + || echo "πŸ”΄ a refuted claim is still being asserted" +exit $fail