Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
ff055df
chore(agents): measured review and test strategy — mutation by tool, …
V3RON Oct 19, 2026
33e94bf
refactor(agents): split the new scripts' long functions so Fallow's c…
V3RON Oct 19, 2026
ee4075e
fix(agents): recurring-findings searches and opens issues over REST, …
V3RON Oct 19, 2026
bba301a
fix(agents): keep the hand probes beside pnpm mutate, which missed ev…
V3RON Oct 19, 2026
83b6d87
feat(agents): build one test at a time — a build mode replaces red an…
V3RON Oct 19, 2026
ff51b1f
fix(agents): a build cycle writes only the code its test needs, one t…
V3RON Oct 19, 2026
f993a55
docs(agents): measured test rules — no new test for as-today behaviou…
V3RON Oct 19, 2026
b3b0dcd
docs(agents): worktree.sh names the build stage
V3RON Oct 19, 2026
1a325a6
revert(agents): mutation testing leaves delivery — probes and pnpm mu…
V3RON Oct 19, 2026
d771ca6
docs(agents): build mode describes the tracer bullet, lets a test com…
V3RON Oct 19, 2026
0b02180
docs(agents): a green cycle writes general logic and no placeholder f…
V3RON Oct 19, 2026
57cac9f
docs(agents): the audit probes each claim in a test's title and swaps…
V3RON Oct 19, 2026
7bfb519
feat(agents): a script checks that a contract shape change and a prot…
V3RON Oct 19, 2026
0511865
docs(agents): point at a value's source instead of copying it; a late…
V3RON Oct 19, 2026
a60694e
chore(hooks): the push hook's e2e typecheck builds only the daemon's …
V3RON Oct 19, 2026
d406c47
Merge origin/main into chore/review-strategy
V3RON Oct 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions .agents/briefs/implement-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,32 @@ when and assumptions; retain earlier evidence for unaffected claims.
under `open`. Never tick a box on intent.

**Check every test you added or changed**, including setup or assertions
edited after the red commit:
edited after its `test:` commit:

- Its title, assertions and fixture state make the same claim. A title with
two claims has an assertion for each. Walk testing rule 10's list against
it.
- It proves a claim no other test proves, through the module's surface
(testing rules 6 and 7). One that repeats another test's claim is folded
into that test.
- Break the code it covers once (flip the condition, drop the filter, return
early) and run its file: it fails on the assertion its title names.
Restore the code. A test that stays green is vacuous: fix it. Every
test, no skipping: a probe the audit skips, a reviewer does on a far
costlier model. Report `probed <p>/<t>` on the `audit:` line: `t` tests
added or changed, `p` probed.
into that test. One that imports a module's internal file instead of its
`index.ts` has the `why:` reason rule 6 asks for, or moves to the
surface, even when `index.ts` exports the same name.
- Break the code it covers once per claim in its title (flip the
condition, drop the filter, delete the call, move the constant either
way, return early, or swap a rule for a near one: sort by another key,
drop the tie-break, take the first instead of the lowest, drop one side
of an `||` or `&&`) and run its file: it fails on the assertion its
title names, not by timing out. Apply each break so that one which
does not match fails loudly (a Python `str.replace` with an assert that
the text was found, not `sed -i`): a break that never applied proves
nothing. Restore the code. A test that stays green
is vacuous: fix it. Every test, no skipping: a probe the audit skips, a
reviewer does on a far costlier model. Report `probed <p>/<t>` on the
`audit:` line: `t` tests added or changed, `p` probed.
- A test comparing two outputs also asserts one of them against a literal.

Run the "Project checks" in `toolchain.md` that the diff triggers. Then the
tests from mode `green` pass, and you push.
tests from mode `build` pass, and you push.

**A failing test you did not touch**, locally or in a failed CI run
(`gh run view <id> --log-failed`):
Expand Down
81 changes: 81 additions & 0 deletions .agents/briefs/implement-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Mode `build`: one test, then the code it needs

