Imported from VION-IoT/dale-sdk (
.claude/skills/spec-pass/SKILL.md). Install upstream withnpx skills add VION-IoT/dale-sdk --skill spec-pass. Copyright stays with the author.
Area pass — extract, classify, implement
One pass turns one roster area (docs/spec-process.md § Corpus) into a
current-truth spec page with a fully rewritten, id-cited test suite — and leaves the area's code,
tests and page mutually consistent: defects the extraction finds are fixed in the pass, not
parked elsewhere. Two phases with a hard operator STOP between them. The brief that dispatched you
names: the area code, the scope as folders and projects (never a transcribed file list —
two passes running, the brief's file and descriptor counts were the thing that was wrong; count
them yourself and record a Drift checkpoint where the brief differs — and the test scope the
same way, as the test project's folders with the suites another page owns named by their
citations, never a list of files: the brief that listed suites missed three in the area's own
project), the anchor kinds
(attributes, descriptor ranges, schema, manifest — you enumerate the instances; an anchor kind that
turns out empty, such as an attribute with no named parameters, is a Drift checkpoint, not a row),
the RFCs to absorb (often none), the spec page path, and the attempt number. Decisions
in the brief and in docs/spec-process.md are binding; contradictions go to the change doc's Drift
checkpoints, never silent divergence.
Work on branch spec-pass/<code-lower>-a<N> (N = attempt). Attempts are disposable by design: if
the operator discards this attempt, the branch dies and the skill gets fixed — never hand-fix a
discarded attempt's output.
Phase A — extract the behavior table
Produces the pass's change doc, proposed, carrying the table. No production edits, no test
edits, no fixes, no Jira writes in this phase — reading and one document only.
-
Branch, then scaffold:
pwsh scripts/spec-change.ps1 new <code-lower>-pass -Areas <CODE>. Fill Summary (what this pass covers) and Spec implications (the page it will create). -
Anchor inventory first. Enumerate the area's machine-readable surface mechanically — grep the attributes, descriptors, schema fields, manifest entries the brief's anchor kinds name — and list the inventory in the change doc. This list is the completeness checklist for the sweeps; a sweep without it starts from a blank page and misses silently. For every attribute in the inventory, compare its
AttributeTargetswith the targets its readers actually walk: a target nothing reads is a row (one pass found that shape twice — a method target and a property target that compiled, emitted nothing and warned about nothing). -
Statement sweep. Walk the scope statement-by-statement (not branch-by-branch —
docs/testing-conventions.md§9's observability discriminator decides what is a row). Every claim comes from code read this session; old RFC prose and comments are hints at best. -
Consumer sweep. The statement sweep finds what the code does; it misses what a consumer depends on. Walk every in-repo consumer of the area and then read the area once more as the author of a plugin/library/topology would: what does the layout of my input have to be; who owns an instance and what follows (dependency resolution, lifetime, identity); what happens when one of my files is broken (tolerated, aborted, what state is left); which mechanics of a marker/attribute/contract does my declaration have to satisfy. Each answer is a row. A Tier C example is a consumer to read, not a test bed: it references a published package, so it cannot prove a same-PR SDK fix.
-
Edge-value sweep. For every knob, token or input the area accepts — durations, thresholds, names, paths, versions — walk the edge values and write a row for what each observably does: negative, zero, empty, whitespace, non-finite (
NaN, infinity), out of range or overflow, an equivalent spelling ("250"vs"250ms", case, culture), a value the compile-time validator accepts that the runtime then ignores or inverts. The pass that skipped this sweep had six of its ten critic misses here. -
State-interaction sweep. Where the area is a multi-step decision (a gate, a resolution chain, a lifecycle), take each decision path once more while another state is pending: a drop while a value is held, a stop while a flush is armed, a reset while a run is active. Each combination whose outcome differs from the naive reading is a row — these are the rows that leave a consumer stale forever and never show in a statement walk. A behaviour stated for one side of a symmetric mechanism — the publish side of a wire, one handler family, one direction of a value rule — is a prompt to read the other side: both of one pass's critic misses sat beside a row the pass had stated for the other side of the same mechanism (a topic pinned on the publish side, stated, and the receive side that reads it live, not; a contract message ignored by the input handler, stated, and by the output handler, not). Where an initialization can fail closed (a refused configuration, a binder that throws), walk every later message the instance can still receive — a stop, a snapshot, a restore, a write, a second configuration — and write a row wherever the answer differs from a healthy instance's: four of one pass's nine critic misses were exactly these.
-
The table is the deliverable — one row per observable behavior, all six columns required:
# Behavior (EARS) Evidence Test today Rec Why 1 WHEN a plugin binds to an assembly marked [DaleSharedAssembly]THE SYSTEM SHALL resolve the shared instance.PluginLoadContext.cs:340PluginLoadContextShould.…intended the cross-plugin type-identity contract - Behavior — written for the spec page, so in published-surface vocabulary only:
public types and members, attribute names, exception types, file/wire formats. No private
method names, no
file:line, no mechanism words a refactor would falsify. The altitude test is could a consumer observe the difference? — a sentence an implementation change would force you to reword is at the wrong altitude. - Evidence —
file:line, read, not recalled. This column is where implementation detail lives; it dies with the archived doc. A probe is evidence only for the shape it ran: when a claim rests on a scratch probe, the row records the probe's fixture shape (the declaration as written —get;is notget; init;) and the surface it read (the definition view is not the live view) beside the result. A probe over a different shape or surface than the row names is a guess wearing evidence's clothes; one pass wrote off a correct reading on such a probe and paid three amendments for it. - Test today — the existing test proving it, or
GAP. - Rec — your recommendation, one of four:
intended(→ spec) ·fix(a defect, small and area-local → AC worded for the correct behavior, fixed in Phase B) ·park(a defect too big or too far-reaching for this pass → one line indocs/specs/_findings.md) ·out-of-spec(implementation shape, not contract). One-line Why each. A row that names a harm names the consumer that suffers it byfile:line, or it is a guess wearing evidence's clothes. Aparkrec that rests on a member's history — added last, newer than its siblings — has no evidence column: recency is not a reason to treat a member differently (an operator overruled one such park; the fix was four lines and retired two special cases). Where the brief pre-classifies a class of rows as propose-and-wait — a wire shape, a public member's semantics — a fifth valueproposecarries the recommendation on the row: implemented as afixif the operator accepts it, written to the ledger as aparkif not, so that neitherfix(fixed on the session's judgment) norpark(not fixed at all) misstates the row (one pass minted it for 21 rows; it was the right reading of its brief). - A
fix/park/proposerec is flagged⚠and gets a two-line failure sketch under the table; aproposesketch ends with the recommendation.
- Behavior — written for the spec page, so in published-surface vocabulary only:
public types and members, attribute names, exception types, file/wire formats. No private
method names, no
-
Map every existing test in scope to a row; tests mapping to no row go in an unmapped tests list (Phase B merge/delete candidates).
-
Self-check against the anchor inventory and the PublicApi manifest's entries for the area's assemblies (where the area has any — some are
[InternalApi]by design): every member visited or explicitly out-of-scope. State the counts. Visited by a row is not covered by a criterion: in Phase B this self-check is re-read so that every classifiedintended/fixrow maps to a criterion id or to a checkpoint that says why not, and every hole in the id sequence has a checkpoint naming the id (spec-tracerefuses a hole no archived change doc names) — one pass claimed two fields covered that no criterion stated. The self-check also asks the reverse question per anchor instance: which observable behaviours have neither a row nor a criterion? Counting rows against criteria never asks it, and two behaviours reached a page that way (a lifecycle entry point, and the one silent success the pass had left). Ask it of the doc's own Reviewer's questions as well: a question that describes an observable and recommends its disposition is an observable someone noticed and nobody tabled — one pass's question 7 described a refusal on a false premise, recommendedfix, numbered it after an unrelated row, and no row carried it until the classification asked. -
Commit the change doc (status stays
proposed), push the branch, and STOP with exactly this report shape: row/GAP/⚠/unmapped counts · the ⚠ rows verbatim · the unmapped-test list · the line "Classify: reply with row numbers to override, or 'accept recs' to take all recommendations."
The operator gate
The operator classifies (the coordinator may add a second opinion on ⚠ rows). No Jira is filed by
default: fix rows are fixed in Phase B, park rows go to the ledger, and Jira is for the rare
finding the operator actively schedules. Do not proceed to Phase B without the classification.
Phase B — implement the classified table
-
Flip the doc
in-flight. Mint idsAC-<CODE>-NNN.M(umbrella per behavior cluster, leaves per criterion) and author the Spec-delta lines targeting the brief's page path. Minting is a consolidation. Extraction and specification want different granularities: the sweeps over-produce rows on purpose, and the page states one criterion per rule, with the fields, tokens or sites the rule ranges over as the[DataRow]s of its test — never one criterion per field. A family of schema mirrors folds into the rule they mirror; a doc-comment defect row is a fix without a criterion; a row another page owns is cited there, never re-minted. Aim for roughly half the classified rows as criteria, and record a consolidation map (row → criterion, or row → the line saying why it mints nothing) in the change doc, so no classified row vanishes silently — the critic checks it, and a row with neither is a blocker (230 rows became 135 criteria without losing one). Aparkrow appears in the map by name with the line saying why it mints nothing, and is never folded into a criterion: one pass's REPORT listed its parks off the map and lost the one the map had folded, so its ledger line was written a round late. A criterion you already know no test can reach carries itsGAP: <reason>marker on the delta line —spec-tracehonours it there exactly as on a page. A criterion's text on the page and on its delta line are one text: reword one, reword the other in the same commit (aMODIFIEDline for a criterion already delta'd asADDED) —spec-change.ps1 archiverefuses a delta whose text the page no longer carries, and one pass reworded a criterion on the page with no delta line at all, so page and delta disagreed until review. An id hole that opens before the page is published — a leaf dropped for want of a reachable mutation, in the pass's own PR — is closed by renumbering the leaves below it and their citations in one pass over the page and the tests; after publication a hole is named in the change doc and never renumbered, because a consumer may cite the id. -
Write the mutation with the test, before the AC counts. For every AC: the test, the one mutation of the code under it that reddens that test and no other claim, run and observed. A test that pins an ordering, a bound or an edge value runs its own mutation once before it is cited — one pass's flush-ordering test survived its mutation until the fix-up round, because the put-back landed in a queue the snapshot had just emptied, where inserting at the head and appending coincide; a test that survives its mutation pins nothing. An AC no mutation can redden is not a requirement — reword it to what is observable, merge it into the AC it converges on, or drop it; never mint it. An AC that two guards enforce is over-determined: say so on its line, mutate both, and keep it — the binary rule has no other verdict for it. A mutation that survives is a hypothesis about the test as much as about the mutation: when another mechanism produces the same observable — a stop's drain republished the value the hook wrote, so a test about the started flag read green with the flag already down — remove that mechanism from the fixture (a controllable clock turns the emission policy off) rather than strengthen the mutation. The PR body carries the
test → mutationlist, one line each (§11). A mutation that survives because no seam constructs the window it needs — a race between two adjacent statements on one thread and a pool continuation — is reported as surviving, with the observable that is carried stated beside it (one pass's drain race had no deterministic window: the fix is the order, the carried observable that a queued request is dropped, never run); an amendment item that owes a test for a race names the observable it expects, so the session can report an absence instead of manufacturing a proxy. Two rules about claims ride on this step: a test cites a criterion for what the criterion's text states, not for the behavior the test happens to prove (spec-tracechecks that an id exists, not what it says; three tests in one pass cited criteria that said something else — read the criterion against the assertion before citing it; and because the gate un-GAPs an id the moment any test carries it, a criterion no test in the suite can reach isGAPhowever many tests name it — one about a CI-only gate read as proven on two option-description tests); and any claim that names a test as its guarantee — in a comment, a doc, a checkpoint — is read from that test's call sites, not its name (a test that feeds one of two parsers pins one parser, whatever it is called). An instruction to cite — in an amendment, in a brief — is not evidence the citation fits: re-read the assertion before adding the tag (an amendment once named the wrong test for a criterion and the session cited it unread). A behaviour that holds by accident of structure — two dictionaries that happen to be separate — has no reachable mutation until it is one line that states the rule: write that line, then mint. Two assertion shapes read green on exactly the case they exist to exclude: a substring test on a rendered number (Contains("0 s")holds on"60 s"— assert the field whole,testing-conventions.md§11) and a wall-clock bound standing in for a claim about behaviour where a virtual-clock delta or the branch's own effect is observable (§16; one pass wrote three and replaced all three). A test that pins an implementation premise rather than a criterion (two parsers agreeing on every vector) stays uncited by design, says so in its class summary, and is listed in the REPORT —docs/spec-process.mdnames the category; never mint a criterion to hang it on. -
Fix rows: the test for the correct behavior, proven red against the pre-fix code (that red run is the defect proof — name it in the list), then the minimal fix. Disciplines a fix owes beyond its own lines: a fix that makes previously inert inputs live re-checks every validator over those inputs (the pass that unblocked measuring-point knobs left all six analyzers blind to them); a fix that names a defect shape sweeps the shape, not the symbol (grep for the expression, not the one call site you noticed); a guard added to a
switchbelongs to every arm — route every arm through one guard, or the arm you did not test skips it; a fix that says match rule R enumerates R's properties — membership, naming, each declaration level — and covers every one in the same round (one pass matched membership, then property naming, then class-level naming: three rounds for one rule). A test's fixture carries the observable its assertion needs: a block with no service members cannot show "the interface did not bind" through the service map — find the seam or the fixture that shows it before minting the test, and know that a generated seam can exist on one half of a contract only (the sender side, not the sink side), so a fixture on the quiet half tests the guard and not the path. Size guard: if a fix turns out non-local or design-bearing while you implement it, STOP and report — it becomes aparkrow or its own change doc, never a silent absorption. A deviation from the classification's letter is checkpointed with the criterion it rests on and the test that carries that criterion — a reason is not a proof: one session deviated because a synchronous observe would block teardown, and the criterion that reason rested on had six citations and no test constructing the case. A fix closes one path and opens its sibling for the sweep: before the REPORT, re-run the state-interaction and edge-value sweeps over every fixed path's neighbours — the restart beside the double start, the duplicate reference beside the duplicate answer, the second map beside the first; three of one pass's four critic misses sat exactly there, on paths the extraction had swept before the fixes existed, and another pass's one miss was the offset three freshly guarded slices read from, never checked against the topic's prefix — an edge value beside the edges just fixed. A behaviour the classification adds is a path the extraction never swept: sweep it as a fix's sibling before the REPORT — its other output mode, its options, its JSON document — because three of one pass's six critic misses sat on the annotate path the classification had just added, where the create path beside it had been swept and the new one had not. A pass that creates test projects sweeps them with the mirror diff it runs over the packages: four articles one pass mirrored from its digital test files into its new analog ones were invisible to a checkpoint that diffed only the two shipped packages — the residue class the checkpoint existed for, in files the same pass had just written. Hedges are STOPs: a brief that says appears to … — verify has named an assumption; when it fails, record the deviation in the change doc and ask, never improvise a different design in its place (one pass improvised "resolve by evaluating" when the promised AST was not there; evaluation short-circuits, so the check never reached the name it existed to find — resolution is a syntactic question, answered from a parse tree). -
Author the spec page: current-truth prose + the AC declarations, frontmatter
trace: enforced. Prose states rules, never rosters (a list of today's instances drifts; "grep-enumerable" does not). Rows the operator accepted without a test carry theGAP: <reason or VION-nn>marker on the declaring line — and if the reason is "no observable", the row isout-of-spec, notGAP. The marker binds only on the id's own line: keep a declaring bullet's id and itsGAPtail on one line, becausespec-tracereads the marker from the line that declares the id, and a wrapped bullet fails the gate with no hint why.spec-tracealso reads any acceptance id on a line without aGAPmarker as a declaration: cite a neighbour's GAP'd id by family (AC-ANLZ-018.*, never in full) and refer to your own GAP'd criteria by description in the prose below the bullet, never by number — four of one page's eleven GAPs were un-GAP'd by their own explanatory prose on the first run. -
Rewrite the area's whole test suite to
docs/testing-conventions.md§9–17 — ids cited via the quoted-literal forms (§17), unmapped tests merged or deleted per their list, no assertion on log calls (§15). A[DataRow]merge is a rewrite of the assertion: re-derive the mutation after it, or the merge is a deletion (one dropped a criterion's own sentence). A scripted fixture edit asserts its match count, or it can be applied, reported and absent. Names and Triple-A markers are gated, not remembered:pwsh scripts/test-style-lint.ps1fails on any cited test with an article in its name or no markers (§12/§13) — run it before the REPORT and budget the rename round (it caught fourteen names in one pass that the session wrote after reading §12; the natural phrasing of an assertion carries an article). The round also invalidates every test name the change doc carries — the behavior table's Test column, the unmapped list, the mutation list: after it, resolve everyClass.Methodtoken in the doc — and the shorthand`.Method`continuation form, whose class is carried from the token before it — against a declaration with a script, paste both counts, and rewrite the stale cells from the declarations (a per-class declaration list before and after the round is what works; matching bodies by similarity does not on a rewritten suite — 104 stale names survived two rounds that way, and four more survived a resolver that read only the full form). §17's "no other string" includes an expectation array: read the ids off the artifact under test, never write them as literals in aCollectionAssert. A project you cite from without owning (another area's registry) is on the script's exempt list with its reason until that area's pass; one citation never exempts a project, and a file this pass authors in an exempt project conforms anyway — run the lint once with the exemption removed locally, fix what it lists, commit nothing of the exemption change. A fixture inserted above an attribute block steals the doc comment above the anchor (the new declaration gets two<summary>blocks, the old one none):scripts/doc-comment-lint.ps1fails the double; re-read the insertion point for the bare half. A test deleted because "another gate already covers this" names the gate and its failure mode in the commit — a snapshot that is regenerated and auto-committed gates nothing, and a warning-level diagnostic fails no build. -
If the brief lists RFCs to absorb: delete them and run the reference sweep (
docs/spec-process.md§ Area passes, step 5). If it lists none, say so in the report. Sweep discipline: a scripted sweep deletes only the spans it matched and proves each rewritten line is the original minus exactly those spans (assert the match count, diff the rest); it reads and writes bytes with the file's own line endings (newline=''); and it applies no whole-file tidy-up after the edit — two sweeps in one pass reset the tree, one by stripping every empty()in the repo, the other by rewriting every CRLF file to LF.scripts/sweep-residue-lint.ps1names the shapes a sweep leaves behind (an orphaned(), a doubled space, a Markdown line ending on(); run it, then re-read every touched sentence anyway, because a regex sweep cannot see the sentence it leaves without a subject, the bare§pointing at a deleted file, or the stub a reflow left mid-paragraph. A filegrepcalls binary is skipped by every sweep — check withgrep -a/grep -cbefore trusting a zero. Vendored files (their header says so) are exempt from the sweep; a cross-reference in a still-living RFC is re-pointed with one line, not absorbed. -
If the area reaches the DevHost SPA (
Vion.Dale.DevHost.Web/wwwroot): the change is demonstrated, not reasoned —devhost-smokeTier 2 on a live host, evidence in the change doc — and if no committed fixture can show it, grow the SmokeHost with the member that can (docs/devhost-conventions.md§ 1,testing-conventions.md§ 6). A Tier 2 row is a paste — the page text or a described screenshot the browser tool returned — never a sentence composed from what the code should do. One pass recorded an observation that could not have occurred, because the export that produces the string was imported by nothing; the row read as evidence for a whole round. The observation is made through the UI's own controls — click the option, type in the box — never a scripted DOM write: a value set from a script reaches the DOM and not the model, and the verdict read back is about the row that was still there; open the raw view and read the model back before believing it (docs/devhost-conventions.md§ 1). -
Gates, all of them, results verbatim in the report — every line a paste from the terminal, including the ones whose numbers did not move; a number carried from an earlier run is stale by default and a composed one is the same defect (three recurrences in one pass):
dotnet build(zeroDALEwarnings in the SDK's own build — a deliberately illegal fixture gets#pragma warning disablewith its reason) +dotnet teston the full solution,scripts/spec-lint.ps1,scripts/spec-trace.ps1,scripts/test-style-lint.ps1,scripts/doc-comment-lint.ps1,scripts/bom-lint.ps1,scripts/journal-lint.ps1,scripts/sweep-residue-lint.ps1,scripts/run-script-tests.ps1,/cleanuponce — and a run under CI's shape where a fixture asserts a build-time literal (dotnet test <project> -p:Version=0.0.0-ci.1: CI passesVersionas a global property, and a project's own<Version>loses to it). A suite that gained a real-clock interaction — a runner loop, a captured console, a background host — runs five times in a row, every result line pasted; a pasted run count is still not a proof against load (one passed three runs and failed the reviewer's first), so the race is fixed, never outrun. Stryker.NET is optional: run it only where the test project references a single mutatable project (it cannot run otherwise — MTP runner in preview, multi-reference crash), read survivors by hand, never a gate or a score. -
Distill every delta line into the page, then
pwsh scripts/spec-change.ps1 archive <code-lower>-pass— it refuses a delta line whose id or text the page does not carry. The archive commit is the last commit that touches the page or the delta. A fix that lands after it — a sibling sweep's late find — carries its criterion, its delta line and its map row in the same commit and re-runs the gate against a slug-renamed copy placed back underdocs/changes/(the archived file cannot be archived twice without doubling its relative links), or it waits for the fix-up round; one pass shipped a consumer-visible refusal in its last commit with none of the three, and the review found it by readinggit show --statof the head against the doc's own claim of a "second half". -
Commit per task, push, and STOP with the REPORT. Its mandatory preamble is the self-check, in writing — the coordinator's checks read it first:
- every gate line in the REPORT and the scorecard is pasted from the terminal, never typed;
- for every test added or changed, the cited criterion's text was read against the assertion — list the pairs;
- every sentence in the change doc that a later checkpoint disproved has been corrected in place or annotated;
- every Tier 2 row is a pasted observation;
- every number and tense in the sections above the append was re-read, and every count is
pasted with the command that produced it — re-reading a number one wrote is not counting it
(an amendment appends to the change doc and nothing else re-reads what stands above it: a
37for a 33-method file and a future-tense plan survived two rounds that way; 106 criteria against 105 on the page and 466 cited tests against 452 were recounted by a reviewer with one grep each); - every
OUTCOMEline under the doc's Reviewer's questions carries its outcome — a(pending classification)that survived Phase B is a placeholder above the append that nothing re-read (seven survived a pass, its archive, two checks and a fresh round); - the change doc carries a
## Relay notes for the PR bodysection naming every consumer-visible change the pass landed, written as each landed — the PR body quotes that section verbatim and nothing else; one pass reached its close-out with the notes in two REPORTs and none in the doc, and the coordinator had to compose them.
Then: commands run + results · the test → mutation list · GAP list · premise tests left uncited, with reasons · park rows written to the ledger · friction one-liners (journal candidates,
docs/process-journal.mdformat) · no PR yet — the coordinator runs the completeness critic and/vion-code-reviewfirst; the PR opens on the operator's go.
After the REPORT — the coordinator's checks
Two fresh-context Opus subagents (docs/spec-process.md § Dispatching): a completeness critic and
an adversarial review of the branch diff, both reading every cited criterion's text against its
test. Findings return as one numbered amendment, and the amendment is worked by a fresh session:
the session that wrote Phase B retires at its REPORT, and the amend file is the fresh session's
brief (the fix-up shape — item, artifact, proof — with the same self-check preamble). Four passes
in a row showed the Phase B session producing amendment items done wrongly, with checkpoints that
did not read true — context depth degrades exactly the disciplines an amendment asks for — and each
needed a further fresh round; retiring at the REPORT costs one session's ramp-up and saves that
round. The coordinator closes the round with targeted reads of every item at its call site, and a
further Opus check runs only when a targeted read finds a blocker. A message reaches you only
when both sessions run in bypass mode; the amend file is the artifact and the message a
notification, and the coordinator reads delivery off your transcript (docs/spec-process.md
§ Checks and amendments) — the classification relay of Phase A arrives that way; an amendment
arrives as a brief.
The coordinator's second opinion on the ⚠ rows, taken before the classification, reads the
readers and not only the call sites: where a Why cell names a reader whose repository is on
the machine — the private runtime, the gateways, the first consumer — the subagent opens it,
because a reader named from memory is a hypothesis about someone else's code. One pass's second
opinion found five reader claims wrong and three of them changed a row's class: a runtime with no
arm at all for the message type the row said it dispatched, a marker the row called unread that
the runtime's scan reads, and a helper the row would route a discovery through that the runtime
rejects in its own comments. The test for a propose row is unchanged — a silent wrong outcome
made visible; no consumer depending on today; small and area-local — but its second clause is now
answered by reading, and a wire change whose every reader was read and found not to read the
field is a fix with a relay note, not a park.
The brief that dispatches a pass is built the same way: an inventory subagent's counts are hypotheses until a second fresh-context subagent reads them against the code — one inventory said thirty-nine analyzers, three hundred and eighty-eight tests and the severities transposed, and the check corrected eighteen claims before the brief went out. The two checks after the REPORT run after the session's own sibling sweep and never instead of it: the sweep finds the neighbour the fixer thinks of, and one pass's five critic misses all sat on neighbours the sweep had visited and not seen. And a REPORT's numbers are read against the head they were taken at — a carried count does not announce itself as stale, it announces itself as an interesting difference, and one round went into explaining a CI-versus-plain gap of three tests that was three tests added in the last commit.
An amendment's premise is a hypothesis until the tree confirms it: a check reading a branch at one commit gets the shape right and the constants wrong (an "empty schedule" that was the framework's 60 s periodic event; a "CRLF file" that was LF). Verify the mechanism at the call site before implementing, annotate a refuted premise in the checkpoint, and still test the behaviour the item names when it is real — both refuted items of one round were worth doing. An item with two clauses owes two proofs: do both and paste each, because the half without a number is the half that gets skipped ("the mutation list and the test map" — the map stayed stale for a round).
Scorecard (coordinator fills, into the change doc before the PR merges)
| Measure | Value |
|---|---|
| Gates (build/test/lint/trace/style/doc-comment/bom/self-tests/cleanup/CI) | green / what failed |
| Completeness-critic misses | count + rows added, by the sweep that should have caught them |
| Evidence errors found in review | count |
| Mutation evidence | named-mutation list complete? · over-determined criteria stated? |
| Operator corrections (table + PR) | count |
| Cost | sessions × model · amendments · wall time |
Non-negotiables
| Temptation | Reality |
|---|---|
| "Fix it in Jira later" | A pass leaves code, tests and page consistent. Small and area-local → fix now; otherwise park in the ledger. Jira only when the operator schedules it. |
| "This fix is growing, I'll finish it anyway" | The size guard exists for exactly this: STOP, report, park. A "bug" that is really a feature band never rides a pass. |
| "This row is obvious, skip the evidence" | Unevidenced prose is this repo's most repeated defect class (journal, D10). Every row cites file:line; every harm names its consumer. |
| "The probe came back green, so my reading was wrong" | A probe is evidence for the shape it ran. Record the fixture shape and the surface; re-probe on the row's own shape before writing a reading off. |
| "The AC reads well, I'll find its mutation later" | An AC without a reddening mutation describes the code instead of constraining it. Mutation first, or it is not minted. |
| "The test proves this, so the id fits" | A citation is for the criterion's text. Read it against the assertion; if it says something else, reword the criterion (with its MODIFIED line) or cite the right one. |
| "I fixed the site I found" | Sweep the shape, re-check the validators the fix just made relevant, route every switch arm through the guard, cover every property of the rule. The site you found is the one the critic will not need to. |
| "The brief said verify — it didn't hold, so I'll do it another way" | A failed hedge is a STOP. Record the deviation, propose, wait. |
| "Another gate already covers this test" | Name the gate and its failure mode. Two passes deleted a test on that sentence and had to restore it. |
| "I'll write the Tier 2 row from the code" | A Tier 2 row is a paste. No paste, no row. |
| "The numbers didn't change, I'll carry them" | Paste every gate line, every time. |
| "The amendment told me to cite it" | A citation is read from the assertion, whoever asked for it. |
| "I merged the rows, the mutation is the same" | A merge rewrites the assertion; re-derive the mutation. |
| "Patch the discarded attempt's table by hand" | The next pass repays the same debt. Fix the skill, delete the branch, rerun. |
| "Enshrine it — the code clearly does this" | The code doing it is evidence of behavior, not intent. Surprising rows get fix/park or the operator's explicit intended. |
| "It was added last, so it is special" | Recency is not a reason to treat a member differently. A park rec argued from a member's history has no evidence column; classify it by its shape. |
| "One criterion per row keeps the map simple" | Extraction over-produces on purpose; the page states one criterion per rule with the fields as [DataRow]s, and the consolidation map is what keeps the rows. |
| "The sweep is done; a tidy-up regex will polish the rest" | A sweep deletes matched spans and nothing else. Two tidy-ups reset a tree. Run sweep-residue-lint, then read every touched sentence. |
"I set the input's value from the script and read valid" |
A scripted write reaches the DOM, not the model. Click the control; read the model back. |
| "The amendment says the schedule is empty" | A check's finding is a hypothesis. Verify the mechanism at the call site, annotate a refuted premise, test the real behaviour. |
| "I'll work the amendment myself, I know this code" | The session that wrote Phase B retires at its REPORT; a fresh one works the amendment. Four passes paid a round each for the alternative. |
| "Every row maps to a criterion, so the page is complete" | Ask the reverse per anchor: which observables have neither a row nor a criterion. Two reached a page that way. |
| "The OUTCOME lines can wait for the operator" | A placeholder above the append is a number nothing re-reads. Fill it at the classification or name it in the REPORT; seven survived every reader once. |
| "I fixed the path the row named" | Its sibling path is where the next miss sits. Re-run the state-interaction and edge-value sweeps over every fix's neighbours before the REPORT. |
| "The question already names the row" | A reviewer's question that describes an observable is a row until the table carries it. Ask the reverse question of the doc's own questions; one pass's question 7 had no row. |
| "The reader is the runtime, which I cannot open" | Where the reader's repository is on the machine, the second opinion opens it. Five reader claims fell that way in one pass, three flipping a row's class. |
| "The relay notes are in my REPORT" | The PR body quotes the change doc's ## Relay notes for the PR body, not the REPORT. Write the section as each change lands; one pass reached close-out with none in the doc. |
| "The inventory says thirty-nine" | An inventory's count is a hypothesis; a second reader counts again before the brief dispatches. Eighteen claims fell that way once. |
| "Every local run passed" | One machine is one culture and one OS. A number a diagnostic renders is formatted invariantly and a test that pins it expects the invariant text; CI found the one test of 455 every local run had passed. |
| "The archive gate ran at T-008" | The archive commit is the last touch on the page or the delta. A fix after it re-runs the gate and carries its criterion, delta line and map row, or waits for the fix-up round. |
| "I re-read every number" | Re-reading a number one wrote is not counting it. Every count is pasted with its command; a reviewer recounted two with one grep each. |
| "I deviated for a good reason" | A deviation is checkpointed with the criterion it rests on and the test that carries it. One rested on a criterion six tests cited and none proved. |
| "The race is fixed — I'll write the test that shows the window" | A window no seam constructs has no deterministic test. Report the surviving mutation and the observable that is carried. |
| "The map folds the park into a criterion" | A park is a row the map carries by name and no criterion covers. A folded park is a lost ledger line. |
| "It's new, so nothing broke" | A behaviour the classification adds has never been swept. Sweep it as a fix's sibling before the REPORT. |
| "Two tests cite it, so it is proven" | The trace gate cannot tell a citation from a proof. A criterion the suite cannot reach is GAP however many tests name it. |
| "The other side is the same mechanism" | A behaviour stated for one side of a symmetric mechanism is a prompt to read the other. Both of one pass's critic misses sat beside a row stated for the other side. |
| "The mirror diff was clean" | The mirror diff covers the files the pass created too. Four mirrored articles in a pass's own new test files were invisible to a diff of the shipped packages. |
| "The test pins the ordering" | A test that pins an ordering, a bound or an edge runs its own mutation once before it is cited. One survived its mutation for a round: the window it pinned was empty. |
| "The csproj says so" | What a build system decides is read from its evaluation, not from a regex over its inputs. A roster proof was blind to MSBuild's packable default; a parallelisation claim read csprojs the test framework's props override. |