Merge pull request #175 from fiddlerwoaroof/docs/wave-agent-rules
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
CI / Build all bundles (push) Has been cancelled
CI / Test and lint (host) (push) Has been cancelled
CI / wasm32 check (browser bundle crates) (push) Has been cancelled
CI / Browser JS unit tests (node --test) (push) Has been cancelled
CI / Knowledge base consistency (push) Has been cancelled
CI / Lint the harness crate (push) Has been cancelled
CI / Browser harness (OPFS contract + shell) (push) Has been cancelled
CI / Deploy to GitHub Pages (push) Has been cancelled
wave skill: agent standing rules move into the repo; one home for the brief checklist (improvise-1f8e)
This commit is contained in:
@@ -7,6 +7,8 @@ description: Dispatch parallel agents to work through open beads and shepherd ea
|
|||||||
|
|
||||||
An orchestrator chunks the open backlog, fans agents out, reviews what comes
|
An orchestrator chunks the open backlog, fans agents out, reviews what comes
|
||||||
back, and merges. `AGENTS.md` has the history; this is the operating procedure.
|
back, and merges. `AGENTS.md` has the history; this is the operating procedure.
|
||||||
|
This file is the brief checklist's one home, and `agent-rules.md` beside it
|
||||||
|
holds the rules each agent follows.
|
||||||
|
|
||||||
## Every agent gets its own worktree. No exceptions.
|
## Every agent gets its own worktree. No exceptions.
|
||||||
|
|
||||||
@@ -17,9 +19,8 @@ here. If you discover it mid-wave, stop every agent, have each create a worktree
|
|||||||
and copy across **only files it can prove it touched**, then `git checkout --`
|
and copy across **only files it can prove it touched**, then `git checkout --`
|
||||||
those files in the primary tree.
|
those files in the primary tree.
|
||||||
|
|
||||||
In the worktree: `direnv allow`, or `bd` reports a version *mismatch* rather than
|
In the worktree `.envrc` must be allowed, or `bd` fails confusingly:
|
||||||
failing cleanly. `direnv status` prints `Found RC allowed 0`, and `0` means
|
`agent-rules.md`, "Discipline per ticket".
|
||||||
allowed — it reads like the opposite.
|
|
||||||
|
|
||||||
## Partitioning
|
## Partitioning
|
||||||
|
|
||||||
@@ -33,32 +34,41 @@ it must cross. Two agents adding a workspace member will still collide in
|
|||||||
|
|
||||||
## What every brief must carry
|
## What every brief must carry
|
||||||
|
|
||||||
|
**Point the agent at [`agent-rules.md`](agent-rules.md) and tell it to read it in
|
||||||
|
full first.** That file is the agent's standing rules: base and push mechanics,
|
||||||
|
the gate list, the claim, the vacuity shapes, evidence, the files it must not
|
||||||
|
write, GitHub conventions, the hand-back and disk cleanup. Do not restate them
|
||||||
|
in the brief. A restated rule drifts from its source, and the brief is the copy
|
||||||
|
nobody corrects. The brief adds only what varies per wave:
|
||||||
|
|
||||||
1. **The expected base commit, by name.** Worktrees do not reliably branch from
|
1. **The expected base commit, by name.** Worktrees do not reliably branch from
|
||||||
HEAD — one was created three merges behind and only noticed because it was
|
HEAD. One was created three merges behind and was only noticed because it
|
||||||
told to check.
|
was told to check. The agent checks against it: `agent-rules.md` rule 1.
|
||||||
2. **The baseline**, so "N passing" is checkable rather than asserted: Rust test
|
2. **A reference baseline**, so "N passing" is checkable and a drop is
|
||||||
count, harness counts, node counts.
|
visible: Rust test count, harness counts, node counts, **and the machine**.
|
||||||
3. **Its ground, and the ground that is not.**
|
The same commit once measured `improvise-io`'s binary at 1.4s on one machine
|
||||||
4. **Never write** `.beads/**`, `prolog-sessions/kb.pl`, `context/repo-map.md`.
|
and 3.7–5.2s on another, so a figure with no machine is a claim about the
|
||||||
Agents read them freely and report proposed text; the orchestrator applies it.
|
suite, which it is not. The agent still measures its own.
|
||||||
5. **The commit trailers and PR footer**, spelled out.
|
3. **Its ground, and the ground that is not.** Name any orchestrator-only file
|
||||||
6. **Do not push to `main`, do not merge.** The orchestrator merges.
|
it is exceptionally allowed to edit.
|
||||||
7. **What to report**: branch and head SHA, PR number, what changed per ticket,
|
4. **Its `BEADS_ACTOR` and its tickets.**
|
||||||
*what could not be verified and why*, proposed repo-map/kb text, and **what it
|
5. **The attribution line, commit trailers and PR footer**, spelled out.
|
||||||
learned that the ticket did not predict** — consistently the most valuable
|
They name the agent (Claude's line opens `_Posted by Claude (<model>)…_`)
|
||||||
part, and omitted unless asked for explicitly.
|
and this session's URL, which is why the shared `agent-rules.md` cannot
|
||||||
|
hold them.
|
||||||
|
6. **An explicit ask for what the ticket did not predict.** `agent-rules.md`
|
||||||
|
lists it in the hand-back. Say it in the brief anyway: it is consistently
|
||||||
|
the most valuable part of a hand-back, and agents omit it unless asked.
|
||||||
|
|
||||||
## Method to require, because this repo's defect is a test that passes
|
When a hand-back teaches a new rule, add it to `agent-rules.md` in the same
|
||||||
|
wave, not to the next brief.
|
||||||
|
|
||||||
- Failing test first, then the fix.
|
## Method to require
|
||||||
- Every guard proved by **injecting the fault it names** and watching it fail
|
|
||||||
**by name**. An injection that does not compile reads as a clean run, so
|
`agent-rules.md`, "Discipline per ticket" and "Gates": failing test first, a
|
||||||
require a positive signal the build ran.
|
rival injected and watched failing by name, `--no-fail-fast`, and test *names*
|
||||||
- `cargo test --workspace` is **fail-fast**; `--no-fail-fast` for any claim about
|
diffed after any merge. Hold the hand-back to it. This repo's characteristic
|
||||||
blast radius.
|
defect is a test that passes.
|
||||||
- A textually clean merge can **delete tests** with no conflict marker, and
|
|
||||||
`cargo check` will not notice. After any merge that moves a test module, diff
|
|
||||||
test **names** — a count is masked by the other side's additions.
|
|
||||||
|
|
||||||
## Shepherding
|
## Shepherding
|
||||||
|
|
||||||
@@ -72,7 +82,9 @@ it must cross. Two agents adding a workspace member will still collide in
|
|||||||
commit reads as a pass.
|
commit reads as a pass.
|
||||||
- Merge on GitHub, then `git fetch gh && git merge --ff-only gh/main`.
|
- Merge on GitHub, then `git fetch gh && git merge --ff-only gh/main`.
|
||||||
- Anything posted to GitHub goes out under the owner's account: open every
|
- Anything posted to GitHub goes out under the owner's account: open every
|
||||||
comment with a line saying a Codex agent wrote it.
|
comment with a line naming the model and saying an agent wrote it. That
|
||||||
|
wording is agent-neutral because this one file serves Claude and Codex
|
||||||
|
(`.claude/skills/wave` is a symlink to `.agents/skills/wave`).
|
||||||
|
|
||||||
## Between waves
|
## Between waves
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,198 @@
|
|||||||
|
# Standing rules for a wave agent
|
||||||
|
|
||||||
|
Every work-unit agent reads this **in full before its first command**. A brief
|
||||||
|
points here and adds only what is specific to its wave: the expected base
|
||||||
|
commit, the agent's ground, its `BEADS_ACTOR`, and its tickets. Every rule below
|
||||||
|
was bought by a failure.
|
||||||
|
|
||||||
|
This file holds each agent-side rule **once**. The brief checklist is
|
||||||
|
`SKILL.md` beside it. Where `AGENTS.md` ("The Wave Workflow") carries a longer
|
||||||
|
history, the rule here points there. Change a rule here, not in a brief, and
|
||||||
|
not in a second copy.
|
||||||
|
|
||||||
|
## Base, branch, push
|
||||||
|
|
||||||
|
1. **Verify your base against the commit your brief names, first.** Run
|
||||||
|
`git log --oneline -1` and compare. Worktrees do not reliably branch from
|
||||||
|
the orchestrator's HEAD: one was created three merges behind, and it was
|
||||||
|
only noticed because the agent was told to look.
|
||||||
|
2. **Branch from `gh/main`, never `main` or `origin/main`.** `git fetch gh &&
|
||||||
|
git checkout -b <branch> gh/main`. A worktree handed to you may already sit
|
||||||
|
on unpushed commits. Why: `AGENTS.md`, "Shipping a wave" (the two remotes
|
||||||
|
both spelled `main`, and the worktree-base vector).
|
||||||
|
3. **Before opening a PR, check `git diff --numstat gh/main...<branch>`.** Do
|
||||||
|
not use `gh pr view --json files`: that is the union of your commits' files,
|
||||||
|
not the effective diff.
|
||||||
|
4. **Push with an explicit refspec:** `git push gh HEAD:refs/heads/<branch>`. A
|
||||||
|
branch cut from `gh/main` tracks `gh/main`, so a bare push targets `main` and
|
||||||
|
is refused.
|
||||||
|
5. **Before pushing a fix to an existing PR, check `gh pr view <n> --json
|
||||||
|
state`.** GitHub deletes a merged PR's branch. A push to it then prints
|
||||||
|
`* [new branch]` and lands nowhere. Why: `AGENTS.md`, "Shipping a wave".
|
||||||
|
6. **The "Session Completion" block near the end of `AGENTS.md` does not apply
|
||||||
|
to you.** It says `git merge origin/main` and then a bare `git push`. On a
|
||||||
|
wave branch the first is the #145 trap and the second is refused (rule 4).
|
||||||
|
Rules 1–5 replace it. The block sits between bd's generated
|
||||||
|
`BEGIN/END BEADS INTEGRATION` markers, so it is not edited by hand
|
||||||
|
(improvise-x1uk).
|
||||||
|
|
||||||
|
## Commit early: a worktree is not durable storage
|
||||||
|
|
||||||
|
Commit a WIP as soon as your first test run is green, and again after every
|
||||||
|
meaningful step. Push your branch (rule 4) once it is worth keeping. An agent
|
||||||
|
finished a whole ticket with every gate green and lost all of it, uncommitted,
|
||||||
|
when its worktree was deleted in a disk cleanup. A local commit survives a
|
||||||
|
deleted worktree. Tidying history before the PR is fine; losing it is not.
|
||||||
|
|
||||||
|
## Gates
|
||||||
|
|
||||||
|
```
|
||||||
|
direnv exec . cargo test --workspace --no-fail-fast
|
||||||
|
direnv exec . cargo clippy --workspace --all-targets -- -D warnings
|
||||||
|
direnv exec . ./scripts/fmt-workspaces.sh # NOT cargo fmt --all; exit 2 = the gate did not run
|
||||||
|
direnv exec . python3 scripts/check-comment-runs.py --check-evidence
|
||||||
|
direnv exec . ./scripts/checkers.sh
|
||||||
|
direnv exec . ./scripts/node-test.sh 'web/tests/*.test.js'
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Never `cargo fmt --all`.** It reaches only **one** of this repo's two
|
||||||
|
workspace roots, because `harness/opfs-contract` declares its own
|
||||||
|
`[workspace]`. The obvious repair is worse: `cargo fmt -p opfs-contract` from
|
||||||
|
the repo root exits **1**, *"not a member of the workspace"*, which looks
|
||||||
|
exactly like a real formatting failure (improvise-b4ks). Both spellings fail
|
||||||
|
in the direction that looks like success.
|
||||||
|
- **Run every gate under `direnv exec .`.** `./scripts/checkers.sh` scrubs the
|
||||||
|
environment to an allowlist, so a bare run drops `tpl` off `PATH` and reports
|
||||||
|
spurious failures.
|
||||||
|
- **Never pipe a gate.** `$?` must be the gate's own. And
|
||||||
|
`check-comment-runs.py --check-evidence` prints two lines with the comment
|
||||||
|
cap **first**, so `| tail -1` silently drops half of it.
|
||||||
|
- **`--no-fail-fast`**, because plain `cargo test --workspace` stops at the
|
||||||
|
first failing binary. Use it for any claim about blast radius.
|
||||||
|
- If you touch a browser-bundle crate (core, formula, io, protocol, command,
|
||||||
|
wasm-client, worker-server), also run
|
||||||
|
`cargo check --target wasm32-unknown-unknown -p <crate>` **for each crate**.
|
||||||
|
CI checks each one separately, so feature unification cannot hide a leak.
|
||||||
|
- If you touch `web/` or `harness/`, run the Playwright suite in `harness/`.
|
||||||
|
- **Measure your own baseline** before changing anything, and report it with
|
||||||
|
the machine it was measured on. A figure from the brief is a reference, not
|
||||||
|
your baseline.
|
||||||
|
- **Merge `gh/main` and re-run every gate before calling a PR green.** Then
|
||||||
|
check that no test *disappeared*. Diff test **names**, not counts: a
|
||||||
|
textually clean merge can delete a test module with no conflict marker, and
|
||||||
|
the other side's new tests mask the loss in a count.
|
||||||
|
- **The shell guard refusing a compound command means NEITHER part ran.** Split
|
||||||
|
the command. After a refusal, re-check the state it was meant to produce.
|
||||||
|
- **Re-run the full suite after reverting an injected fault.** A revert applied
|
||||||
|
to the wrong occurrence once shipped two faults past every other gate.
|
||||||
|
|
||||||
|
## Discipline per ticket
|
||||||
|
|
||||||
|
- **Claim first:** `export BEADS_ACTOR=<your actor>` in every shell, then
|
||||||
|
`bd update <id> --claim`. Exit 13 means another actor holds it. Pick another;
|
||||||
|
do not retry.
|
||||||
|
- **`bd` needs `.envrc` allowed in your worktree.** Without it you get a
|
||||||
|
**version mismatch**, not a clean failure. Run `direnv allow` in the worktree,
|
||||||
|
or rely on the `[whitelist] prefix` in `~/.config/direnv/direnv.toml`.
|
||||||
|
`direnv status` reports `Found RC allowed 0`, and `0` means **allowed** (the
|
||||||
|
enum is 0=Allowed, 1=NotAllowed). It reads like the opposite.
|
||||||
|
- **Reproduce at HEAD before fixing.** A dozen tickets were stale-open in one
|
||||||
|
campaign, one fixed two days before it was filed. If it does not reproduce,
|
||||||
|
find the fixing commit, confirm with `git merge-base --is-ancestor <sha> HEAD`,
|
||||||
|
report the SHA, and close nothing.
|
||||||
|
- **Write a failing test first, then inject a rival and watch it fail.** Run
|
||||||
|
it; do not reason about it. Report *where* it failed, by case name. An
|
||||||
|
injection that does not compile reads as a clean run, so get a positive
|
||||||
|
signal that the build ran.
|
||||||
|
- **Check your test against every vacuity shape seen here:**
|
||||||
|
- an assertion the default state already satisfies;
|
||||||
|
- `f(x) == f(x)`: calling a pure `Cmd` twice against one immutable context;
|
||||||
|
- a disjunctive assertion whose other branch is the bug's own symptom;
|
||||||
|
- a rival that fails the *setup*, which proves the neighbouring question
|
||||||
|
(e.g. setup and subject share an `EffectKind`);
|
||||||
|
- a fixture that is right by accident (expected value 1, group at row 0,
|
||||||
|
bystander already on the relayed value);
|
||||||
|
- a fixture or stub that lacks the structure the hazard needs, or fails in a
|
||||||
|
wider shape than the real fault;
|
||||||
|
- hand-picked fixture cases where the set could be **enumerated**: four
|
||||||
|
vacuities in `fmt-workspaces-test.sh` were each a case nobody thought of
|
||||||
|
(improvise-90ea);
|
||||||
|
- a rendered-output test at a width where the thing asserted is never drawn;
|
||||||
|
- a fold test that batches differently from the real producer (a
|
||||||
|
`Binding::Sequence` is ONE effect vec);
|
||||||
|
- **the cursor at index 0**: "the item under the cursor" and "the first item"
|
||||||
|
are indistinguishable there, and that was four of five findings in one
|
||||||
|
review. Seat the cursor at a nonzero index of a list with at least two
|
||||||
|
elements;
|
||||||
|
- a determinism check against ONE context instance: every `HashMap` iterates
|
||||||
|
the same way twice. Build two equal contexts independently
|
||||||
|
(improvise-hzjo);
|
||||||
|
- two derivations of one fact where the fixture makes them agree (drawn vs
|
||||||
|
committed, edit text vs value, `1200` vs `1.23456789`). Use a value where
|
||||||
|
they disagree.
|
||||||
|
- **Record each bug in `context/test-evidence/<area>.md`**, keyed by test name
|
||||||
|
(module-qualify the name when the leaf is not unique). It is append-at-EOF, so
|
||||||
|
**expect a conflict**. Keep both sides and verify line by line against both
|
||||||
|
parents: `--check-evidence` cannot see a dropped entry.
|
||||||
|
- **Comment runs are at most two lines.** Reasoning goes in `context/`, not in
|
||||||
|
comments (`context/design-principles.md` §6).
|
||||||
|
- **If the acceptance criteria look wrong, argue it** rather than following
|
||||||
|
them silently. Three agents inverted theirs in one campaign, and all three
|
||||||
|
were right.
|
||||||
|
|
||||||
|
## Files you must not write
|
||||||
|
|
||||||
|
`.beads/**` (never commit `issues.jsonl`, never `git checkout` it),
|
||||||
|
`prolog-sessions/kb.pl`, `context/repo-map.md`: `AGENTS.md`, "Who owns what".
|
||||||
|
Also `AGENTS.md`, unless your brief grants you a named section. Report proposed
|
||||||
|
text for any of these in your hand-back.
|
||||||
|
|
||||||
|
## GitHub
|
||||||
|
|
||||||
|
- `gh` is shell-aliased to a different tool. Use
|
||||||
|
`nix shell nixpkgs#gh --command gh …`, and pass bodies with `-F body=@file`.
|
||||||
|
- **Everything posted goes out under the repository owner's account.** Open
|
||||||
|
every PR body and comment with the attribution line your brief gives you,
|
||||||
|
verbatim. It names your agent and model, which is how our posts are told
|
||||||
|
apart from an automated Codex review (`AGENTS.md`, "Shipping a wave").
|
||||||
|
- The attribution line, commit trailers and PR footer all come from your brief.
|
||||||
|
They name the agent and the session, so this shared file cannot hold them.
|
||||||
|
- Read reviews with `./scripts/pr-reviews <n>`, and do not pipe it. How to tell
|
||||||
|
a ChatGPT Codex review from ours, and why Copilot is not coming: `AGENTS.md`,
|
||||||
|
"Shipping a wave". Answer each Codex review on its thread.
|
||||||
|
- **Do not merge, and do not close beads.** Avoid stacked PRs. If you must
|
||||||
|
stack, never let the base branch be deleted.
|
||||||
|
|
||||||
|
## Hand-back, per ticket
|
||||||
|
|
||||||
|
Report:
|
||||||
|
|
||||||
|
- your branch, head SHA and PR number. Review is dispatched against the SHA;
|
||||||
|
- what changed, per ticket;
|
||||||
|
- the claim result;
|
||||||
|
- your measured baseline;
|
||||||
|
- whether the ticket reproduced (the SHA if it did not);
|
||||||
|
- the rival and where it failed;
|
||||||
|
- what you could not verify, and why;
|
||||||
|
- proposed repo-map and `kb.pl` text;
|
||||||
|
- **what the ticket did not predict**, consistently the most valuable part.
|
||||||
|
|
||||||
|
## Disk
|
||||||
|
|
||||||
|
Each worktree's `target/` grows to 3–6G, and a full disk (ENOSPC) once stopped
|
||||||
|
every agent. **When you hand back, delete your own build output, and only
|
||||||
|
yours.**
|
||||||
|
|
||||||
|
Run `pwd` and `git rev-parse --show-toplevel` first, and read the answer. Then
|
||||||
|
delete by **literal absolute path**, typed out:
|
||||||
|
`rm -rf /Users/.../.claude/worktrees/agent-<you>/target`.
|
||||||
|
|
||||||
|
**Never interpolate a computed path into `rm -rf`.** One agent's worktree had
|
||||||
|
been removed, so `$(git rev-parse --show-toplevel)` printed nothing and the
|
||||||
|
command became `rm -rf "/target"`. A guarded one-liner was tried, but the
|
||||||
|
worktree shell guard refuses it as too complex, which pushed agents back to an
|
||||||
|
unguarded form. A literal path is the version that is both allowed and safe.
|
||||||
|
|
||||||
|
Keep your branch and any uncommitted work. Delete only `target/` (and
|
||||||
|
`harness/opfs-contract/target` if you built it). If you see ENOSPC, stop and
|
||||||
|
report rather than deleting anything outside your worktree.
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../../.agents/skills/wave
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
---
|
|
||||||
name: wave
|
|
||||||
description: Dispatch parallel agents to work through open beads and shepherd each to a merged PR. Use when an orchestrator is running a wave, partitioning the backlog, or writing a brief for a work-unit agent.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Running a wave
|
|
||||||
|
|
||||||
An orchestrator chunks the open backlog, fans agents out, reviews what comes
|
|
||||||
back, and merges. `AGENTS.md` has the history; this is the operating procedure.
|
|
||||||
|
|
||||||
## Every agent gets its own worktree. No exceptions.
|
|
||||||
|
|
||||||
Dispatch with `isolation: "worktree"`. Without it every agent edits the **same**
|
|
||||||
working tree: one `git status` shows four agents' half-finished files, any commit
|
|
||||||
sweeps up the others' work, and any `git checkout` destroys it. This has happened
|
|
||||||
here. If you discover it mid-wave, stop every agent, have each create a worktree
|
|
||||||
and copy across **only files it can prove it touched**, then `git checkout --`
|
|
||||||
those files in the primary tree.
|
|
||||||
|
|
||||||
In the worktree: `direnv allow`, or `bd` reports a version *mismatch* rather than
|
|
||||||
failing cleanly. `direnv status` prints `Found RC allowed 0`, and `0` means
|
|
||||||
allowed — it reads like the opposite.
|
|
||||||
|
|
||||||
## Partitioning
|
|
||||||
|
|
||||||
By **crate or directory**, never by ticket count. **Tickets that share a file go
|
|
||||||
to one agent**, to be done sequentially — four widget migrations all touching
|
|
||||||
`src/draw.rs` are a guaranteed conflict split four ways. Group first, then count.
|
|
||||||
|
|
||||||
Tell each agent what ground is *not* theirs, and to report rather than guess when
|
|
||||||
it must cross. Two agents adding a workspace member will still collide in
|
|
||||||
`Cargo.toml`/`Cargo.lock`; keep both sides.
|
|
||||||
|
|
||||||
## What every brief must carry
|
|
||||||
|
|
||||||
1. **The expected base commit, by name.** Worktrees do not reliably branch from
|
|
||||||
HEAD — one was created three merges behind and only noticed because it was
|
|
||||||
told to check.
|
|
||||||
2. **The baseline**, so "N passing" is checkable rather than asserted: Rust test
|
|
||||||
count, harness counts, node counts.
|
|
||||||
3. **Its ground, and the ground that is not.**
|
|
||||||
4. **Never write** `.beads/**`, `prolog-sessions/kb.pl`, `context/repo-map.md`.
|
|
||||||
Agents read them freely and report proposed text; the orchestrator applies it.
|
|
||||||
5. **The commit trailers and PR footer**, spelled out.
|
|
||||||
6. **Do not push to `main`, do not merge.** The orchestrator merges.
|
|
||||||
7. **What to report**: branch and head SHA, PR number, what changed per ticket,
|
|
||||||
*what could not be verified and why*, proposed repo-map/kb text, and **what it
|
|
||||||
learned that the ticket did not predict** — consistently the most valuable
|
|
||||||
part, and omitted unless asked for explicitly.
|
|
||||||
|
|
||||||
## Method to require, because this repo's defect is a test that passes
|
|
||||||
|
|
||||||
- Failing test first, then the fix.
|
|
||||||
- Every guard proved by **injecting the fault it names** and watching it fail
|
|
||||||
**by name**. An injection that does not compile reads as a clean run, so
|
|
||||||
require a positive signal the build ran.
|
|
||||||
- `cargo test --workspace` is **fail-fast**; `--no-fail-fast` for any claim about
|
|
||||||
blast radius.
|
|
||||||
- A textually clean merge can **delete tests** with no conflict marker, and
|
|
||||||
`cargo check` will not notice. After any merge that moves a test module, diff
|
|
||||||
test **names** — a count is masked by the other side's additions.
|
|
||||||
|
|
||||||
## Shepherding
|
|
||||||
|
|
||||||
- Wait on checks with `scripts/pr-watch <pr> --expect <sha>`. Never hand-roll a
|
|
||||||
poll; see the `pr-watch` skill for the three ways they report green while wrong.
|
|
||||||
- Review before merging. Copilot's quota may be exhausted and its request is a
|
|
||||||
**silent no-op**; an absent review and an unrequested one both read as
|
|
||||||
"pending". Dispatch an adversarial reviewer and give it the head SHA, the base,
|
|
||||||
and a test-merge, so it reviews the tree that will exist.
|
|
||||||
- A re-review is of the **delta**, at a named SHA. A review of a superseded
|
|
||||||
commit reads as a pass.
|
|
||||||
- Merge on GitHub, then `git fetch gh && git merge --ff-only gh/main`.
|
|
||||||
- Anything posted to GitHub goes out under the owner's account: open every
|
|
||||||
comment with a line saying a Claude agent wrote it.
|
|
||||||
|
|
||||||
## Between waves
|
|
||||||
|
|
||||||
Run the code-review skill on the merged range. The characteristic find here is
|
|
||||||
not a wrong line, it is **a test that passes while the thing it names is
|
|
||||||
broken** — a vacuous fold test, a one-category fixture, a helper that fabricates
|
|
||||||
what the code under test needs. Ask the reviewer to inject the fault and watch
|
|
||||||
the check fail.
|
|
||||||
@@ -100,52 +100,19 @@ Two agents each adding a workspace member will still collide in
|
|||||||
|
|
||||||
### Every wave agent's brief must include
|
### Every wave agent's brief must include
|
||||||
|
|
||||||
1. **Verify your base commit first.** Worktrees do **not** reliably branch from
|
The wave skill holds both halves, each in one place (improvise-1f8e):
|
||||||
the orchestrator's HEAD — one was created three merges behind and only
|
|
||||||
noticed because it was told to look. `git log --oneline -1` against a named
|
|
||||||
commit, reset onto `main` if behind. Name the expected commit in the brief.
|
|
||||||
2. **The baseline test count**, so "1090 passing" is checkable rather than
|
|
||||||
asserted, and a drop is visible. Tell the agent to **measure its own** and
|
|
||||||
cite the machine: the same commit measured `improvise-io`'s binary at 1.4s on
|
|
||||||
one machine and 3.7–5.2s on another, so a figure with no machine is a claim
|
|
||||||
about the suite, which it is not.
|
|
||||||
3. **The gate list, and it must not say `cargo fmt --all`.** That reaches only
|
|
||||||
**one** of this repo's two workspace roots — `harness/opfs-contract` declares
|
|
||||||
its own `[workspace]` — and the obvious repair is worse: `cargo fmt
|
|
||||||
-p opfs-contract` from the repo root exits **1**, *"not a member of the
|
|
||||||
workspace"*, which is indistinguishable from a real formatting failure
|
|
||||||
(improvise-b4ks). Both spellings fail in the direction that looks like
|
|
||||||
success. The gate is:
|
|
||||||
|
|
||||||
```
|
- **The brief checklist** — what an orchestrator must put in a brief — is
|
||||||
direnv exec . ./scripts/fmt-workspaces.sh # exit 2 = the gate did not run
|
`.agents/skills/wave/SKILL.md`, "What every brief must carry".
|
||||||
```
|
- **The agent's standing rules** — base and push, gates, claim, vacuity shapes,
|
||||||
|
evidence, forbidden files, GitHub, hand-back, disk, commit early — are
|
||||||
|
`.agents/skills/wave/agent-rules.md`. A brief points there rather than
|
||||||
|
restating them.
|
||||||
|
|
||||||
Every gate goes through `direnv exec .` — `./scripts/checkers.sh` scrubs the
|
`.claude/skills/wave` is a symlink to `.agents/skills/wave`, so Claude and Codex
|
||||||
environment to an allowlist, so a bare invocation drops `tpl` off `PATH` and
|
read the same files. A new rule goes into one of those two files, not here and
|
||||||
reports spurious failures. And **never pipe a gate**: `$?` must be the gate's
|
not into the next brief: a restated rule is the copy nobody corrects, and this
|
||||||
own, and `check-comment-runs.py --check-evidence` prints two lines with the
|
list was once a third copy that drifted from the skill's.
|
||||||
comment cap **first**, so `| tail -1` silently drops half of it.
|
|
||||||
4. **Commit frequently, so the work is safe in git.** A WIP commit after the
|
|
||||||
first green test, and again after every meaningful step. A worktree is not
|
|
||||||
durable storage: an agent finished a whole ticket with every gate green and
|
|
||||||
lost all of it, uncommitted, when its worktree was deleted during a disk
|
|
||||||
cleanup. Tidying the history before the PR is fine; losing it is not.
|
|
||||||
5. **Do not merge to `main`.** The orchestrator merges. Pushing the agent's own
|
|
||||||
branch (`git push gh HEAD:refs/heads/<branch>`) is encouraged once it is
|
|
||||||
worth keeping.
|
|
||||||
6. The commit-message trailers, spelled out.
|
|
||||||
7. **What to report**: branch and commits, what changed per ticket, *what could
|
|
||||||
not be verified and why*, and proposed repo-map/`kb.pl` text. Ask explicitly
|
|
||||||
for the thing the agent learned that the ticket did not predict — that is
|
|
||||||
consistently the most valuable part of a hand-back, and agents omit it unless
|
|
||||||
asked.
|
|
||||||
|
|
||||||
`bd` works in any worktree, but `.envrc` must be allowed there or you get a
|
|
||||||
**version mismatch** rather than a clean failure — `direnv allow` in the
|
|
||||||
worktree, or rely on the `[whitelist] prefix` in `~/.config/direnv/direnv.toml`.
|
|
||||||
Note `direnv status` reports `Found RC allowed 0`, and `0` means **allowed**
|
|
||||||
(the enum is 0=Allowed, 1=NotAllowed). It reads like the opposite.
|
|
||||||
|
|
||||||
### Between waves
|
### Between waves
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user