Repository navigation
feat(inflight): docs context query - divergence header at read time, keyword injection, inflight docs - #419
Conversation
…ead time, keyword injection, inflight docs An agent working here is told, without asking, when a document it is reading has a newer version on another branch, or when a mechanism it names has a write-up it cannot see from its own branch. The motivating incident was the opposite: an agent found the right document on master, acted on it, and the correction sat on a branch with nothing to say so. What this commit adds is the requirements-only plan for one context query in bin/inflight.mjs and its three agent-facing deliveries - a divergence header on any docs file at read time, titles injected per prompt keyed on the prompt's own words, and an `inflight docs` command family that browses the corpus and, called bare, says what exists and what the tool can do. The session-start index migrates onto the same query and becomes corpus-scoped. Decisions the brainstorm settled, and the alternatives it rejected: - Agents are the only audience. A browsable front end was considered and dropped: the use is agents driving a CLI and hooks. - The header ships first and alone, because it is the one piece that would have caught the incident; injection and `inflight docs` follow on the same query. - The header appears on both direct reads and tool output, so the agent that never runs the tool is still told. Coverage of Bash reads is best-effort by path token. - One query with three renderings, over three hooks each reading the corpus its own way. - The session-start title list stays whole rather than shrinking once injection exists: the list is for recognition, injection is for the moment, and neither substitutes for the other. - No MCP adapter in this work; the sketch is recorded in the plan so it is not re-derived. Also records a constraint the claim verifier corrected: the corpus index has no cache today and rebuilds from git on every run, so a per-read hook pays that cost until caching lands. The plan carries a latency budget for the header rather than assuming reads are free. Adds "Divergent version" to CONCEPTS.md, the term the header turns on, and the branch's working note. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
…xists Renamed from branch- to pr-419- per docs/inflight/AGENTS.md; nothing cited the old path. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
✅ Duplicate Code ReportTwo engines run in parallel for cross-validation. Each has its own thresholds tuned to its baseline - the real safety net is the per-engine "max increase vs base" check. ✅ PMD CPD
No new clones introduced by this PR. ✅ jscpd (language-agnostic)
No new clones introduced by this PR. Powered by astubbs/duplicate-code-cross-check |
[superseded - a quarantined test changed outcome] 🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its Updated for Superseded by a newer quarantine lane report. |
|
[superseded - a quarantined test changed outcome] 🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its No quarantined test changed outcome since the previous push. Updated for Superseded by a newer quarantine lane report. |
[superseded - status changed to no-rate] 🟢 Throughput — OKThis branch measured about 12% slower than master, on the one test this measures. That is INSIDE this test's own run-to-run spread of about 17%, so read it as a reading and not as a result - re-running the same commit moves it by about as much.
Allowable range 🟢 ≥ 0.70 · 🟡 0.50–0.70 (about a 30% loss) · 🔴 < 0.50 (about a 50% loss) What the numbers mean, and what they cannot tell youThe one that gets misread. Why a shape and not a rate. A rate depends on which runner you drew. A shape does not: every test here processes a fixed number of records, so a runner twice as slow doubles the subject and the controls together and leaves their ratio alone. That is the whole trick, and it is why the reported rate is shown last and labelled as this machine only. Reading the comparison. By conservation, not by correction. Every test in this lane processes a fixed number of records, so within one run the ratio of one test's time to another's is invariant under machine speed — a runner twice as slow doubles both terms and leaves the ratio alone. There is no machine-index correction to be wrong, because nothing needed correcting. Per-method times, not class times. A class time is Reference is the median of 10 recent What this still cannot do. It removes machine-to-machine variance. It does not remove this test's own run-to-run variance, measured at about 30% on a single unchanged commit while its controls stayed within 5%. That is a property of the test, not of the comparison, and no arithmetic here can touch it — which is why the reference is a median and the bounds are deliberately coarse. 🟡 means look at this; only 🔴 is outside the measured spread. Runs used: 10ed71c, 75b48bb, e028296, 8df9cc7, 88f5774, ebd8bcb, 626fc32, 9ff715d, 856dc54, b917ae6 Since the previous push: ratio 1.132 -> 0.88, share 1.442 -> 1.854, rate 75828 -> 61102 (-19.4%). One push of difference sits inside this test's measured spread - read it as movement, not as a result. Updated for Superseded by a newer throughput report. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #419 +/- ##
============================================
+ Coverage 81.57% 82.10% +0.52%
- Complexity 1462 1472 +10
============================================
Files 95 95
Lines 5118 5118
Branches 498 498
============================================
+ Hits 4175 4202 +27
+ Misses 745 723 -22
+ Partials 198 193 -5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…corrected against the code The requirements plan is enriched in place with the planning contract, seven implementation units, a verification contract and a definition of done. Two document-review rounds ran against it (four reviewer lenses plus an independent codex read on the requirements; three lenses on the implementation plan), and their accepted findings are folded in rather than left as open items, because the pipeline runs hands-off. What the review corrected, each verified against the tree before it was taken: - The corpus already spans every ref: refTips looks everywhere and refKind marks tags and backup refs archival. The "widen the corpus later" deferral was stale; the header now reports archival-only versions as preserved, never as divergent branches. - The header never builds the corpus index. drift asks git about one path, so the per-read cost is the narrow query and the index cost falls on the corpus-wide deliveries. Budgets are cold; there is no warm state and no cache decision to make. - corpusIndex covers inflight notes only; the query widens it to solutions and plans through one DOC_AREAS constant that prior-art's sections derive from too. - Injection matches frontmatter retrieval fields first, then headings, then capped body text, because class names live in related-components fields, not headings; and a document injected once in a session is not injected again unless its divergence changed. - Divergence is always baseline-relative and the header names which of three states the copy at hand is in, comparing the committed blob so a dirty worktree is not reported as a divergent version elsewhere. "Newer" is gone from the vocabulary; only "divergent" remains. - A dead delivery is distinguishable from silence: each records its last failure and the bare docs call prints it. - The existing write-time solutions hook is named as a delivery and kept; the deferred files-touched trigger is re-keyed on written text, the shape that hook measured as useful. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A single git grep pass for prompt injection (the corpus index would have cost seconds per prompt), batched title reads for the session index, the summary tier carrying the copy-at-hand added size, a corpusIndex areas option so note find and stranded keep their scope, a pinned-SHA equivalence test with a positive control, the registration-count sentence the hook audit parses, and search over live refs with preservation reported from all refs. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Pushed at the author's request so the draft PR shows progress. Not a complete unit: the self-test suite may be red on this commit. The finished unit follows as its own commit. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… costs, over every docs area Lands U1 of the docs context query plan. The code is the snapshot pushed one commit earlier at the author's request; this commit closes the unit with its working-note update, and the two together are the unit. What changed for an agent: `drift` now answers at two costs. The summary tier resolves which refs carry which blob, the baseline's history and the added size of the copy at hand only, in a few hundred milliseconds with one merge-base; the full tier adds branch facts and a preview of what each divergent version adds - its added headings, else its first added line - so the header can say what a branch knows without the reader running twenty-six diffs. Versions carried only by archival refs (tags, backup refs) are reported as preserved and no longer counted as divergent, which changes one line of `note drift` output for the most-shared note and nothing else. The corpus index gains an areas option defaulting to a single DOC_AREAS constant that prior-art's sections now derive from; `note find` and `stranded` keep the notes-only scope they had, and `stranded` says so in its usage. Titles are read in one cat-file batch rather than one fork per blob, which the session index will need. A source-frame helper puts a fixed label first and the "more" command last on every block the harness will inject. Two traps recorded in the code: Node 25 rejects `encoding: 'buffer'` on child_process, so the batch reader uses `encoding: null`; and the shared self-test fixture carries exact-count assertions that a widened corpus would break, so the docs checks build their own repository. The stale corpus-scope section of ci-inflight-next-commands.md is rewritten as resolved: refTips has looked everywhere since #400 landed. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
[superseded - a quarantined test changed outcome] 🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its Since the previous push: Updated for Superseded by a newer quarantine lane report. |
[superseded - a quarantined test changed outcome] 🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its No quarantined test changed outcome since the previous push. Updated for Superseded by a newer quarantine lane report. |
…file Lands U2 of the docs context query plan: the first delivery, on its own, as the plan orders. What changed for an agent: reading a file under docs/inflight, docs/solutions or docs/plans - through the Read tool, or a Bash command whose tokens name the path - now delivers one line alongside the result saying how many divergent versions exist on live branches, how many refs carry them, what state the copy at hand is in (baseline, this branch's own divergent version, branch-only), whether the working copy has uncommitted edits, and the command that prints the full header. It fires once per session per divergence state, and never blocks: any failure exits 0 with no output and is recorded so a later bare `inflight docs` can say the delivery failed. Verified before it was written, against Claude Code 2.1.258: a PostToolUse hook matched on Read delivers additionalContext to the model the way it does for Bash, so the read-time moment needs no pre-read hook and no latency in front of the read. Recorded in docs/agent-harness.md with the probe shape. Measured cold cost about 240 ms against a 500 ms budget, published in the hook header. Shared pieces extracted rather than copied: the tree derivation and the per-session seen-store move from the solutions-surfacing hook into .claude/hooks/lib/hook-common.mjs; the corpus fixture moves out of the tool self-test into bin/lib/fixture-repos.mjs so the hook suite drives the same repository shape. Tree derivation follows the 2026-08-31 solution: the command or payload first, the session root last. Two traps recorded: git's fatal lines reached the hook's stderr because execFileSync inherits it, so exec now returns the child's stderr as a value; and the registered-hook audit parses a counted sentence in the harness doc whose number words stopped at twenty, so it now derives the compound words. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…own channel Lands U3 of the docs context query plan, and gives the read-time hook the command it names. What changed for an agent: `inflight docs show <path>` prints one document under its full divergence header from the ref that carries it - the baseline when it does, else the first live carrier in sorted ref order, never an archival ref unless `--ref` asks - and always names the ref on its first line. `inflight docs header <path>` prints the header alone, byte-identical to `docs show --header-only`. A path on no ref answers with the refs it searched, exit 0; a path outside the three docs areas names the areas; an unreadable repository exits 2. The header's "more" command now points at the version the preview put first rather than the most carried cluster, which on the most-shared note was a different branch. The bare `docs` call is a usage error until the next unit gives it the corpus shape. docs/inflight-tool.md gains the worked examples in its own voice. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
[superseded - status changed to OK] 🟠 Throughput — no rate to reportThe performance lane ran but produced no usable Not a pass — both of those look identical to a clean lane otherwise, which is exactly why this is reported rather than skipped. Since the previous push: status OK -> no-rate. One push of difference sits inside this test's measured spread - read it as movement, not as a result. Updated for Superseded by a newer throughput report. |
…th each prompt, across every live ref Lands U4 of the docs context query plan: the second delivery. What changed for an agent: a prompt that names a class, a flag, a path, a backticked token or an issue number now gets, alongside the prompt, the titles and paths of the documents that name it across every live ref - marked when off the baseline or divergent elsewhere - once per document per divergence state per session, capped with a `+N more` tail and the prior-art command for the rest. A prompt with no identifier-shaped token gets nothing and costs about the price of starting Node, because the silent path loads only the term extractor. Matching order, as the plan decided after the requirements review: a document's frontmatter fields outrank its headings, which outrank body text, because class names live in related-components fields and not in headings; body hits are capped per term. One git grep over live refs is the whole read - the corpus index is never built on this path. Two measured decisions recorded in the code: fixed-string grep (`-F -e a -e b`) instead of an alternation, because the alternation alone cost more than the firing budget on this repository; and issue references collapsed to their bare number so every qualified spelling matches. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… is unavailable On a runner with no authenticated gh, the PR-facts warning printed before the page, so the first line named the warning rather than the ref shown - invisible on a machine where gh is logged in, red on the Linux self-test lane for the three docs show checks. The warning now goes inside the header box with the freshness warnings, which is where the plan puts every scope warning. Reproduced in a node:22 container before the fix; green there and on macOS after it. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
🟢 Throughput — OKThis branch measured the same speed as master, on the one test this measures.
Allowable range 🟢 ≥ 0.70 · 🟡 0.50–0.70 (about a 30% loss) · 🔴 < 0.50 (about a 50% loss) What the numbers mean, and what they cannot tell youThe one that gets misread. Why a shape and not a rate. A rate depends on which runner you drew. A shape does not: every test here processes a fixed number of records, so a runner twice as slow doubles the subject and the controls together and leaves their ratio alone. That is the whole trick, and it is why the reported rate is shown last and labelled as this machine only. Reading the comparison. By conservation, not by correction. Every test in this lane processes a fixed number of records, so within one run the ratio of one test's time to another's is invariant under machine speed — a runner twice as slow doubles both terms and leaves the ratio alone. There is no machine-index correction to be wrong, because nothing needed correcting. Per-method times, not class times. A class time is Reference is the median of 10 recent What this still cannot do. It removes machine-to-machine variance. It does not remove this test's own run-to-run variance, measured at about 30% on a single unchanged commit while its controls stayed within 5%. That is a property of the test, not of the comparison, and no arithmetic here can touch it — which is why the reference is a median and the bounds are deliberately coarse. 🟡 means look at this; only 🔴 is outside the measured spread. Runs used: 77fbba8, 7a8a7f0, 2e2705a, 28c6be6, c813942, 558fcfb, 5ae7b34, 10ed71c, 75b48bb, e028296 Since the previous push: ratio 0.902 -> 1.001, share 1.683 -> 1.5, rate 64238 -> 72151 (+12.3%). One push of difference sits inside this test's measured spread - read it as movement, not as a result. Updated for |
…to one document by copied commands Lands U5 of the docs context query plan: the third delivery's browse half. What changed for an agent: `inflight docs` with no arguments prints every docs area with its groups and counts across every ref - how many documents each holds and how many exist only off the baseline - then every docs subcommand with the sentence that says when to use it, then one line per delivery whose last run failed, then the refs it searched. `docs list <area> [<group>]` prints one level with the commands for the next, down to titles with `docs show` commands, so an agent that knows nothing about the corpus reaches a document by copying what it was shown. Unknown names are answered with the valid names as commands rather than a usage error. The grouping is the session index's: solutions by category directory, inflight notes by the cost-of-not-knowing order with registers first and deferred work last, plans by month. The tag vocabulary now lives in Node as well as bash, held together by a parity check that sources the bash library and fails on any difference, until the gate itself migrates. Titles and markers come from one cat-file batch, never one fork per blob. AGENTS.md gains one row in the investigate table so a host without hooks has the pull form of every delivery. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…ResidentIT setup-guard flake Seen on this PR's integration lane at a head that changes no Java. Same shape as the first sighting: the pause-point setup guard timed out with a clean ambient probe, and the confluentinc#909 assertion was never reached. Recorded before the branch merges, because the evidence expires with the CI log. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
[superseded - a quarantined test changed outcome] 🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its Since the previous push: Updated for Superseded by a newer quarantine lane report. |
🧪🔒 Quarantine Lane Report
🔴 expected while the owner PR is open · 🟡🎲 flapper, pass proves nothing · 🚨 a deterministic quarantined test passing means its fix landed: delete its No quarantined test changed outcome since the previous push. Updated for |
… the query, and lists what it could not see before Lands U6 of the docs context query plan: the session index migrates onto the query. What changed for an agent: the index every session opens with now covers the whole corpus for the three docs areas rather than the checked-out branch's copy of it. Documents that exist only off the baseline appear under each area grouped by the set of branches carrying them, largest workstream first, the current branch's own group pinned to the top, and beyond a line cap the rest collapse to a count and the command that lists them. The sections outside the corpus - ideation, the test-hardening audits, the repo-level registers - keep their working-tree rendering. The hook no longer scans the tree in bash and no longer sources the bash tag vocabulary; when node is absent or the call fails it says the delivery failed and never falls back to the old scan. An equivalence test materialises the pre-migration hook at the merge-base commit on master, runs it against the current checkout, proves it printed its own headings, and then proves every title it listed is in the new index. Pinned to a master commit so a squash-merge cannot orphan it. A real defect fixed on the way: process.exit drops stdout still queued on a pipe, so a page over 64 KB captured through command substitution arrived cut off, exit 0, and the hook silently lost its plans section. The front door now sets exitCode and lets the stream drain; a self-test pins it. Session start measured on this repository: inside the 8 s budget on a quiet host with little headroom, almost all of it the one-ls-tree-per-ref shape of the corpus index; the lever is named in the hook header for whoever needs the headroom. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… its PR and its issues Lands U7 of the docs context query plan, the last unit: the branch's own facts as a trigger. What changed for an agent: a session opened on a branch now sees, after the corpus index, the documents across every live ref that name the branch's slug, its PR number, or the identifiers in the cached PR title - the same line shape and marks as the per-prompt block, so the two read as one family. On the baseline or a detached head it says so in one line. PR facts come from the tool's cache only, never a gh call at session start, and the block's first line says whether the PR was in the cache, because a branch opened minutes ago is exactly when that matters and the cache is a day old. `inflight docs for-branch [<ref>]` is the pull form. The prompt hook and this command share one hit formatter, lifted into the views so the two cannot drift. Measured on this repository: the block costs about a second; the whole session-start hook now sits a little above its budget on a quiet host, almost all of it the corpus index's one-ls-tree-per-ref shape. The lever is named in the hook header and pulled in the next commit. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The corpus index ran one ls-tree per ref, and most ref tips share the same docs tree object, so most of those calls returned identical answers. It now resolves every ref's docs tree in one cat-file batch, lists each distinct tree once, and fans the rows back out per ref. The index's rows are byte-identical; a self-test compares them against the per-ref listing they must reproduce, and a mutant that restores one listing per ref goes red. What it changed for an agent: session start on this repository dropped from just under the budget to comfortably inside it, and bare `inflight docs` by about the same share. The shape and the reproduce command are in the corpusIndex header; the figures live nowhere a reader would mistake for current state. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…tion as a marker The registered-hook audit asserts the session index lists the refactoring register by its title, and that title spells out the marker words the todo index scans for. On the merge head the committed index went stale by exactly that one line, and the hygiene lane went red. The pattern is now split around the words so the assertion still matches and the scanner has nothing to find. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…mily in its own modules The simplify pass over the branch, driven by the author's review. Behaviour unchanged: every command's output diffs empty against captures taken before the pass, apart from the capped added-headings line, and every suite is green on macOS and Linux. The tag vocabulary has one owner now. bin/lib/inflight-tags.mjs holds the sets and prints them as shell assignments on request; bin/lib/inflight-tags.sh is a thin wrapper that evals that output and refuses loudly when node is missing, so the gates that source it keep working and nothing can drift between two copies. The parity test became a round-trip test. The docs family moved out of the front door and the shared views: bin/lib/docs-commands.mjs holds the command bodies with their summary and usage text, the way prior-art always has, and bin/lib/docs-views.mjs holds the divergence header, the show, shape, list and index renderings, the source frame and the hit line. bin/inflight.mjs keeps the registry rows; bin/lib/views.mjs keeps the older family plus the two helpers both families share. Duplication the seven units introduced is gone: one renderer for the added-size classification that three formatters had each written, one match-body renderer for the prompt hook and the branch-facts command, one fail-open wrapper for both hooks, and three exports with no consumer made private. The working-tree comparison in the read-time hook now asks git hash-object, so clean filters and line-ending normalisation match what git would commit. Two efficiency findings landed with negative-controlled checks: drift accepts the refs, baseline and blob lookup a caller already resolved, and computes branch facts and previews only for the versions the header will show; and the added-headings preview is capped like every other list in the views. Measured on the busiest note the header render dropped by about half. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…g on a branch with no Java The `shell: macos` lane checked out at the default depth, and the agent-hooks self-test now exercises the session-start hook against the real clone: its corpus index needs origin/master as the baseline, and the equivalence case pins a master commit. On the shallow checkout the index reported "neither origin/master nor master resolves", the hook failed open to silence, and seven cases went red on macOS while the same suite passed on the Linux lane, which already fetches everything. Reproduced in a depth-1 clone locally; a plain fetch of origin/master into the same clone cleared it, so the lane's checkout depth is the term, not the userland. The chaos lane on the same head killed ChaosChurnStormIT with the ZOMBIE_MEMBER/REBALANCE_BLOCKED probe. This branch changes no Java and no pom, so the Java under test is master's at the merge base, which makes it a master-state firing of the known open arm. Recorded in the 857 family note with its seed and run, per the register's own rule that the rate is what is being measured. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Five findings from the code review, each with a test that went red before the fix and green after. The read-time divergence hook resolved the refs and the baseline once per path, so a Bash command naming four corpus files paid four ref listings and overran the 500 ms budget. The refs, the baseline and the branch name are now resolved once per tree and threaded into every drift call, the way the prompt-time matcher already did; the header records the re-measured four-path figure beside the single-path one, and a self-test counts the for-each-ref calls through the git shim. docs for-branch printed its baseline note through the caller's emit, so the session-start hook, which captures stdout, injected "master is on the baseline" into every session on master. The library now returns the note and prints nothing; the front door owns the stderr channel. The hooks self-test asserts the captured output on master has no such line. Issue-number terms were matched as substrings, so #41 hit #411 and #419. The per-line attribution now uses a digit boundary for terms shaped like an issue number, and a hit line naming no term cannot create a document entry. Two docblocks had drifted off the declarations they describe during the simplify pass; both sit above their subjects again. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…-context-query # Conflicts: # docs/inflight/test-untracked-ci-flakes.md
|
Review response - how each point was handled. "needs refactoring" (second review) - landed as
After that, the code review's five apply-eligible findings landed as "lgtm" (first review) - no action. Bot reports on the current head: both duplication engines report no new clones and no increased similarity from this PR. SpotBugs' count is master's - this branch changes no Java. Codecov's one failed test was the |
…ighting on the same PR The merged head's Integration Tests lane failed the same setup guard at the 30s ceiling, one failure in 201, probe clean, on a branch that still carries no Java. Counted in the row and dated in the paragraph; the push carrying this note is the lane's next measurement. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
|
@claude review this |
|
Claude finished @astubbs's task in 9m 40s —— View job Review
This is a large, carefully-built PR, and it already went through 8 review lenses with an apply/open triage in the body — most of what a fresh pass would find is already listed there. I traced two of those "Open" items against the actual code to confirm they're real (not just plausible), and one of them turns out to have a worse failure mode than described. No new correctness bugs beyond what's already disclosed. Confirmed: Confirmed and sharper:
So when a second Everything else checked out: Environment notes, not PR defects: my tool allowlist here is master's copy of the review workflow, so any grant this PR's |
The PR body listed six single-reviewer findings below the pipeline's apply bar; the requested review confirmed two against the code, and the author asked for all six. Each lands with a test observed red before its fix. Read-time header hook: a later path failing in the same event no longer drops earlier headers that were already marked seen, because the seen store is written once, for the blocks actually printed. A command that changes directory after its leading cd, or reaches another tree through git -C or GIT_DIR, now keeps only absolute path tokens, so the header never describes the wrong tree's copy. Corpus paths past the per-event cap are named in one trailing line with the command that checks each by hand. A shallow or never-fetched clone marks its summary UNRELIABLE with the remedy, in the hook and in the prompt-time matcher alike, since both would otherwise report divergence the clone cannot see. docs show: a repeated --ref is refused before any path resolution. The review traced that with the second flag ahead of the path, its value was taken as the document path and the real path silently dropped. The argument-validation branches of docs show, docs list and docs for-branch each have a test now. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
… the flake measurement Nothing in the note was both live and unowned: each delivery's measured cost lives in its hook header, the tree-batching shape in bin/lib/notes.mjs, the single-owner tag vocabulary in docs/inflight/AGENTS.md, and the one unpulled lever moves to docs/refactoring.md here. The plan's three citations of the note are repaired the way docs/citations.md prescribes: the address says where each item went and that a squash merge leaves the note only in the branch history. The flakes note records the outcome of the measurement its last paragraph promised: two green runs at normal length with nothing changed. Claude-Session: 85dcb374-ef1a-45d2-b7cd-ea904ff9d0a9 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…am-memory-leak Two commits, one conflict, and it is the flake ledger again - the third time this branch and master have both written to the same row, which is what a shared ledger looks like when it is being used rather than ignored. #419 raised `RegistrationRaceStaleResidentIT` from five sightings to six, naming #419's own two among them. This branch's version of the row carried something master's does not: a same-day cross-branch control, taken from recorded codecov history rather than by re-running builds, showing the identical `mid-loop pause point (offset 25)` signature on two unrelated branches within an hour while both passed at neighbouring commits. Resolved by keeping master's sighting record - it is strictly the better count - and grafting this branch's control into it, then re-appending the `AmbientProbeExtensionTest` row master does not have. Taking either side whole would have dropped either two sightings or the evidence that makes them mean something. `docs/inflight/AGENTS.md` and `docs/refactoring.md` auto-merged; both sides verified present afterwards rather than assumed, in both directions - master's additions and this branch's - because a prose loss in a merge fails no test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RVXBFaG4YXFP7Gjrj6pbVM
Inherited: #116's jstream result-stream fix (breaking, and it WITHDRAWS the queued JStream deprecation - `docs/refactoring.md` loses those entries here as a result, which is master's change and not this branch's), and #419's docs context query, which moves `bin/lib/inflight-tags.sh` to `.mjs` and rewrites the prior-art section of the root `AGENTS.md`. Neither touches the infer lane, the retry queue or the commit-timing path. One conflict, in `docs/inflight/test-untracked-ci-flakes.md`, on the registration-race row both sides had just edited. Resolved by keeping BOTH controls rather than either side's: - master's same-day CROSS-branch control (the same guard red on two unrelated branches within an hour, green at neighbouring commits on both), from #419; - this branch's WITHIN-branch control (the same content passing at `01fb0c4` and failing at `53ef4d6`), which is the stronger of the two because no cross-branch comparison can hold content fixed. The count is the union of the two sighting lists, and master's new `AmbientProbeExtensionTest` row is kept - it arrived in the same hunk and taking either side whole would have dropped it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C3KnLcX4KibVMCP6sMfNgM
… correct the record The previous commit filed `dups: clones` as a flake-ledger row saying the lane "tips over on a slow runner". A fourth attempt, on a fresh five minutes from a new head, failed identically, and the framing does not survive it. The row is retired and replaced with a note that says what the evidence actually supports. WHAT THE EVIDENCE SAYS Outcomes split cleanly by DATE, not by branch or runner: two attempts on 2026-09-03 succeeded and posted the full report; four on 2026-09-04 were cancelled. One of those four is on an unrelated PR, which is what rules out branch content - a second PR failing the same way at the same time cannot be explained by either branch's diff. The boundary is master gaining #419 and #116. Each cancelled attempt dies a few seconds past the five-minute cap with jscpd still running, named by the runner's own cleanup as an orphan process. The action runs PMD CPD and jscpd over the whole tree twice - PR and base - inside one five-minute budget, so corpus growth is paid four times. WHY THE FILING MATTERS AS MUCH AS THE DIAGNOSIS A deterministic breakage sitting in a flake ledger invites the response a flake deserves - re-run until green - which here would burn runner time and hide a required check that no longer works. It also is not the failure `ci-duplication-report-can-fail-to-post.md` already owns: that one is the lane FINDING a clone and failing to post it. A cancelled tick and a failed tick look alike in the checks list and mean opposite things. WHAT IT COSTS RIGHT NOW `dups: clones` is a required check, so while this holds no PR in the repository can merge. That is why the note is `impact: stall` rather than a CI-hygiene item, and why the fix belongs on master rather than on the feature branch that happened to find it. Master history cannot be used to attribute it: the job is `if: pull_request`, so on master it is `skipped`, which reads as green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C3KnLcX4KibVMCP6sMfNgM
Inherited #439, #445 and #442. The first and third matter to this branch: they fix the `dups: clones` lane that was blocking it, and they do so with a cause this branch got wrong. THE DUPS NOTE THIS BRANCH ADDED IS DELETED, NOT UPDATED `ci-dups-clones-lane-times-out-and-blocks-every-merge.md` described a problem #442 has fixed, so keeping it - even rewritten as a was-fixed narrative - is what `docs/inflight/AGENTS.md` forbids. Nothing in it survives as both true and unowned: master's workflow now carries the explanation at the point of use, and states it better. **Its causal claim was also wrong, which is the part worth recording.** The note attributed the timeout to corpus growth from #419 and #116, reasoning from a clean date boundary - every attempt on 2026-09-03 passed, every attempt on 2026-09-04 failed, corroborated on an unrelated PR. The mechanism was right (the job exceeding its five-minute cap with jscpd still running) and the attribution was not. The real cause, per #442's workflow comment: the action installed jscpd with `npx jscpd@4` inside the step it measures, so the base-branch engine paid a cold install the PR-branch step did not - 288s against 15s on the same tree - and npm's 300s default fetch-timeout let one stalled registry request consume the whole budget. The date boundary tracked registry conditions, not master's content. That is a reasoning failure worth naming rather than quietly dropping: a correlation across two branches felt like a controlled comparison, and it was not - both branches shared the runner and the registry, which is exactly the variable that moved. The control that would have settled it was re-running an OLD head, which this branch never did. THE FLAKE LEDGER'S REGISTRATION-RACE ROW, CONFLICTED AND UNIONED Both sides had grown it independently and neither is a superset. Master's version carries four #442 sightings - two of them on documentation-only heads - and counts a `ce-optimize` sighting where this branch counts #433; those are different runs, so the count is their union rather than either side's. This branch's WITHIN-branch control is restored, because master's row never had it and it is the strongest evidence in the row: the same tree produced both outcomes. Master's documentation-only heads are that same argument from the other direction, so they are kept beside it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C3KnLcX4KibVMCP6sMfNgM
Description
An agent working here should be told, without asking, when a document it is reading has a divergent
version on another branch, or when a mechanism it names has a write-up it cannot see from its own
branch. The motivating incident was the opposite: an agent found the right document on master, acted
on it, and the correction sat on a branch with nothing to say so.
This PR builds one context query in
bin/inflight.mjs- given a path being read, a set of words, ora branch, which documents across every ref matter, and which have diverged elsewhere - and three
agent-facing deliveries of its answer:
docs/file at read time, on both direct reads (a PostToolUse hookon Read and Bash) and tool output (
inflight docs show,inflight docs header). It names which ofthree states the copy at hand is in, what the newest divergent version adds, and the command that
shows it. Archival refs (tags, backup branches) are reported as preserved, not as divergence.
frontmatter, headings or body name an identifier the prompt used, marked when off master or
divergent elsewhere, silent when nothing matches, once per session per document. At session start
the branch's own facts follow: the documents naming this branch, its PR and its issues.
inflight docs:docsbare shows the corpus shape and the commands;docs list,docs show,docs header,docs index,docs for-branchbrowse it. Nothing interactive.The session-start title index now renders from the same query and is corpus-scoped: every document
under
docs/inflight/,docs/solutions/anddocs/plans/across every ref, with off-masterworkstreams grouped by the branch set carrying them, and the sections outside the corpus kept in
bash.
How it is built. Libraries under
bin/lib/never print or exit; they return{ok, ...}and thefront door owns the process boundary. "Found nothing" and "could not look" are different answers
with different exit codes. Hooks fail open. The tag vocabulary has one owner,
bin/lib/inflight-tags.mjs, and the bash gate evals its--shellrendering. Each delivery publishesits measured cold cost in its own header against the budgets in the plan. Every self-test is
negative-controlled with a mutant.
The plan, with the decisions and the alternatives they were chosen over, is
docs/plans/2026-09-03-001-feat-inflight-docs-context-query-plan.md. The working notepr-419-inflight-docs-context-query.mdwas retired at merge prep: nothing in itwas still both live and unowned, and the plan's citations of it say where each item went.
CONCEPTS.mdgains "Divergent version".Also on this branch, found by its own CI: the
shell: macoshygiene lane now fetches fullhistory, because the hooks self-test reads the real clone's refs and the shallow checkout made seven
cases go red on macOS only (reproduced locally in a depth-1 clone). A
ZOMBIE_MEMBERchaos firing ona head that changes no Java is recorded in the 857 family note as a master-state sighting.
Not in this PR: any human-facing UI, an MCP adapter (deferred, sketch recorded in the plan), the
GitHub tunnel and edge graph, the files-touched trigger, folding the existing write-time solutions
hook onto the query, and migrating the inflight-tag gate to Node.
Unapplied review findings
The code review ran with eight lenses. Five findings met the pipeline's apply bar and landed in
fix(review): apply review findings. These six came from a single reviewer each, below that bar;the first three were confirmed by the independent validation pass, the last three were not
validated. The author asked for all six after the requested review, and they landed together in
fix(review): apply the six findings left open for the author, each with a test observed red first.(Plain bullets on purpose: the PR Checklist gate reads every task box in the body as a template item.)
.claude/hooks/inject-docs-divergence.mjs- a non-leadingcd,pushd,git -CorGIT_DIR=in a Bash command makes the header describe the wrong tree's copy. Suggested: when thecommand carries a directory change that
leadingCddid not consume, keep only absolute pathtokens and drop relative ones; add the
(cd <wt> && cat <note>)case..claude/hooks/inject-docs-divergence.mjs- a later path failing marks earlier paths seenwithout showing them. Suggested: collect
{key, block}pairs and callstore.rememberonce, forthe blocks actually written; test with a second, unreadable path.
.claude/hooks/inject-docs-divergence.mjs- a shallow or never-fetched clone inflatesdivergence with no warning. Suggested: run the two cheap
freshnessWarningschecks in the summarypath and prefix the line with the invalidating warning, or stay silent and record why; same for
matchDocs; add a shallow-clone case tobin/test-check-docs-hooks.mjs.bin/lib/docs-commands.mjs-docs show --refgiven twice keeps the first silently, andthe requested review traced it sharper: when the second
--refprecedes the path token, its valueis taken as the document path, so the command reports the ref name as "outside the areas" and never
shows the document asked for. Suggested: the same repeated-flag guard
cvOptsuses, returningok: false.bin/lib/docs-commands.mjs- the argument-validation branches ofdocs show,docs listand
docs for-branchhave no tests. Suggested: oneinvoke()check per branch with apatch()mutant, beside the sibling validation checks in
bin/test-inflight.mjs..claude/hooks/inject-docs-divergence.mjs- corpus paths past the four-path cap are droppedwith no signal. Suggested: one trailing line naming how many were not checked and the
docs header <path>command for each.The requested review (comment of 2026-09-03) confirmed the second and fourth of these against the code and found no new correctness defects. Also noted and still not applied:
runFailingOpenin.claude/hooks/lib/hook-common.mjsstill callsprocess.exit(0)after writing stdout, the same truncation class the front door fixed withprocess.exitCode; hook output is far below the 64 KB pipe threshold today. The cross-modeladversarial peer timed out on this diff, so that lens ran in-process. Review run
20260903-152710-f6debb6d.Checklist
CONCEPTS.mdentry;docs/agent-harness.md,docs/inflight-tool.mdandAGENTS.mdper unitdocs/features/- N/A - agent tooling and harness, not a library featurebin/test-inflight.mjs,bin/test-check-docs-hooks.mjs,bin/test-check-agent-hooks.sh(including the pinned-baseline equivalence case),bin/test-check-inflight-tags.sh; all negative-controlleddocs/inflight/working note (pr-/branch-) started at the PR's first commit -pr-419-inflight-docs-context-query.md, retired at merge prep with its contents migratedce-simplifyandce-code-reviewlocally - simplify landed as the refactor commit; the review's applied and unapplied findings are above🤖 Generated with Claude Code