From 5bbc3a9f39a7681e86fb9dfe02fcf0565a98eeb0 Mon Sep 17 00:00:00 2001 From: Topi Jarvinen Date: Wed, 29 Jul 2026 10:17:51 +0300 Subject: [PATCH] =?UTF-8?q?chore:=20update=20handoff=20=E2=80=94=20the=20f?= =?UTF-8?q?ifth=20sweep,=20and=20a=20claim=20wrong=20in=20both=20direction?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #151 merged (494b9eb): fifth triage-friction-log sweep, seven entries in and seven out, two new tickets (#149, #150). Inbox 203 -> 136. The session's durable result is a failure mode the previous one measured but did not name: an operator's narrow remark ("CodeRabbit is currently not available here") widened into a stronger claim ("not installed, never exercised, nothing rate-limited") and published as operator-confirmed on five surfaces, including a structurally-never-reviews verdict filed onto #45 — the issue whose subject is that such a verdict cannot be made from outside. The fix then over-corrected with a review count that was really a count of bot comments; two independent re-derivations disagreed, so no count was published. Two panel rounds on this wrap-up PR found nine defects in it, then three more in the correction of those nine. All are now fixed. The worst: it called #151 "the third sweep" in a heading, the Last-updated line, the commit subject and the PR title — reinstating, forty minutes later, the exact correction #151's own review had landed, while the same block said "Fifth sweep overall" three lines below. Four inbox entries added by this commit, giving five under the 2026-07-29 (post-sweep) heading; the fifth is the #121 entry, which landed in #151. An earlier revision of this message said "four added" while naming the #121 entry as one of them, and its correction then said "three added" — both wrong, and the second was published as a fix. The count is 4 added / 5 total, from git: 43 insertions, 0 deletions on the friction log. Entries: the operator-remark widening (H), the unrecoverable-count trap (M), a check that errored and reported a pass inside the step guarding #71 (M), and the wrap-up reinstating a merged correction (M). Handoff swept with --keep 4 (465 -> 322 plan lines, 325 after later edits); the default --keep 6 was a no-op because six blocks already exceeded the budget. The move is verbatim, but it is NOT cross-reference-clean: it created a new #73 instance, a relative "the 287-line figure above" now dangling in the history file while its referent stayed live. The inbox is 179/150 -- over budget the same day it was swept, from this session's own entries. Not swept inline per the wrap-up contract; noted in the handoff as an argument that #6 is closer to urgent than merely open. Verified with make test (503 passed), check_doc_budget (handoff 325/400) and kit_doctor (26 unchanged, 0 differ). --- docs/kit-friction-log.md | 43 +++++++ docs/kit-handoff-history.md | 139 +++++++++++++++++++++ docs/kit-handoff.md | 232 +++++++++++++----------------------- 3 files changed, 267 insertions(+), 147 deletions(-) diff --git a/docs/kit-friction-log.md b/docs/kit-friction-log.md index ec5c52e..8e7c8bd 100644 --- a/docs/kit-friction-log.md +++ b/docs/kit-friction-log.md @@ -134,3 +134,46 @@ The swept entries now live in the archive, under the section `Graduated 2026-07- swept inbox:** surfaced during pre-flight, recorded on operator instruction, and rewritten after review; it sits below the marker for the next pass, where it should be merged into `#121` rather than filed fresh. +- **An operator's remark was widened into a stronger claim and published as operator-confirmed — + on five surfaces, including the tracker.** *"CodeRabbit is currently not available here"* became + *"not installed, never exercised, nothing rate-limited, no credit run out"*, which was then used + to file a **structurally-never-reviews** verdict onto `#45` — the issue whose whole subject is + that such a verdict cannot be made from outside. Both panel lenses caught it independently. **H** + — proposed remedy: `#140` asks for the command behind *"X is not available here"*; it needs widening + to cover the positive form too, and a remark attributed to the operator should be quoted at its + original scope rather than paraphrased into its implications. Distinct from `#149`: that one asks + a correction to reach every surface, this asks the claim not to exceed its source in the first + place. +- **Correcting a wrong number with a precise one failed twice, because the number is not + recoverable.** The fix above asserted a review count that was really a count of bot comments; a + second round caught it, and two independent re-derivations of "how many PRs did CodeRabbit + actually review" then disagreed with each other — *reviewed* vs *quota-refused* vs *silent* is + not separable from the comment stream without deciding what counts. **M** — proposed fix: + withdrawing the count was the only stable move, and the irreducibility is better evidence for + `#45` than any count. Occurrence data for `#45`, and an argument that a machine-readable reviewer + state is the actual fix. +- **A check that errored reported a pass, inside the step guarding `#71`.** The closing-keyword + scan used a `grep -E` alternation with an empty branch; `ugrep` rejected it, exited non-zero, and + the `|| echo clean` branch fired. A later run of the rewritten scan read a **zero-byte** surface + (nothing staged) and also reported clean. **M** — occurrence data for `#150`, and a scope note: + `#150` is written for text *replacements*, and both instances here are *scans*. The durable form + is that any check must assert it examined something — a match count, a byte count, an explicit + failure — and `|| ` must never follow a command that can fail for reasons other + than the condition being tested. **Third instance, same session, different mechanism:** the + rewritten scan's own regex required the keyword and the reference to be adjacent modulo + whitespace, so it silently missed the same keyword followed by a **backtick-wrapped** reference — + the code-span form `CLAUDE.md` explicitly names and the archive already records firing against + `#61`. (Written as prose, not quoted: quoting it puts the live construction into an inbox entry a + future sweep will paste into an issue body.) It was caught only because the same + text appeared *without* backticks on another surface. A guard written from memory of a rule + reproduced the rule's headline and dropped its stated exception. +- **The wrap-up reinstated a correction that had merged forty minutes earlier.** `#151`'s review + changed "third sweep" to "fifth" on every surface it reached, and the handoff written immediately + after called it *"the third sweep"* again — in a heading, the `Last updated` line, the commit + subject, the PR title and the PR body — while the same block said "Fifth sweep overall" three + lines below. Two lenses caught it. **M** — occurrence data for `#149`, and a sharpening of it: the + six surfaces `#149` enumerates are the ones a claim *was* published to, which is the wrong + frame for this failure. The handoff was written from the session's memory rather than from the + merged artifact, so the corrected value never entered the drafting at all. The remedy is narrower + than "enumerate surfaces" — **when a session's own review changed a fact, the wrap-up must source + that fact from the merged text, not from recollection of the session.** diff --git a/docs/kit-handoff-history.md b/docs/kit-handoff-history.md index b11176a..b9c035b 100644 --- a/docs/kit-handoff-history.md +++ b/docs/kit-handoff-history.md @@ -4,6 +4,145 @@ Archived session narratives from [`kit-handoff.md`](kit-handoff.md). Keep active and the next step there; this file is append-only history. ## Session log +### 2026-07-28 (`#92` shipped; the record corrected; five panel rounds) + +**Theme —** Two deliverables, and a five-round panel that spent most of its findings on +this branch's own claims rather than on the code. The `AGENTS.md` template is the small +half; the durable result is a data-loss bug caught before it shipped and a much sharper +picture of where self-review fails. + +- **`#104` merged (`985dcd0`), closing `#92`.** `docs/templates/AGENTS.md.tmpl` — the + Codex entry point — rendered by `init.sh` through the same seed guard as the narrative + docs, with two new tokens (`{{PROTECTED_BRANCH}}`, `{{HANDOFF_PATH}}`, repo-relative). + `KIT_OWNED` row in, manifest 25 → 26. The verification command is deliberately a + fill-me placeholder, not a token: `init.sh` knows no such value, so rendering one would + have meant guessing (`#110` tracks giving it a real config key). +- **Seven corrections to the permanent record**, each re-verified against its primary + source before editing rather than taken from the review that prompted them. +- **The rule-citation count went six → nine → ten.** Nine was itself wrong; the miss was + `scripts/kit_doctor.py:101`. Two isolated lenses reached ten independently. +- **A live data-loss bug, caught pre-merge.** `seed_doc` matched the unrendered marker + *anywhere* in a file, so any in-use doc that merely quoted the marker in prose was + silently overwritten — no backup, run still printed "seeded". Reproduced against the + pre-fix script on both a hand-written `AGENTS.md` and a rendered `kit-handoff.md`. The + marker now counts on line 1 only, in `init.sh`, in `kit_doctor`, and in the tests. + +**Learned** + +- **Three separate pieces of new behaviour shipped unpinned** — the seeding call, both + token substitutions, and later the `kit_doctor` predicate. Each survived the full suite + when deleted. The manifest-hash gate reads as coverage and is not: it is discharged by + one documented regenerate command, after which the mutant is green. +- **A fix round introduced a regression while fixing that same class.** Aligning + `kit_doctor` with `init.sh` via `Path.read_text()` swapped one divergence for another, + because universal-newline translation ends a "first line" at a lone CR where `head -n 1` + ends only at LF. Round 3 caught it; round 2 had asserted the two matched "exactly". +- **A test can certify destroyed data as fine.** The line-1 assertions used + `splitlines()[0]`, which breaks on nine separators production does not. A `U+2028` + before the marker passed the suite while `init.sh` would seed over the live plan. +- **Rounds 1–4 each found a false claim in the previous round's fix**, most of them mine: + a fabricated rationale in a test docstring, a "harmless" characterisation of a bug that + was destroying data, a verification claim whose setup step was omitted, a side-effect + claim whose cited command was scoped narrowly enough to hide the difference, and four + consecutive sweeps declared complete that were not. The pattern is specific: the errors + cluster in prose *about* verification, not in the verification itself. +- **Two lenses beat one, twice.** Round 3's correctness lens explicitly cleared the CR + case as "behaviourally equivalent for all realistic inputs" — it had tested CRLF but not + CR-only, where the adversarial lens proved divergence by execution. A lens's "verified + clean" is worth exactly the edge cases it ran. +- **Convergence is visible when it happens.** Round 5 came back clean on the code: 4000 + randomized byte documents and a 30-cell separator matrix driving the test helper, the + `kit_doctor` predicate and the real `head -n 1 | grep -qF` over identical bytes, with + zero disagreements. That, not round count, is what ended the loop. + +**Open, and owned by nothing yet** + +- **`#105`–`#110`** — this session's six: `/adopt` never seeds `AGENTS.md`; `kit_doctor` + aborts on unreadable/directory/invalid-UTF-8 docs where `init.sh` fails safe; the marker + predicate is duplicated between `kit_doctor` and its tests and kept in sync by a + docstring; `AGENTS.md`'s config-derived links freeze at first render; the intermittent + `test_portability.py` flake; and the template's fill-me placeholder. +- **`#77` reproduced** — I edited the shared tree while a lens was reviewing it. The lens + caught it on its own initiative, not because the contract asks. Occurrence logged there. +- **`#47` gained a third instance** — `docs/AGENTS-sections.md` untracked, alongside `#37` + and `#41`. Not fixed, because adding one more hand-maintained row is what `#47` exists + to stop. +- **`#93`, `#95`, `#97`, `#98`** unchanged; `#54` is directly relevant after this session. +- `#50`, `#66`, `#71`, `#72`, `#75`, `#76`, `#86`, `#88` and the rest per `session-start`. + +▶ Next: `triage-friction-log` — **discharged**, shipped as `#126` later the same day. The +inbox is now 28 lines; the 287-line figure above is that session's reading, kept as the +record of why the sweep was called for. + +### 2026-07-28 (fix-round scope shipped; the severity gate it exposed) + +**Theme —** Two doctrine changes, the second existing because the first cost far more +than it should have. `#101` took three panel rounds and six isolated reviewers for one +paragraph; `#102` is the rule that stops that recurring. + +- **`#101` merged (`238de25`), closing `#100`.** Rule 3 gains *"a fix round addresses + only what the review found"* — a new mechanism is an addition however squarely a + finding prompted it, so it gets filed. Plus a paragraph in `fallback-review-panel.md` + stating that lever replaces none of the stopping criterion. +- **One of `#101`'s two HIGHs came from my own fix rounds — not both.** Round 2's HIGH + was a gap the rule inherited: it did not catch two of the three cases it is built on, + and `205d0a4`'s own message records that `#100`'s proposed wording has it too — round + 1's carve-out licensed those cases outright but did not create the gap. Round 3's + HIGH was mine: two fresh readers, given only the paragraph, both permitted the case, + both quoting my carve-out clause. +- **`#102` merged (`87dfa83`).** The blast-radius classification now also decides which + findings to act on. A gate, send path, destructive operation, or kill/recovery path — + plus any change that does not clearly sit in one class — gets **every** finding acted + on; only on the second, reported-but-never-acted-on class is the gate HIGH always, + plus anything at any severity that says the change is a *regression* rather than + merely imprecise. New contract item 9 makes lenses report both labels. +- **CodeRabbit reviewed neither PR's final state** — one clean pass on `#101`'s first + head, then a plan quota that no waiting clears. The fallback panel was the independent + pass throughout: five rounds, ten isolated lenses across the two PRs. + +**Decided** + +- **Two failed tightenings ⇒ delete, applied to my own clause.** `#101`'s carve-out was + itself an unrequested mechanism added mid-fix-round in response to a MED — the shape + the paragraph prohibits, reproduced inside it. Deleted rather than reworded a third + time. +- **Severity level alone is the wrong gate.** `#102`'s own first round returned 0 HIGH / + 7 MED, four of which said the paragraph loosened a control it claimed to tighten. The + discriminator that works is regression-vs-imprecision. +- **The gate belongs at the act-on stage, never in the lens prompts.** `#101` was + docs-only and drew two real HIGHs; a lens told to calibrate down for "it's only docs" + would have downgraded exactly those two. It is also the anchoring contract item 2 + forbids. + +**Learned** + +- **A gate that reads labels nothing produces is not a gate.** `#102`'s HIGH: "act on + HIGH" and "says regression" are lens output, and no contract item or `focus` string + ever asked for either. It read as working only because I supplied severity ad hoc in + my own launch prompts — the drift the single-source rule exists to stop. +- **A three-space list continuation is correct CommonMark and broken Python-Markdown**, + which silently renumbered rule 4 to rule 1 while the header still said "Four rules + apply". Ten files outside the session records cite these rules by number (fourteen + counting the records themselves). Caught by rendering in both engines, + not by review — a genuine completed bot review of the head carrying it passed clean. +- **I shipped a false claim in a commit message** (`4ac203e`), retracted in the PR body + before merge, so it never reached `main`. +- **`#76` reproduced twice**: neither PR's final head was lens-reviewed, and + `--record-review --head` can only assert the exact head, so both merged with the + coverage recorded as PR prose and no receipt. + +**Open, and owned by nothing yet** + +- **`#92`, `#93`** — untouched; `#92` was the planned follow-on and now lands under both + new rules. +- **`#95`, `#97`, `#98`** — the three panel-found defects on `main`, unchanged. +- `#47`, `#54`, `#66`, `#71`, `#72`, `#75`, `#76`, `#77`, `#86`, `#88` and the rest per + `session-start`. + +▶ Next: `#92` — ship `docs/templates/AGENTS.md.tmpl` rendered by `init.sh`, added to +`KIT_OWNED` and the manifest so `kit_doctor` reports it. Read `#92` for the generic +spine to lift; note in the template that adopters are expected to extend it. + ### 2026-07-27 · 4 (gh-less REST transport; `#91` closed, `#96` merged) **Theme —** One feature, five review rounds, two PRs. The first attempt was closed diff --git a/docs/kit-handoff.md b/docs/kit-handoff.md index 6ad5b29..74a5be9 100644 --- a/docs/kit-handoff.md +++ b/docs/kit-handoff.md @@ -14,10 +14,91 @@ > Older session blocks graduate to [`kit-handoff-history.md`](kit-handoff-history.md) once > this file crosses its line budget (`scripts/check_doc_budget.py`). -Last updated: 2026-07-29 — the inbox graduated a second time (`#144`) and the documentation -was audited against the shipped tree (`#147`); eight new tickets (`#138`–`#146`). +Last updated: 2026-07-29 — the inbox graduated for the fifth time (`#151`, merged `494b9eb`); two new +tickets (`#149`, `#150`) and a HIGH whose own fix produced a second HIGH. + +## Latest session — 2026-07-29 (the fifth sweep, and a claim that was wrong in both directions) + +**Theme —** One merge, four panel rounds, seven isolated lenses (two rounds on `#151`, two on the +wrap-up PR that records it). The sweep itself was never contested by any lens. The durable result is a failure mode the previous session's measurement +predicted but did not name: **an operator's narrow remark, inflated into a stronger claim and +published as operator-confirmed.** The fix for it then over-corrected, and round 2 caught that. + +- **`#151` merged (`494b9eb`).** Fifth `triage-friction-log` sweep overall, dated 2026-07-29. + Seven entries in, seven out: one graduated into two issues (`#149`, `#150`), six routed as + seven occurrence comments (`#120`, `#138`, `#127`, `#75`, `#71`, `#45`, `#113`). LLM-only mode + again (`#6` still not vendored). Inbox 203 → 136 against a 150 budget. +- **Two tickets filed:** `#149` (when a claim is corrected, enumerate every surface it was + published to *at that moment*), `#150` (a scripted text replacement that matches nothing must + fail, not report success). +- **The HIGH, and the HIGH inside its fix.** The operator said CodeRabbit is *currently* not + available here. That was published as *"not installed, never exercised, nothing rate-limited"* — + and then used to file a **structurally-never-reviews** verdict onto `#45`, the issue whose + entire subject is that such a verdict cannot be made from outside. Both lenses found it + independently. `#45`'s own body records a **Pro Plus** plan; `Review limit reached` notices sit + on `#89` and `#99`. The correction then asserted a review count that was really a count of bot + comments, and round 2 found *that*. Two independent re-derivations of "how many PRs did it + actually review" disagreed with each other, so **no count was published**. +- **The silent run is twelve PRs, not seven** — `#102`, `#103`, `#104`, `#111` and `#148` were + never counted. Third consecutive undercount in that series (four → six → seven → twelve). And + `#151` merged silent too, so it is **thirteen** by the same rule — a lens caught the tally going + stale inside the sentence announcing it was stale. -## Latest session — 2026-07-29 (the second sweep, and a documentation audit) +**Learned** + +- **An operator's remark has a scope, and widening it is the same defect as inventing it.** + "Currently not available" is not "never installed". The wider version was published on five + surfaces and read as operator-confirmed on all of them, which is what made it durable. + `#140` already asks for the command behind *"X is not available here"*; it arguably needs + widening to cover *"X **is** available here, this much"* — round 2's finding. +- **Correcting a wrong number with a right one is a trap when the number is not recoverable.** + Reviewed vs. quota-refused vs. silent is not cleanly separable from the comment stream without + deciding what counts, and each attempt decided differently. Withdrawing the count was the only + stable move — and the irreducibility is *better* evidence for `#45` than any count. +- **Deleting beat correcting, again — and it is now two-for-two.** Five review rounds across two + sweeps have gone to the marker's verification section, every one finding the prose claiming more + than the checks did. This session cut it rather than correct it a third time. +- **A check that errors can report a pass.** A closing-keyword scan built on a `grep -E` + alternation with an empty branch was rejected by `ugrep`, exited non-zero, and the `|| echo + clean` branch fired — printing a clean result from a check that never ran, inside the step + guarding `#71`. A second run scanned a zero-byte surface and also read clean. +- **`#75`: 4 of 4 lens launches again**, all self-corrected. No running total is claimed; the + addendum posted this session declares the existing tallies approximate and unreconcilable. +- **The check harness was left unfixed on purpose.** Round 2 showed checks 4/5 have headings + larger than their assertions and that checks 1+2 share no trust chain (a forged snapshot yields + byte-identical output). Documented, not repaired — building a harness inside a fix round is the + mechanism-creep the panel doctrine warns against, and `#138`/`#127` exist to ask for it. + +**Open, and owned by nothing yet** + +- **`#149` and `#150`** — this session's two. `#149`'s own six-surface list **omits PR comments**, + found by a lens after a retracted claim survived on one; that gap is unrecorded on the issue. +- **`#121` should absorb the config-placeholder question** rather than have it re-filed. This + session re-derived `#121` from scratch without noticing it, and the rewrite of that entry then + made a *larger* false claim than the one it corrected. The live inbox entry now routes there. +- **`#138` and `#127` are still the pair that would make a sweep's claims mechanically checkable**, + and both were reproduced *again* inside this session's pilot run of them. +- **`#73` gained a *new* instance from this session's own archive sweep**, in the other direction: + `kit-handoff-history.md` now says *"the 287-line figure **above**"* while that figure stayed in the + live handoff. A lens found it; an earlier draft of this bullet claimed the *predicted* instance + instead, which was the previous session's. Recorded in no routing row. +- **`#33`, `#112`, `#132` housekeeping is unchanged** from the previous session; `#132` is closed, + so cs-toolkit Phase 2 blockers remain `#41`/`#37`/`#134`. +- **The inbox is back over budget the same day it was swept** — 179/150. The sweep took it 203 → + 136; wrapping up added four more entries and took it to 179. Not swept inline, per the + wrap-up contract: graduating needs tracker writes and operator approval. Worth noting that a + sweep now buys roughly one session of headroom, which is an argument for `#6` (vendor the + engine) becoming urgent rather than merely open. + +▶ Next: `session-start` — the threads are genuinely diffuse (two fresh tickets, two observations +recorded nowhere but here, and unchanged housekeeping), and nothing in the inbox is urgent despite it +being over budget. Page the tracker at `perPage: 25` reading `number`/`title`/`labels`/`state` +only — `#143` records `session-start` overflowing its tool limit at 68 open issues, and there are +~82 now. + +______________________________________________________________________ + +## Earlier session — 2026-07-29 (the second sweep, and a documentation audit) **Theme —** Two merges and eight panel rounds. The deliverables are routine; the durable result is a measurement: **across eight rounds and at least fifteen isolated lenses, no HIGH finding @@ -91,7 +172,7 @@ files, so "prose" means wherever it lives — and the prose that kept failing wa - **`#33` and `#112` are shipped but still open** — close them deliberately after confirming `#131` is what each asked for. -▶ Next: `triage-friction-log` — the inbox is 196/150, the same tripwire that opened this +▶ Next: `triage-friction-log` — **discharged** (`#151`). The inbox was 196/150, the same tripwire that opened this session, and its seven entries are the freshest evidence behind `#120`, `#138`, `#127` and `#71`. Prefer it over `session-start` this time: `#143` (filed here) records that `session-start`'s tracker step overflowed its tool limit at 68 open issues and that the remedy it prescribes cannot @@ -237,149 +318,6 @@ because every future mutation-testing claim depends on it. ______________________________________________________________________ -## Earlier session — 2026-07-28 (`#92` shipped; the record corrected; five panel rounds) - -**Theme —** Two deliverables, and a five-round panel that spent most of its findings on -this branch's own claims rather than on the code. The `AGENTS.md` template is the small -half; the durable result is a data-loss bug caught before it shipped and a much sharper -picture of where self-review fails. - -- **`#104` merged (`985dcd0`), closing `#92`.** `docs/templates/AGENTS.md.tmpl` — the - Codex entry point — rendered by `init.sh` through the same seed guard as the narrative - docs, with two new tokens (`{{PROTECTED_BRANCH}}`, `{{HANDOFF_PATH}}`, repo-relative). - `KIT_OWNED` row in, manifest 25 → 26. The verification command is deliberately a - fill-me placeholder, not a token: `init.sh` knows no such value, so rendering one would - have meant guessing (`#110` tracks giving it a real config key). -- **Seven corrections to the permanent record**, each re-verified against its primary - source before editing rather than taken from the review that prompted them. -- **The rule-citation count went six → nine → ten.** Nine was itself wrong; the miss was - `scripts/kit_doctor.py:101`. Two isolated lenses reached ten independently. -- **A live data-loss bug, caught pre-merge.** `seed_doc` matched the unrendered marker - *anywhere* in a file, so any in-use doc that merely quoted the marker in prose was - silently overwritten — no backup, run still printed "seeded". Reproduced against the - pre-fix script on both a hand-written `AGENTS.md` and a rendered `kit-handoff.md`. The - marker now counts on line 1 only, in `init.sh`, in `kit_doctor`, and in the tests. - -**Learned** - -- **Three separate pieces of new behaviour shipped unpinned** — the seeding call, both - token substitutions, and later the `kit_doctor` predicate. Each survived the full suite - when deleted. The manifest-hash gate reads as coverage and is not: it is discharged by - one documented regenerate command, after which the mutant is green. -- **A fix round introduced a regression while fixing that same class.** Aligning - `kit_doctor` with `init.sh` via `Path.read_text()` swapped one divergence for another, - because universal-newline translation ends a "first line" at a lone CR where `head -n 1` - ends only at LF. Round 3 caught it; round 2 had asserted the two matched "exactly". -- **A test can certify destroyed data as fine.** The line-1 assertions used - `splitlines()[0]`, which breaks on nine separators production does not. A `U+2028` - before the marker passed the suite while `init.sh` would seed over the live plan. -- **Rounds 1–4 each found a false claim in the previous round's fix**, most of them mine: - a fabricated rationale in a test docstring, a "harmless" characterisation of a bug that - was destroying data, a verification claim whose setup step was omitted, a side-effect - claim whose cited command was scoped narrowly enough to hide the difference, and four - consecutive sweeps declared complete that were not. The pattern is specific: the errors - cluster in prose *about* verification, not in the verification itself. -- **Two lenses beat one, twice.** Round 3's correctness lens explicitly cleared the CR - case as "behaviourally equivalent for all realistic inputs" — it had tested CRLF but not - CR-only, where the adversarial lens proved divergence by execution. A lens's "verified - clean" is worth exactly the edge cases it ran. -- **Convergence is visible when it happens.** Round 5 came back clean on the code: 4000 - randomized byte documents and a 30-cell separator matrix driving the test helper, the - `kit_doctor` predicate and the real `head -n 1 | grep -qF` over identical bytes, with - zero disagreements. That, not round count, is what ended the loop. - -**Open, and owned by nothing yet** - -- **`#105`–`#110`** — this session's six: `/adopt` never seeds `AGENTS.md`; `kit_doctor` - aborts on unreadable/directory/invalid-UTF-8 docs where `init.sh` fails safe; the marker - predicate is duplicated between `kit_doctor` and its tests and kept in sync by a - docstring; `AGENTS.md`'s config-derived links freeze at first render; the intermittent - `test_portability.py` flake; and the template's fill-me placeholder. -- **`#77` reproduced** — I edited the shared tree while a lens was reviewing it. The lens - caught it on its own initiative, not because the contract asks. Occurrence logged there. -- **`#47` gained a third instance** — `docs/AGENTS-sections.md` untracked, alongside `#37` - and `#41`. Not fixed, because adding one more hand-maintained row is what `#47` exists - to stop. -- **`#93`, `#95`, `#97`, `#98`** unchanged; `#54` is directly relevant after this session. -- `#50`, `#66`, `#71`, `#72`, `#75`, `#76`, `#86`, `#88` and the rest per `session-start`. - -▶ Next: `triage-friction-log` — **discharged**, shipped as `#126` later the same day. The -inbox is now 28 lines; the 287-line figure above is that session's reading, kept as the -record of why the sweep was called for. - -______________________________________________________________________ - -## Earlier session — 2026-07-28 (fix-round scope shipped; the severity gate it exposed) - -**Theme —** Two doctrine changes, the second existing because the first cost far more -than it should have. `#101` took three panel rounds and six isolated reviewers for one -paragraph; `#102` is the rule that stops that recurring. - -- **`#101` merged (`238de25`), closing `#100`.** Rule 3 gains *"a fix round addresses - only what the review found"* — a new mechanism is an addition however squarely a - finding prompted it, so it gets filed. Plus a paragraph in `fallback-review-panel.md` - stating that lever replaces none of the stopping criterion. -- **One of `#101`'s two HIGHs came from my own fix rounds — not both.** Round 2's HIGH - was a gap the rule inherited: it did not catch two of the three cases it is built on, - and `205d0a4`'s own message records that `#100`'s proposed wording has it too — round - 1's carve-out licensed those cases outright but did not create the gap. Round 3's - HIGH was mine: two fresh readers, given only the paragraph, both permitted the case, - both quoting my carve-out clause. -- **`#102` merged (`87dfa83`).** The blast-radius classification now also decides which - findings to act on. A gate, send path, destructive operation, or kill/recovery path — - plus any change that does not clearly sit in one class — gets **every** finding acted - on; only on the second, reported-but-never-acted-on class is the gate HIGH always, - plus anything at any severity that says the change is a *regression* rather than - merely imprecise. New contract item 9 makes lenses report both labels. -- **CodeRabbit reviewed neither PR's final state** — one clean pass on `#101`'s first - head, then a plan quota that no waiting clears. The fallback panel was the independent - pass throughout: five rounds, ten isolated lenses across the two PRs. - -**Decided** - -- **Two failed tightenings ⇒ delete, applied to my own clause.** `#101`'s carve-out was - itself an unrequested mechanism added mid-fix-round in response to a MED — the shape - the paragraph prohibits, reproduced inside it. Deleted rather than reworded a third - time. -- **Severity level alone is the wrong gate.** `#102`'s own first round returned 0 HIGH / - 7 MED, four of which said the paragraph loosened a control it claimed to tighten. The - discriminator that works is regression-vs-imprecision. -- **The gate belongs at the act-on stage, never in the lens prompts.** `#101` was - docs-only and drew two real HIGHs; a lens told to calibrate down for "it's only docs" - would have downgraded exactly those two. It is also the anchoring contract item 2 - forbids. - -**Learned** - -- **A gate that reads labels nothing produces is not a gate.** `#102`'s HIGH: "act on - HIGH" and "says regression" are lens output, and no contract item or `focus` string - ever asked for either. It read as working only because I supplied severity ad hoc in - my own launch prompts — the drift the single-source rule exists to stop. -- **A three-space list continuation is correct CommonMark and broken Python-Markdown**, - which silently renumbered rule 4 to rule 1 while the header still said "Four rules - apply". Ten files outside the session records cite these rules by number (fourteen - counting the records themselves). Caught by rendering in both engines, - not by review — a genuine completed bot review of the head carrying it passed clean. -- **I shipped a false claim in a commit message** (`4ac203e`), retracted in the PR body - before merge, so it never reached `main`. -- **`#76` reproduced twice**: neither PR's final head was lens-reviewed, and - `--record-review --head` can only assert the exact head, so both merged with the - coverage recorded as PR prose and no receipt. - -**Open, and owned by nothing yet** - -- **`#92`, `#93`** — untouched; `#92` was the planned follow-on and now lands under both - new rules. -- **`#95`, `#97`, `#98`** — the three panel-found defects on `main`, unchanged. -- `#47`, `#54`, `#66`, `#71`, `#72`, `#75`, `#76`, `#77`, `#86`, `#88` and the rest per - `session-start`. - -▶ Next: `#92` — ship `docs/templates/AGENTS.md.tmpl` rendered by `init.sh`, added to -`KIT_OWNED` and the manifest so `kit_doctor` reports it. Read `#92` for the generic -spine to lift; note in the template that adopters are expected to extend it. - -______________________________________________________________________ - > Older session entries (below the live blocks above) live in [`kit-handoff-history.md`](kit-handoff-history.md). > Active open items from them are folded into the "Open for next session" lists above.