Build the issue one Tests line at a time (a bug's triage test already
exists: its line is the first cycle's, with step 1 done).

**Tracer bullet first.** The first cycle takes the line whose test crosses
the most of the path the issue builds, from its seam to its outermost
effect: the CLI command through the daemon to the stored record, not the
parser alone. Its green builds every layer on that path, each only as thick
as this one test needs: one case, no options, no error path. It proves the
layers connect before any of them grows, so a wrong seam or a missing wire
shows in cycle one, not in the last. Each next cycle takes the line next to
code already built and widens it by one case, field or error path, using
what the earlier cycles showed. Never build a layer ahead of the test that
reaches it, and never write the tests in bulk first: tests written before
the code check an imagined shape.

For each line, one cycle:

1. **Red.** Write the one test the line asks for at the seam it names, or
extend the existing test it names (testing rule 7). A line that lists
cases is one test, its cases a table in its body. Its title is the line's
claim, word for word where it fits. Read it against testing rules 6, 8
and 10. The commit hook typechecks the whole project, so a test that
calls code not yet written cannot commit: add only the stub it calls,
its real signature returning the type's emptiest value (`[]`, `0`,
`undefined`, or doing nothing), never the logic. Run its file: it fails
on a named assertion, for the reason the line gives, not on a typo, a
thrown stub or a timeout (testing rule 2). Commit the test and its
stubs, one test per commit: `git commit -m "test: <the line's claim>
(#<N>)"`. A test that passes before you change code either proves
behaviour the repo had before this issue (delete it when an existing
test proves the line, else keep it and list the line under `open` as
`already green: <line>`), or code an earlier cycle built ahead of its
test: keep it and list the line as `built ahead: <line>`.
2. **Green.** Write only the code this test needs to pass: no branch,
case, field or error path that a later Tests line asks for, even when
you can see it coming. What you write is the general logic the spec
describes, never a value or branch that matches only the test's input;
a field the type needs but no Tests line asserts is computed from
state, never a placeholder (`ready: 0`). Run the files of every earlier cycle's test:
they stay green. Commit: `<type>(<scope>): <what now works> (#<N>)`.

Never write the next test before this one is green, and never refactor
between cycles: the last cycle's push runs Fallow's duplication and
complexity checks on everything the cycles added, and you fix what they
flag then. Changing an earlier
cycle's test to make this one pass is a `spec needs` stop (above).

After the first cycle, push and open the draft PR:

```bash
LEFTHOOK_EXCLUDE=fallow git push -u origin <kind>/<N>
gh pr create --draft --base <base, or main> --title "<type>(<scope>): <summary>" --body-file <scratch>/pr-<N>.md
```

The push skips Fallow alone until the last cycle: stubs and code a later
cycle wires in are dead code until then. The last cycle's push runs every hook. With a
`base` argument (a task stacked on its feature's last reviewed PR), the PR
targets that branch. The PR body, in this order: `Closes #<N>`; a
`### Status` section the orchestrator keeps current; the Done when lines
as an unchecked list; `## Assumptions` ("none", or one `- Assumption:` line
per gap); the line `*Written by an agent.*`. Keep it current as you go.

- Run only the commands under "Tests agents run" in `toolchain.md`. Never
run a check listed under "Checks agents never run", nor a tool behind
it, from any path. A type or lint error shows in the commit hook's
output.
- The commit hook rejects a comment that does not start with `why:`
(architecture rule 17). Delete it; start it with `why:` only when it says
why the code does something a reader would not expect.
- Never wait on CI. Run `node .agents/scripts/ci-failures.mjs <M>` at most
once, before the report: `none` is `ci: pass`, a failed test `ci: fail`.
- Never use `git stash`: all worktrees share one stash list. Commit instead.
Temporary files go in your scratchpad, not `/tmp`.
- Build what `always-in-scope.md` lists as you go. Anything else you notice
outside the spec becomes a `bug:new` issue or one line under `open`.

Stop after about ten cycles, or sooner when your context grows long: push,
and list the Tests lines not yet built under `remaining`, in order. A fresh
agent goes on from the branch.
3 changes: 2 additions & 1 deletion .agents/briefs/implement-fix.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ mechanical. Inputs include immutable `base`, `merge-base`, `previous` and
mode and order, including both at once) and check each.
2. **Fix every instance:**
- behaviour: make a test fail first, then fix. Extend the test that
proves the behaviour next to it; write a new one only when none does
proves the behaviour next to it; write a new one only when none does,
and list it under `fixes` with the test you could not extend and why
(testing rule 9);
- a broken rule (`[architecture N]`, `[safety N]`, ...): change the code
so it keeps the rule, never the doc that states the rule;
Expand Down
23 changes: 0 additions & 23 deletions .agents/briefs/implement-green.md

