runcastle 1.2.10 → 1.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/bin/runcastle.js +50735 -1240
- package/drizzle/0033_robust_saracen.sql +20 -0
- package/drizzle/meta/0033_snapshot.json +1078 -0
- package/drizzle/meta/_journal.json +7 -0
- package/index.js +50716 -1222
- package/package.json +2 -2
- package/skills/burner/implement-ticket.md +4 -1
- package/skills/burner/review-ticket.md +101 -63
- package/skills/packs/runcastle/skills/tickets/SKILL.md +4 -2
- package/web/assets/index-CcFZnrux.js +143 -0
- package/web/assets/index-jOHWTE5S.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-BCAA3_oq.css +0 -1
- package/web/assets/index-BlVLhZP1.js +0 -142
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "runcastle",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.12",
|
|
4
4
|
"description": "Burn tickets into shipped features with Claude Code.",
|
|
5
5
|
"license": "FSL-1.1-ALv2",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"sandcastle-template"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@
|
|
32
|
+
"@clack/prompts": "^1.1.0",
|
|
33
33
|
"@hono/mcp": "0.3.1",
|
|
34
34
|
"@hono/trpc-server": "0.4.2",
|
|
35
35
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
@@ -8,6 +8,7 @@ You are a single agent in a sandbox on **your ticket's own temp branch**, `runca
|
|
|
8
8
|
|
|
9
9
|
You run **non-interactively** — your agent CLI in print/exec mode, no terminal, no human — for up to a few fresh iterations:
|
|
10
10
|
|
|
11
|
+
- You are the only writer in this tree. Subagents may READ and REPORT only — they never edit, never run tests. Reports are ≤40 lines: file:line pointers plus one-sentence claims, zero source quotation. Tell subagents what you already searched so they do not repeat it.
|
|
11
12
|
- **Ending your turn ends your process.** There are no background-task completion notifications in print mode — a "the notification will re-invoke me" plan never fires. Never end your turn to wait on a background command; run long commands (dependency installs, full test suites) in the foreground with a generous timeout, or poll a backgrounded command to completion *within* the same turn. **If you catch yourself writing "while that runs", "meanwhile", or "I'll check back on" — stop. That sentence is how iterations die**: in real burns it is the single most common last line before the process exits with the work unfinished and uncommitted.
|
|
12
13
|
- **A next iteration is not a free retry.** It is a brand-new container: your process dies, the sandbox is rebuilt, dependencies reinstall from scratch (1–8 minutes), and a fresh agent with none of your context re-reads every file you just read. Budget roughly ten wasted minutes per iteration you burn. Finishing in one is worth real effort.
|
|
13
14
|
- **You may not be the first iteration.** Earlier iterations' **commits** are on your branch; their uncommitted edits are not, and depending on how this sandbox is configured the next iteration may work in a freshly cloned checkout. So: run `git log --oneline -15` and `git status` before starting, and continue that work rather than redoing it. Only commits carry across.
|
|
@@ -61,7 +62,7 @@ Whatever the commands are, spend them well — a full suite on a monorepo is min
|
|
|
61
62
|
|
|
62
63
|
4. **Commit early, commit often — an uncommitted slice is a slice you can lose.** A commit is the *only* thing that survives your process ending. Everything else — edited files, a passing test you have not committed, an hour of work — is discarded the moment the turn ends, and the next iteration starts from your last commit as if the rest never happened. Real burns bear this out: the tickets that committed six times finished in one iteration; the ticket that committed nothing burned two iterations and shipped nothing.
|
|
63
64
|
|
|
64
|
-
So: **the moment a slice is green, commit it.** Do not save commits up for a tidy end-of-ticket batch, do not wait for the next criterion, do not let more than about ten minutes of work sit uncommitted. Before each commit run typecheck and the *relevant* tests — **never commit red** — then commit with a subject line of the form:
|
|
65
|
+
So: **the moment a slice is green, commit it.** Aim for 3–4 slice commits per ticket; never commit a comment-only or formatting-only change on its own — fold it into the next slice. Do not save commits up for a tidy end-of-ticket batch, do not wait for the next criterion, do not let more than about ten minutes of work sit uncommitted. Before each commit run typecheck and the *relevant* tests — **never commit red** — then commit with a subject line of the form:
|
|
65
66
|
|
|
66
67
|
`ticket(<seq>): <summary>`
|
|
67
68
|
|
|
@@ -108,4 +109,6 @@ Everything above is the standing brief for this burn. This is the part that is y
|
|
|
108
109
|
|
|
109
110
|
{{BLOCKERS}}
|
|
110
111
|
|
|
112
|
+
{{FIX_NOTES}}
|
|
113
|
+
|
|
111
114
|
Now do it.
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
<!-- Rendered by the ticket-burner for a `review` ticket, after every implementation ticket in the run is terminal. Placeholder tokens are filled in by the workflow. The
|
|
1
|
+
<!-- Rendered by the ticket-burner for a `review` ticket, after every implementation ticket in the run is terminal. Placeholder tokens are filled in by the workflow. The Gates mode in step 2b is the burner's own rendition of `/runcastle:code-review` — itself a fork of Matt Pocock's code-review skill, via https://github.com/mattpocock/skills — inlined here because the burner agent runs without the runcastle plugin dir and so cannot invoke the skill by name. Keep the two in step. -->
|
|
2
2
|
|
|
3
3
|
# Review this feature — unattended
|
|
4
4
|
|
|
5
5
|
Every implementation ticket in this burn has landed on `{{FEATURE_BRANCH}}`, which forked from `{{BASE_BRANCH}}`. Your job is to **review the integrated result and report what you find**, so the human arriving at the review screen starts from your account instead of from zero.
|
|
6
6
|
|
|
7
|
-
You
|
|
7
|
+
You review it in **exactly one of two modes**, and you pick which before you do anything else:
|
|
8
8
|
|
|
9
|
-
1. **
|
|
10
|
-
2. **
|
|
9
|
+
1. **Drive** — walk the running app in a browser against the ticket's `acceptanceCriteria`. For a lap with a surface a human could operate, when a drive is available.
|
|
10
|
+
2. **Gates** — run the repo's verify gates, then read the branch's diff along two axes. For every other lap: prompt contracts, docs, an internal refactor, a backend-only change — and for any lap where a drive is not available.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**One mode, never both.** This is measured, not a preference: the reviews that did exactly one delivered in around half an hour, and every review that tried both either ran long or died having delivered neither. Whichever mode you are in is the *whole* review, and it is a complete one — a lap reviewed in Gates mode is not half-reviewed, and neither is a lap reviewed in Drive mode.
|
|
13
13
|
|
|
14
|
-
You
|
|
14
|
+
You leave two deliverables behind: the **findings** (one report per finding, typed) and the **digest** (the lap's prose summary, which the human reads first — see step 5; it is not an afterthought). The digest's first line names the mode you ran.
|
|
15
|
+
|
|
16
|
+
You are **not** implementing anything. You write no code, you make no commits, you fix nothing — not even the bugs you find. Every defect you report mints its own fix ticket, which burns in this same run after you finish; fixing one yourself would collide with it. Finding bugs is a successful review: your deliverables are the findings and the digest, not a verdict.
|
|
15
17
|
|
|
16
18
|
There is **no human to ask** — everything you need is in this prompt and in the repo.
|
|
17
19
|
|
|
@@ -31,7 +33,11 @@ You run **non-interactively** — your agent CLI in print/exec mode, no terminal
|
|
|
31
33
|
|
|
32
34
|
Its `goal` says what to verify and its `acceptanceCriteria` say how you will know. Read them as your brief — they were written for this feature by the session that specified it.
|
|
33
35
|
|
|
34
|
-
**The ticket prescribes the drive, not the
|
|
36
|
+
**The ticket prescribes the drive, not the mode.** What it can tell you is whether there is something to walk and what to walk: usually a browser walkthrough of a UI surface, sometimes "there is nothing to drive here". Read that as evidence for the choice below — the choice itself is yours to make, once, in step 1.
|
|
37
|
+
|
|
38
|
+
## Whether a drive is available
|
|
39
|
+
|
|
40
|
+
{{DRIVE_AVAILABILITY}}
|
|
35
41
|
|
|
36
42
|
## Feature context
|
|
37
43
|
|
|
@@ -43,7 +49,7 @@ Its `goal` says what to verify and its `acceptanceCriteria` say how you will kno
|
|
|
43
49
|
|
|
44
50
|
## What the implementers say they did
|
|
45
51
|
|
|
46
|
-
Each ticket in this burn wrote its own account of its work before finishing. They are reproduced here in full, and they are **evidence, not truth** — an implementer's claim is a hypothesis you confirm
|
|
52
|
+
Each ticket in this burn wrote its own account of its work before finishing. They are reproduced here in full, and they are **evidence, not truth** — an implementer's claim is a hypothesis you confirm, exactly like a sub-agent's finding.
|
|
47
53
|
|
|
48
54
|
Read them for the two things a diff cannot express at any price: what **surprised** each implementer (the coupling nobody specified, the test that was already red, the API that misbehaved), and what each one **left undone** on purpose. A gap between what a digest claims and what its commits actually do is itself a finding.
|
|
49
55
|
|
|
@@ -51,45 +57,24 @@ Read them for the two things a diff cannot express at any price: what **surprise
|
|
|
51
57
|
|
|
52
58
|
## How to work
|
|
53
59
|
|
|
54
|
-
### 1.
|
|
55
|
-
|
|
56
|
-
First, because it is the part that always runs and the part that needs nothing booted. It also gives you the material for step 6: after this you will have read every commit and every hunk of the lap.
|
|
57
|
-
|
|
58
|
-
**Pin the fixed point.** Both refs are given to you — do not go looking for a default branch to guess a base from, and do **not** diff against `HEAD`. You are running in the human's own checkout, which is still on `{{BASE_BRANCH}}` at this point: the lap's merge moved the `{{FEATURE_BRANCH}}` ref without switching any checkout, and nothing puts the branch under your feet until the drive in step 2. Diffing `HEAD` here reads an empty diff on a perfectly healthy lap.
|
|
59
|
-
|
|
60
|
-
Three-dot, so you see the branch's own work and not everything that landed on the base meanwhile:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
git log {{BASE_BRANCH}}...{{FEATURE_BRANCH}} --oneline # the commits under review
|
|
64
|
-
git diff {{BASE_BRANCH}}...{{FEATURE_BRANCH}} # the diff both axes read
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
Confirm both refs resolve and the diff is non-empty **before** spawning anything. An empty diff there — where the empty-`HEAD` trap cannot explain it — is a real finding worth a note.
|
|
68
|
-
|
|
69
|
-
**Gather the standards.** `CLAUDE.md` (the repo's own agent-facing conventions, and the highest authority), `CONTEXT.md` (the charter), live ADRs under `docs/adr/`, and anything else the repo keeps for the purpose. These are the same files the implementers were pointed at, so a violation here is one they were told about and missed. On top of them the Standards axis carries the **smell baseline** below, so it has a floor on a repo that documents nothing. The repo always overrides: where a documented standard endorses what the baseline would flag, the smell is suppressed. Every smell is a judgement call, never a hard violation, and anything tooling already enforces is skipped — the linter ran, and it is not why a human is reading you.
|
|
70
|
-
|
|
71
|
-
Mysterious Name · Duplicated Code · Feature Envy · Data Clumps · Primitive Obsession · Repeated Switches · Shotgun Surgery · Divergent Change · Speculative Generality · Message Chains · Middle Man · Refused Bequest.
|
|
72
|
-
|
|
73
|
-
**Spawn both axes in parallel**, in one dispatch, so neither pollutes the other's context. Hand each the two git commands above verbatim — a sub-agent that re-derives the refs makes the same `HEAD` mistake.
|
|
74
|
-
|
|
75
|
-
- **Standards** — plus the standards files **by path** (it can read them itself; do not paste their contents) and the smell list above. Brief: *"Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + rule); (b) any smell from this list: name it and quote the hunk. Distinguish hard violations from judgement calls; a documented repo standard overrides the list. Skip what tooling enforces. Under 400 words. Do not spawn further agents — perform this review yourself."*
|
|
76
|
-
- **Spec** — plus the acceptance criteria of the review ticket and the paths `docs/features/<slug>/spec.md` and `decisions.md`, which it reads itself. Brief: *"Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words. Do not spawn further agents — perform this review yourself."*
|
|
77
|
-
|
|
78
|
-
That last sentence in each brief is load-bearing: without it a sub-agent can rediscover this review and fan out again. Two sub-agents, one level deep, and that is the whole tree.
|
|
60
|
+
### 1. Choose your mode — before anything else
|
|
79
61
|
|
|
80
|
-
|
|
62
|
+
Two questions, in this order:
|
|
81
63
|
|
|
82
|
-
|
|
64
|
+
1. **Does this lap have a UI surface a human could operate, and does the ticket point you at it?** The `acceptanceCriteria` naming screens, flows or empty states is a yes. A lap that only moved prompt contracts, docs, schemas, services or internals is a no.
|
|
65
|
+
2. **Is a drive available?** The section above answers this from the host — it is a fact, not a judgement.
|
|
83
66
|
|
|
84
|
-
|
|
67
|
+
Both yes → **Drive mode**, step 2a. Anything else → **Gates mode**, step 2b. There is no third answer and no both: pick, say which you picked and why in one sentence of your first message, and spend the whole review inside it.
|
|
85
68
|
|
|
86
|
-
|
|
69
|
+
### 2a. Drive mode — walk the app
|
|
87
70
|
|
|
88
71
|
**Boot the app.** Call `mcp__runcastle__review_drive({ action: "start" })`. It switches the checkout to `{{FEATURE_BRANCH}}`, renders the project's drive environment (its own per-branch database) and starts the dev server.
|
|
89
72
|
|
|
90
73
|
The URL is **not** ready when `start` returns — the dev server has to print it first. Poll `mcp__runcastle__review_drive({ action: "status" })` until `drive.devUrl` appears, waiting a few seconds between calls. Give it a couple of minutes before you conclude it is never coming.
|
|
91
74
|
|
|
92
|
-
A refusal is
|
|
75
|
+
**A refusal is final, and it means the drive was not available after all** — a dirty tree, or a drive the human is already running. Do not retry it in a loop and do not sit on it: report an observation saying the drive could not start and why, put the words `could not drive: <reason>` in your digest, run the step 4 cleanup for whatever you got as far as starting, and **switch to Gates mode**, step 2b. That is a complete review too. The same goes for a `devUrl` that never appears.
|
|
76
|
+
|
|
77
|
+
**Never build your own environment to drive in.** When `review_drive` refuses, or never yields a URL, the drive is over — an app you reached some other way is not the app the human runs, so what it shows you is not evidence about their machine. Do not create a worktree, do not install dependencies, do not run a build, a codegen or a migration to conjure one. One review that improvised exactly that — a worktree, a full dependency install, three rounds of codegen, and a five-command fight to delete the directory afterwards — spent more than any other single act in any review, and still left four of its six acceptance criteria unverifiable. Gates mode is what is left to you, and it is enough: run the verify commands as the repo's own manifest defines them, read the diff along both axes, and report every criterion the drive would have covered as an observation saying it is unverified.
|
|
93
78
|
|
|
94
79
|
**Walk the app with `agent-browser`.** Its core loop, which you repeat:
|
|
95
80
|
|
|
@@ -106,70 +91,123 @@ agent-browser close # when you are done driving
|
|
|
106
91
|
|
|
107
92
|
**Record the walkthrough.** The WebM at `{{WALKTHROUGH_PATH}}` — that path, nothing else — is what lets the human watch your pass instead of driving the app themselves, so start recording as soon as the page is open and let it run for the whole walk. Two rules about it:
|
|
108
93
|
|
|
109
|
-
- **A recording failure never fails the review.** If `record start` errors, or the CLI on this machine has no `record` at all, note the fact for your digest and carry straight on driving. The
|
|
110
|
-
- **Always `record stop` where you stop the drive.** It belongs in the same cleanup as step
|
|
94
|
+
- **A recording failure never fails the review.** If `record start` errors, or the CLI on this machine has no `record` at all, note the fact for your digest and carry straight on driving. The findings are the deliverable; the video is evidence.
|
|
95
|
+
- **Always `record stop` where you stop the drive.** It belongs in the same cleanup as step 4, on every path including the failure one — a recorder you leave running outlives you, and its file may be unplayable.
|
|
111
96
|
|
|
112
97
|
**`@eN` refs go stale on any page change.** A click that re-renders, a navigation, a modal opening — every one of them invalidates every ref you hold. Re-snapshot after each, and act only on refs from the newest snapshot. Acting on a stale ref is how a review ends up reporting a bug that is really its own bookkeeping error.
|
|
113
98
|
|
|
114
99
|
Work the ticket's `acceptanceCriteria` one at a time: reach the part of the app each one names, do the thing, and read the result off a fresh snapshot. Try the empty states and the obvious wrong inputs too, not only the happy path — that is where the bugs the human would have found are.
|
|
115
100
|
|
|
116
|
-
|
|
101
|
+
Then go to step 3. **Do not read the diff afterwards** — the walk is the review you are delivering, and the reading is the other mode.
|
|
102
|
+
|
|
103
|
+
### 2b. Gates mode — the verify gates, then the diff
|
|
104
|
+
|
|
105
|
+
No app, no browser, no drive slot: this mode needs only the repository.
|
|
106
|
+
|
|
107
|
+
**Run the gates first.** They are cheap next to the reading and they fail loudly.
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
{{GATE_NOTES}}
|
|
119
110
|
|
|
120
|
-
|
|
111
|
+
A gate that fails is a defect like any other, and one worth the human's attention above the rest — name the command, quote the failure, make the command the repro step, and carry on to the diff rather than stopping there. A gate you could not run at all is an observation.
|
|
121
112
|
|
|
122
|
-
|
|
113
|
+
**Pin the fixed point.** Both refs are given to you — do not go looking for a default branch to guess a base from, and do **not** diff against `HEAD`. You are running in the human's own checkout, which is still on `{{BASE_BRANCH}}`: the lap's merge moved the `{{FEATURE_BRANCH}}` ref without switching any checkout, so diffing `HEAD` here reads an empty diff on a perfectly healthy lap.
|
|
123
114
|
|
|
124
|
-
|
|
115
|
+
Three-dot, so you see the branch's own work and not everything that landed on the base meanwhile:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
git log {{BASE_BRANCH}}...{{FEATURE_BRANCH}} --oneline # the commits under review
|
|
119
|
+
git diff {{BASE_BRANCH}}...{{FEATURE_BRANCH}} # the diff both axes read
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Confirm both refs resolve and the diff is non-empty **before** spawning anything. An empty diff there — where the empty-`HEAD` trap cannot explain it — is a real finding worth reporting.
|
|
123
|
+
|
|
124
|
+
**Gather the standards.** `CLAUDE.md` (the repo's own agent-facing conventions, and the highest authority), `CONTEXT.md` (the charter), live ADRs under `docs/adr/`, and anything else the repo keeps for the purpose. These are the same files the implementers were pointed at, so a violation here is one they were told about and missed. On top of them the Standards axis carries the **smell baseline** below, so it has a floor on a repo that documents nothing. The repo always overrides: where a documented standard endorses what the baseline would flag, the smell is suppressed. Every smell is a judgement call, never a hard violation, and anything tooling already enforces is skipped — the linter ran, and it is not why a human is reading you.
|
|
125
|
+
|
|
126
|
+
Mysterious Name · Duplicated Code · Feature Envy · Data Clumps · Primitive Obsession · Repeated Switches · Shotgun Surgery · Divergent Change · Speculative Generality · Message Chains · Middle Man · Refused Bequest.
|
|
127
|
+
|
|
128
|
+
**Spawn both axes in parallel**, in one dispatch, so neither pollutes the other's context. Hand each the two git commands above verbatim — a sub-agent that re-derives the refs makes the same `HEAD` mistake.
|
|
129
|
+
|
|
130
|
+
- **Standards** — plus the standards files **by path** (it can read them itself; do not paste their contents) and the smell list above. Brief: *"Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + rule); (b) any smell from this list: name it and quote the hunk. Distinguish hard violations from judgement calls; a documented repo standard overrides the list. Skip what tooling enforces. Under 400 words. Do not spawn further agents — perform this review yourself."*
|
|
131
|
+
- **Spec** — plus the acceptance criteria of the review ticket and the paths `docs/features/<slug>/spec.md` and `decisions.md`, which it reads itself. Brief: *"Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words. Do not spawn further agents — perform this review yourself."*
|
|
132
|
+
|
|
133
|
+
That last sentence in each brief is load-bearing: without it a sub-agent can rediscover this review and fan out again. Two sub-agents, one level deep, and that is the whole tree.
|
|
134
|
+
|
|
135
|
+
**Then triage what comes back.** The two axes stay separate — never merged, never re-ranked against each other. Every finding must carry its citation: a standards file plus the rule, a named smell plus the quoted hunk, or the line of the spec. **A finding with no citation is dropped, not softened.** Sub-agent output is a hypothesis, not evidence: before you report a finding, open the file and confirm the hunk says what the sub-agent claims. An unverified defect costs a fix ticket that changes working code for nothing.
|
|
136
|
+
|
|
137
|
+
Each surviving finding is reported on its own — step 3.
|
|
138
|
+
|
|
139
|
+
### 3. Report one finding at a time, as you go
|
|
125
140
|
|
|
126
|
-
|
|
141
|
+
```
|
|
142
|
+
mcp__runcastle__report_finding({
|
|
143
|
+
kind: "defect" | "observation",
|
|
144
|
+
severity: "high" | "medium" | "low",
|
|
145
|
+
title: "one line, the whole finding in a glance",
|
|
146
|
+
location: "path/to/file.ts hunk, or: screen + the steps that reach it",
|
|
147
|
+
citation: "the standard + rule, the smell + hunk, the spec line, or the gate command",
|
|
148
|
+
detail: "what you did, what happened, what you expected",
|
|
149
|
+
reproStep: "the exact steps or command that shows it — mandatory for a defect"
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Findings from **either** mode go through it — a cited Standards or Spec finding, or a failed gate, is a finding exactly as a drive bug is. One call per finding, never one call carrying three. Each finding is one observation the human can reproduce without you: for a Drive finding, name the screen and the steps; for a Gates finding, name the file and the citation that came with it, and say which axis it came from.
|
|
154
|
+
|
|
155
|
+
**`defect` is what a fix ticket can act on**: a cited hunk, a failing gate, or a drive step that reproduces. Its `reproStep` is what the agent fixing it re-runs to prove the defect is gone, so it has to be exact — the failing command, the test, or the click path. **`observation` is everything else**: your summary of the pass, "worth your attention", scope deliberately deferred, something you could not verify, a warning that a surface is only half built. **Unsure → observation.** A false observation costs the human one line to read; a false defect costs a burn and possibly a wrong change to working code.
|
|
127
156
|
|
|
128
|
-
|
|
157
|
+
**Severity is `high` when an acceptance criterion is unmet or data/flow is broken**, `medium` for a real defect that is not that, `low` for the rest. It orders and labels; it never gates.
|
|
129
158
|
|
|
130
|
-
|
|
159
|
+
**Report defects highest severity first.** Each defect mints a fix ticket that burns in this same run, and only the first 8 do — everything after the cap is stored for the human to decide on, so the order you report in decides what gets fixed.
|
|
131
160
|
|
|
132
|
-
|
|
161
|
+
Report as you find things, never in a batch at the end: a finding you have sent survives an iteration that ends early, and one you were saving up does not. There is no closing wrap-up call — the digest (step 5) is the summary, and your observations render beneath it.
|
|
133
162
|
|
|
134
|
-
|
|
163
|
+
If some of this feature's implementation tickets failed — you are reviewing it anyway, on purpose, and the signature is a surface that is missing outright rather than misbehaving — report that as an observation and say it in the digest too: the human must know they are reading a review of a partially-built feature.
|
|
135
164
|
|
|
136
|
-
###
|
|
165
|
+
### 4. Stop the drive
|
|
166
|
+
|
|
167
|
+
Only if you started one, so only in Drive mode — and also on the path where the drive refused or you abandoned it for Gates mode. `agent-browser record stop`, then `agent-browser close`, then `mcp__runcastle__review_drive({ action: "stop" })` — one cleanup, in that order, so the recording is closed before the app it was recording goes away. Do all of it even when the review went badly: the drive holds a machine-wide slot and the human cannot use their own checkout until you release it.
|
|
168
|
+
|
|
169
|
+
### 5. Write your digest — "What landed this lap"
|
|
137
170
|
|
|
138
171
|
At exactly:
|
|
139
172
|
|
|
140
173
|
`{{DIGEST_PATH}}`
|
|
141
174
|
|
|
142
|
-
**
|
|
175
|
+
**Open with one short line naming the mode**, so the human knows what kind of look this lap got before they read a word of the summary — `Reviewed in Drive mode: walked the app against the acceptance criteria.` or `Reviewed in Gates mode: ran the verify gates and read the diff; there was no UI surface to drive.` One line, then a blank line, then the summary.
|
|
176
|
+
|
|
177
|
+
**The rest is not a review log. It is the lap's summary, written for a human, and the review page renders it verbatim as the first thing they read.** They arrive at the review screen wanting one question answered — *what did this lap actually do?* — and you are the agent best placed to answer it: you ran last, you hold the spec, and you have every implementer's own account above.
|
|
143
178
|
|
|
144
179
|
So write **prose**, roughly 10–15 lines, for a reader who has none of your context:
|
|
145
180
|
|
|
146
181
|
- **What the lap delivered**, in the language of the product, not the codebase. "The tickets ledger and the notes panel now group by lap, with prior laps collapsed" — not "modified TicketList.tsx and NotesPanel.tsx".
|
|
147
182
|
- **Synthesize, don't enumerate.** Not a ticket-by-ticket walk, not a changed-files list, not a commit log — those all exist elsewhere on the page. Say what the lap adds up to, and where the shape that landed differs from what the spec promised.
|
|
148
|
-
- **Say what it means for them**: what they can now do that they could not before, and what is worth their attention — the thing the drive was rough at, the deferred scope, the criterion you could not verify.
|
|
183
|
+
- **Say what it means for them**: what they can now do that they could not before, and what is worth their attention — the thing the drive was rough at, the deferred scope, the criterion you could not verify. In Gates mode, say whether the gates passed and the worst issue *within each axis* — never one winner across the two. If the drive never started, say `could not drive: <reason>` in those words, so the human knows at a glance why there is no walkthrough to watch.
|
|
149
184
|
- **Plain sentences.** No headings, no bullet lists, no "I did X then Y", no tool names, no `<promise>` markers, no acceptance-criteria checklists. If it reads like an agent's log, rewrite it as something you would say out loud.
|
|
150
185
|
|
|
151
|
-
Findings belong in the
|
|
186
|
+
Findings belong in `report_finding`, not here — your observations are rendered under this prose on the same page, so repeating them costs the reader twice. One honest line about the headline problem is right; the catalogue is not.
|
|
152
187
|
|
|
153
188
|
Write it at that path and nowhere else — **never inside the repo**, which is the human's real working tree. This is the last thing you do before signalling COMPLETE.
|
|
154
189
|
|
|
155
190
|
## Could not review
|
|
156
191
|
|
|
157
|
-
The bar is
|
|
192
|
+
The bar is high, because Gates mode needs almost nothing: no app, no browser, no drive slot. Finding bugs is not failure, and **neither is a drive that would not start** — that is an observation, a switch to Gates mode, and a line in the digest.
|
|
158
193
|
|
|
159
|
-
The review **failed** only when
|
|
194
|
+
The review **failed** only when Gates mode itself could not run and so there was nowhere to fall back to:
|
|
160
195
|
|
|
161
196
|
- the repository is unreadable, or `{{BASE_BRANCH}}` / `{{FEATURE_BRANCH}}` cannot be resolved at all,
|
|
162
|
-
- `git diff {{BASE_BRANCH}}...{{FEATURE_BRANCH}}` is empty *and* `{{FEATURE_BRANCH}}` does not exist. An empty diff on a branch that does exist is a **finding**, not a failed review —
|
|
197
|
+
- `git diff {{BASE_BRANCH}}...{{FEATURE_BRANCH}}` is empty *and* `{{FEATURE_BRANCH}}` does not exist. An empty diff on a branch that does exist is a **finding**, not a failed review — report it and carry on.
|
|
163
198
|
|
|
164
|
-
When that happens: run the step
|
|
199
|
+
When that happens: run the step 4 cleanup for whatever you got as far as starting — recorder, browser, drive — write **`{{BLOCKED_PATH}}`** — that path, not the repo — saying in one or two sentences precisely what stopped you, and print `<promise>COMPLETE</promise>`. Write no digest; the blocked file is your record. Do not report findings speculating about a feature you never saw.
|
|
165
200
|
|
|
166
201
|
## Hard rules
|
|
167
202
|
|
|
168
|
-
- **Never
|
|
203
|
+
- **Never run both modes.** Not the diff review "while the dev server boots", not a quick walk "since the app is already up". One mode, chosen in step 1, for the whole review — the reviews that broke this rule are why it exists.
|
|
204
|
+
- **Never skip the review.** Every lap gets one of the two modes, whatever the ticket asks for and whether or not the app can be driven. A lap nobody reviewed is the silence this ticket exists to end.
|
|
169
205
|
- **Never edit the repo.** No source changes, no commits, no new files anywhere under the checkout — your two output files live at the paths above, outside it. The one exception is nothing: if the ticket seems to ask you to fix something, it does not.
|
|
170
206
|
- **Never merge or re-rank the two review axes**, and never report a finding without its citation.
|
|
171
207
|
- **Never let a sub-agent spawn more agents.** The guard line goes in both briefs, every time.
|
|
172
|
-
- **Never leave the drive — or the recorder — running.** Stop both on every path, including the
|
|
173
|
-
- **Never
|
|
174
|
-
- **Never
|
|
175
|
-
- **
|
|
208
|
+
- **Never leave the drive — or the recorder — running.** Stop both on every path, including the one where you gave up on the drive.
|
|
209
|
+
- **Never build your own environment.** No worktrees, no dependency installs, no builds, no generated artifacts. If `review_drive` did not hand you the app, the drive did not happen: say `could not drive: <reason>`, run Gates mode — the repo's verify commands and the diff — and leave it there.
|
|
210
|
+
- **Never report a finding you did not observe.** Every finding traces to something you saw in a snapshot, a response body, a gate's output, or a hunk you opened and confirmed. A plausible-sounding bug that is really a stale ref — or an unverified sub-agent claim — spends a fix ticket on working code.
|
|
211
|
+
- **Never report a defect without a repro step**, and never one you would not stake a code change on. If it does not reproduce, it is an observation.
|
|
212
|
+
- **Never write the digest as a log.** After its mode line it is the lap's prose summary, and it is rendered verbatim to the human.
|
|
213
|
+
- **Stay inside this ticket.** Review what it names and the lap it landed. Adjacent things you notice are observations, not a sprawl of speculative defects.
|
|
@@ -40,9 +40,11 @@ Give each ticket its **blocking edges** — the tickets that must finish before
|
|
|
40
40
|
<review-ticket>
|
|
41
41
|
Close the batch with **one review ticket** (`kind: "review"`), blocked by every implementation ticket in it. It is not a slice: it is the prose brief for the agent that exercises the *integrated* feature at the tail of the burn, on the feature branch, and writes what it finds as test notes for the human's review phase. Its `goal` says what to verify and its `acceptanceCriteria` are the things to check off, one per behaviour worth confirming — the review agent walks them in order.
|
|
42
42
|
|
|
43
|
-
**Every batch closes with one, unconditionally.** Not "when there is something to exercise" — every batch, no exceptions, exactly one (more per feature comes later).
|
|
43
|
+
**Every batch closes with one, unconditionally.** Not "when there is something to exercise" — every batch, no exceptions, exactly one (more per feature comes later). Whatever the lap turned out to be, there is always a review the agent can run: a diff is the one thing every batch produces by definition. A lap that ships without a review ticket is a lap nobody looked at, and its absence is invisible on the review page — which is precisely the silence this rule exists to end.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
The agent reviews in **exactly one of two modes**, never both — a browser **Drive** of the app against your acceptance criteria, or **Gates**: the project's verify commands plus a two-axis read of the diff. Reviews that attempted both ran long or died having delivered neither, so the burner prompt makes the agent choose up front and spend the whole review inside the choice.
|
|
46
|
+
|
|
47
|
+
Your job is to make that choice obvious. Prescribe a walkthrough only when there is genuinely a surface to walk, in plain prose ("open the settings flow, add a project, check the empty state"), and write the `acceptanceCriteria` as the steps of that walk. When the lap changed nothing a human could drive — prompt contracts, docs, an internal refactor, a backend-only change — say so in the ticket, and write criteria the gates-and-diff mode can actually check off. Do not ask for both; do not ask for a browser walk of something with no UI.
|
|
46
48
|
|
|
47
49
|
The review agent never edits code, so its ticket needs no `seams` beyond the surface it exercises, and finding bugs is a *successful* review — the notes are the deliverable. Its digest is the other one: the agent writes the lap's "What landed this lap" prose summary there, and the review page renders it as the lead of the review card, so `goal` should ask for the verification, not for the summary — that part is the burner's standing contract.
|
|
48
50
|
</review-ticket>
|