Five from the backlog: the tool says where its own answers come from - #38
Merged
Conversation
One theme, five cards, and three of them had a premise that did not survive being
run.
T-0160 — `--root` took the directory as given and checked nothing, so
`doctor --root packages/workfile` reported six issues, exited 0, and indexed that
package's docs as the workspace's. The marker check `cwd` always had now applies
to an explicit root too, strictly rather than as a walk: `--root` is an assertion
by the caller and resolving it upward would be a second surprise. `--allow-new`
is the way through, and it reaches that branch now — it only ever reached the
path that already refused one, which is how this gap existed at all.
T-0218 — every doctor finding carries the reporter that produced it. The card
said every module returns `{ module, issues }`; only the integration registry
does, so stamping `report.module` produced `undefined` on 1396 of 1397 findings
in a real workspace. The module is named where `runDoctor` calls each reporter,
which is the only place that knows. `code` is untouched on purpose: namespacing
it would read better and would stale every accepted baseline at once, so a test
fails if `issueIdentity` grows the field.
T-0223 — the stale-filename rule was cards-only, and memory records, managed
documents and unreleased fragments derive their names from their titles
identically. Written once now, in the layer that holds every kind — the same
argument `duplicate-record-id` already makes there — and `doctor --fix` repairs
all four. On Fube it finds 53 findings that were invisible. What it will not
touch is stated where the rule is: an indexed README is not ours to rename, a
released fragment is history, a release is named after its version. It caught my
own hand-rename of LRN-0033 one commit after I made it.
T-0219 — a claim board entry carries the session behind its claim, so the guard
stops having to recover one from an actor's tail that an explicit `--actor` does
not have. Two agents sharing one prompt now. Building the board before writing
the session file made a session ask about its own card, which the existing
one-separation-rule test caught; the signal is written first. That test was also
modelling the claim as sessionless and agreeing by coincidence, so it now compares
the rule the guard actually applies.
T-0147 — reproduced before being fixed, as the card insisted: with the ceiling
lowered, `project_agent_context` returned `truncated: {"records":1}` where its own
schema declares a boolean. The transport's marker is `resultTruncated` now,
declared in every tool's schema rather than merely allowed.
Two strict-ratchet improvements fell out rather than regressions: 488 → 474,
from typing `runDoctor`'s reports array and narrowing two test files' rejection
callbacks properly instead of annotating them `any`.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
CodeQL reported `js/polynomial-redos` as high against `routeRoots` in `docs/validation.ts`, and it is right: `replace(/\/+$/, "")` retries the anchored `+` from every start position, so a value of N slashes costs O(N²). The alert landed on `main` this morning with T-0217 and blocked a pull request that has nothing to do with it. The spelling was written five times across the package and once more in the hook. Only the `routeRoots` one was reported, because it is the one whose taint CodeQL can follow from a declared value — so fixing that one alone would have left five copies of the same shape and the next report to whichever of them grows an input first. `stripTrailingSlashes` in `core/glob.ts` is a linear loop and all five go through it; the hook keeps its own copy, since it imports nothing from the package, and the scope it strips comes off a card that can arrive from a fork. T-0224 records what this does not do: nothing stops the sixth copy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five backlog cards with one theme: the tool saying where its own answers come from. Three of them had a premise that did not survive being run, and those corrections are on the cards.
T-0160 —
--rootanswered from a directory that was not a workspacedoctor --root packages/workfilereported six issues, exited 0, and indexed that package'sdocs/as the workspace's documents. The failure is silent and plausible: a mistyped or stale--rootone directory too deep produces a clean, empty, believable answer, and nothing distinguishes it from a board that is genuinely empty.The marker check the discovery path always had now applies to an explicit root — strictly, not as a walk, because
--rootis an assertion by the caller and resolving it upward would be a second surprise rather than a fix.--allow-newis the way through, and it reaches that branch now: it only ever reached the path that already refused one, which is how this existed at all.T-0218 — a finding never said which module produced it
Every finding carries its reporter now, and the CLI groups by
module/code, sointegration:<id>/<code>is unmistakable — which is the one case that matters, since a diagnostic returned by a repository's ownhealthCheckis the only source that is not ours.The card's premise was wrong. It says every module returns
{ module, issues }; only the integration registry does. Stampingreport.moduleproducedundefinedon 1396 of 1397 findings in a real workspace — caught by running it against one. The module is named whererunDoctorcalls each reporter, which is the only place that knows which one it is calling.codeis untouched deliberately: namespacing it would read better and would make every baseline accepted with--accept-baselinestale at once. A test fails ifissueIdentitygrows the field.T-0223 — only cards noticed a retitled record's filename
Memory records, managed documents and unreleased changelog fragments derive their filenames from their titles identically and had neither the rule nor the repair. Written once now, in the layer that holds every kind — the same argument
duplicate-record-idalready makes two functions away — anddoctor --fixrepairs all four kinds off the index rather than through four loaders.On Fube it finds 53 findings that were invisible (35 docs, 18 memory). What it will not touch is stated where the rule is: an indexed README is not ours to rename, a released fragment is published history — and the protocol already refuses to retitle one, which I checked rather than assumed — and a release is named after its version.
It then caught my own hand-rename of LRN-0033, one commit after I made it: I wrote
a-cards-findingand the slugifier producesa-card-s-finding. Fixed by the tool, which is the canonical derivation.The four per-kind length caps stay different (50/60/70/70) and a test pins that. Unifying them would rename every existing record whose title crosses the new bound, in one sweep, on the next
--fix.T-0219 — two agents sharing an
--actorlooked like one processA board entry carries the session behind its claim, so the guard stops having to recover one from an actor's tail that an explicit
--actordoes not have. Driven through the real hook, four cases: the holding session stays silent, two agents with different sessions and one actor now prompt, two session-free terminals with one actor stay silent because unproven is not a verdict, and different actors prompt.Two things the existing tests caught on the way. Building the board before writing the session file made a session ask about its own card — the exact failure the guard exists not to have. And the one-separation-rule test was modelling the claim as sessionless, so it agreed with the guard by coincidence on the one case where the board had learned something the model had not; it now compares the rule the guard actually applies.
The hot path gained one string operation and no I/O; the relative latency budget test passes.
T-0147 — the byte ceiling overwrote a tool's own flag
Reproduced before being fixed, as the card insisted. With the ceiling lowered,
project_agent_contextreturnedtruncated: {"records":1}where its ownoutputSchemadeclares a boolean. The transport's marker isresultTruncatednow — declared in every tool's schema rather than merely allowed, so a caller reads it from the schema instead of meeting it the first time a payload gets large.Not a regression
The strict ratchet went 488 → 474, from typing
runDoctor's reports array and narrowing two test files' rejection callbacks properly rather than annotating themany, which is what the ratchet's own message asks for.pnpm run checkgreen — 484 + 10 tests.doctor0 errors 0 warnings,memory verifyandchangelog verifyclean. Every guard in here is mutation-proven; the details are on each card.🤖 Generated with Claude Code
https://claude.ai/code/session_01D3LTdq3mzMAQ98rwBegGjU