This file was deleted.

29 changes: 0 additions & 29 deletions .agents/briefs/implement-red.md

This file was deleted.

9 changes: 6 additions & 3 deletions .agents/briefs/review-claims.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ Whether a comment may exist at all is the commit hook's (rule 17 in

A claim is false when the code at this commit contradicts it: a name or
path that no longer exists, a behaviour, order, owner, default or limit that
changed. Blocking: a false claim. Note: a claim that is true but misleading.
changed. Blocking: a false claim. A claim that is true but misleading is
no finding.

## Assessment

Expand All @@ -44,8 +45,10 @@ already supported remain valid; identify unresolved coverage separately.

`F0` is a good result: do not look for findings to have some. Output only
your list, then your findings: no preamble, no headings, no summary, no
narration. Report every blocking finding; there is no limit. At most five
notes; write no other note. One line per defect, in this form and no other:
narration, at most 400 words besides the list. Report every blocking
finding; there is no limit. Write a note only for a suspected leak of a
secret or a credential that you could not prove: at most two. One line per
defect, in this form and no other:

```
F<n> B|N <path:line> <the claim and what the code does instead, at most 25 words> [architecture 13] ev: <path:line, ...>
Expand Down
29 changes: 16 additions & 13 deletions .agents/briefs/review-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ the code.
In the inputs directory: the specification (`issue.md`, `feature.md`,
`triage.md` and `spec/`, those that exist), so you know what the code is
meant to do; `rules/`, every rule file but `delivery.md`, and the ADR index;
`diff.patch`; `briefs/calibration.md`, when it exists, findings like yours that
were rejected lately: read it first. Repository: the worktree you were
given, checked out at the reviewed commit.
`diff.patch`; `briefs/calibration.md`, when it exists, findings like yours that were
rejected lately: read it first. Repository: the worktree you were given,
checked out at the reviewed commit.

A conflict between the specification and a rule is a finding of class
`spec vs rule`; never resolve it silently. A defect on a line the diff does
Expand Down Expand Up @@ -43,7 +43,7 @@ Then answer, for each of them:

Blocking: the change breaks behaviour, leaves wrong state, or breaches a
rule or an accepted ADR; a user or a later change pays for it. When unsure,
ask "what breaks, and for whom?"; no answer means note.
ask "what breaks, and for whom?"; no answer means drop it.

## Lens: tests and rules (`lens: tests` or `both`)

Expand All @@ -56,8 +56,8 @@ Then answer:
1. For each test: can it fail for the reason its title gives? Read it
against testing rule 10's list first; those shapes need no probe to
prove. Spend your probes on the tests most likely to be wired to
nothing: break the code the title names and see whether the test goes
red on an assertion. A test that stays green is a finding.
nothing: delete a call, move a constant to its edge, loosen what the
test compares. A test that stays green is a finding.
2. Does the diff break any rule in `rules/`? Cite the file and the rule
number.

Expand All @@ -75,16 +75,19 @@ already supported remain valid; identify unresolved coverage separately.

A finding is blocking only when it shows wrong behaviour or state, a false
statement, a rule or ADR breach, or a line of the specification left
undelivered or unproven. Testing rules and always-in-scope coverage apply
even when the spec omits a case. Extra coverage beyond those requirements,
a stronger assertion than its claim needs, or defensive code is a note.
undelivered or unproven. A missing test is a finding only for behaviour a
caller, user, stored record or event can see that the spec, the user docs
or testing rule 3 requires, or for a defect this review found (testing
rule 9). A case that cannot happen, another case of a claim a test already
proves, a stronger assertion than its claim needs, or defensive code is no
finding.
`F0` is a good result: do not look for findings to have some.

Output only your lists, then your findings: no preamble, no headings, no
summary, no narration. Report every blocking finding; there is no limit.
At most five notes, each a possible wrong behaviour or state you could not
prove within your probes; write no other note. One line per defect, in
this form and no other:
summary, no narration, at most 400 words besides the lists. Report every
blocking finding; there is no limit. Write a note only for a suspected
leak of a secret or a credential, or loss of user data, that you could not
prove: at most two. One line per defect, in this form and no other:

```
F<n> B|N <path:line> <the defect, at most 25 words> [<class>] ev: <path:line, ...> | <command> => <the output line that shows it>
Expand Down
31 changes: 20 additions & 11 deletions .agents/briefs/review-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Apply the precedence and scope in `review-protocol.md` in the inputs.

Specification: `issue.md`, `feature.md`, `triage.md` and `spec/`, those
that exist. Diff: `diff.patch`. Tests after red: `tests-after-red.patch`,
every change made to the specification's tests after they were first
committed failing. Assumptions: `assumptions.md`, each line a small gap the
every change made to a test file after a `test:` commit first wrote it
failing, but the next cycle's added test. Assumptions: `assumptions.md`, each line a small gap the
specification left open, closed by the implementer. `spec/always-in-scope.md`
lists what every change includes without its specification asking; treat
each item as asked for. `briefs/calibration.md`, when it exists, lists findings
Expand All @@ -23,16 +23,21 @@ delivered`, or `Done when 3: differently: <how, at most 15 words>`.
2. Does the diff do anything the specification did not ask for? Anything
`always-in-scope.md` lists is asked for: never a finding.
3. For every Tests line of the specification: the test in the diff that
proves it, by `file:line`, or `missing`. For every change in Tests after
proves it, by `file:line`, or `missing`. A line proven by more than one
new test, or a new test no Tests line asks for and no failure-mode or
always-in-scope item needs, is a finding [testing 7]. For every change in Tests after
red that deletes a test or removes or loosens an assertion: which line of
the specification is no longer proven? Whether a test's body proves its
title is the code review's question, not yours.
title, or can fail at all, is the code review's question, not yours; so
is a defect in behaviour the specification does not name (a missing
bound, a race). Do not report them.
4. For each assumption: is it the conservative choice, and consistent with
the specification? One that contradicts a line of it, or decides
behaviour a user would see that nobody decided, is blocking.

Blocking: a line not delivered or delivered differently, a Tests line with
no test, a line of the specification left unproven, an
no test or with several, a new test nothing asks for, a line of the
specification left unproven, an
assumption that fails question 4, behaviour a user sees that the
specification did not ask for, or a breach of a file in `spec/`.

Expand All @@ -53,15 +58,19 @@ already supported remain valid; identify unresolved coverage separately.

A finding is blocking only when it shows wrong behaviour or state, a false
statement, a rule or ADR breach, or a line of the specification left
undelivered or unproven. Testing rules and always-in-scope coverage apply
even when the spec omits a case. Extra coverage beyond those requirements,
a stronger assertion than its claim needs, or defensive code is a note.
undelivered or unproven. A missing test is a finding only for behaviour a
caller, user, stored record or event can see that the spec, the user docs
or testing rule 3 requires, or for a defect this review found (testing
rule 9). A case that cannot happen, another case of a claim a test already
proves, a stronger assertion than its claim needs, or defensive code is no
finding.
`F0` is a good result: do not look for findings to have some.

Output only your list, then your findings: no preamble, no headings, no
summary, no narration. Report every blocking finding; there is no limit.
At most five notes, each a possible wrong behaviour or state; write no
other note. One line per defect, in this form and no other:
summary, no narration, at most 400 words besides the list. Report every
blocking finding; there is no limit. Write a note only for a suspected
leak of a secret or a credential, or loss of user data, that you could not
prove: at most two. One line per defect, in this form and no other:

```
F<n> B|N <path:line> <the defect, at most 25 words> [<class>] ev: <path:line, ...>
Expand Down
4 changes: 2 additions & 2 deletions .agents/scripts/delivery-stats.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ function reviewOf(body) {
rounds: roundsOf(body, section),
tokens: tokensOf(section),
rejected: rejectedIn(section),
measured: /^Review checks: (\d+)\. Invocations: (\d+)\. Cost USD: ([\d.]+|unknown)\./m.exec(
measured: /^Runs: (\d+)\. Cost USD: ([\d.]+|unknown)\. Agent seconds: (\d+|unknown)\./m.exec(
section,
),
};
Expand Down Expand Up @@ -279,7 +279,7 @@ function report({ now, prs, handoffs, needsHardware }, weekCount) {
"",
"## Measured review work (unknown means unavailable; legacy totals remain above)",
"",
"| PR | Checks including fix-check | Invocations | Cost USD |",
"| PR | Agent runs | Cost USD | Agent seconds |",
"| --- | --: | --: | --: |",
...prs
.filter((pr) => inRows(pr, now))
Expand Down
Loading
Loading