runcastle 1.3.2 → 1.3.4
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/bin/runcastle.js +1069 -668
- package/drizzle/0035_feature_tickets_ready_lap.sql +1 -0
- package/drizzle/0036_project_drive_instructions.sql +1 -0
- package/drizzle/meta/0036_snapshot.json +1128 -0
- package/drizzle/meta/_journal.json +7 -0
- package/index.js +1062 -645
- package/package.json +1 -1
- package/skills/burner/review-ticket.md +22 -8
- package/skills/burner/verify-fixes.md +9 -1
- package/skills/packs/runcastle/skills/prepare/SKILL.md +5 -1
- package/skills/packs/runcastle/skills/tickets/SKILL.md +2 -0
- package/web/assets/index-CgCA-f62.js +186 -0
- package/web/assets/index-D697YlOb.css +1 -0
- package/web/index.html +2 -2
- package/web/assets/index-CqM7LtBd.css +0 -1
- package/web/assets/index-Dr6YNyo1.js +0 -145
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ You review it in **exactly one of two modes**, and you pick which before you do
|
|
|
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 leave two deliverables behind: the **findings** (one report per finding, typed) and the **digest** (the lap's
|
|
14
|
+
You leave two deliverables behind: the **findings** (one report per finding, typed) and the **digest** (the lap's account — see step 5; it is not an afterthought). Its first line is a standalone one-liner naming the lap, what landed, the counts and the mode you ran: that line is the one the review page renders on arrival, and the account behind it is what the human opens when they want more.
|
|
15
15
|
|
|
16
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.
|
|
17
17
|
|
|
@@ -68,6 +68,8 @@ Both yes → **Drive mode**, step 2a. Anything else → **Gates mode**, step 2b.
|
|
|
68
68
|
|
|
69
69
|
### 2a. Drive mode — walk the app
|
|
70
70
|
|
|
71
|
+
{{DRIVE_INSTRUCTIONS}}
|
|
72
|
+
|
|
71
73
|
**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.
|
|
72
74
|
|
|
73
75
|
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.
|
|
@@ -152,13 +154,17 @@ mcp__runcastle__report_finding({
|
|
|
152
154
|
|
|
153
155
|
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
156
|
|
|
155
|
-
|
|
157
|
+
**A finding is a `defect` when the human's problem is not actually solved** — even when every acceptance criterion passes. The criteria describe the change that was asked for; the defect boundary is the outcome the human wanted. The canonical case, from a real project: the fix lands correctly at the store seam, but the controller endpoint builds its own response map and never calls the repaired path, so the operator-facing surface shows exactly what it showed before. Every criterion passes and the problem is untouched — that is a defect, and its `reproStep` is the human's own path to the unchanged surface.
|
|
158
|
+
|
|
159
|
+
A defect is also what a fix ticket can act on, so it carries something to act *from*: 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.
|
|
156
160
|
|
|
157
|
-
|
|
161
|
+
**`observation` is everything else**, and that is a narrow bucket: your summary of the pass, scope deliberately deferred, something you could not verify, a warning that a surface is only half built, and findings that are clearly inert — an environment quirk like "no local Maven on the host", metric drift trivia. **Unsure whether the human's problem is solved → defect.** Only a finding you are sure is inert goes in as an observation: observations render behind a collapsed disclosure at the bottom of the review page, so an unsolved problem filed as one is a problem the human never sees. A false defect costs a fix ticket; a misfiled real one costs the feature.
|
|
162
|
+
|
|
163
|
+
**Severity is `high` when an acceptance criterion is unmet, when data/flow is broken, or when every criterion passes and the human's problem is still not solved**; `medium` for a real defect that is not that, `low` for the rest. It orders and labels; it never gates.
|
|
158
164
|
|
|
159
165
|
**Report defects highest severity first.** Each defect mints a fix ticket that burns in this same run, and only the first {{AUTO_FIX_CAP}} do — everything after the cap is stored for the human to decide on, so the order you report in decides what gets fixed.
|
|
160
166
|
|
|
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
|
|
167
|
+
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 inside the page's collapsed *Full account* disclosure, alongside the digest's long account.
|
|
162
168
|
|
|
163
169
|
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.
|
|
164
170
|
|
|
@@ -172,9 +178,17 @@ At exactly:
|
|
|
172
178
|
|
|
173
179
|
`{{DIGEST_PATH}}`
|
|
174
180
|
|
|
175
|
-
**Open with one short line naming the mode**,
|
|
181
|
+
**Open with one short line naming the mode**, the lap, what it landed and the counts — a single standalone line, then a blank line, then the rest. The review page lifts that first line out and renders it alone as the lap account, so it has to stand on its own: one line, no heading, no markdown, no lead-in, and nothing that reads as half a sentence needing the paragraph after it.
|
|
182
|
+
|
|
183
|
+
Its shape — `Lap <N>: <what landed, in the language of the product> · <X> defects found, <Y> fixed in-run · <Drive|Gates> mode`:
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
Lap 2: the review page now opens on state and one action · 3 defects found, 2 fixed in-run · Gates mode
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The counts are the ones you know as you write: how many defects you reported, and how many of those fall inside the auto-fix cap and so burn as fix tickets in this same run. The lap number is `lap` on `mcp__runcastle__get_feature_context`. If you could not drive, the line still names the mode you actually ran.
|
|
176
190
|
|
|
177
|
-
**The rest is not a review log. It is the lap's
|
|
191
|
+
**The rest is not a review log. It is the lap's long account**, and the page keeps it behind a collapsed *Full account* disclosure at the bottom, with your observations — it is what the human opens when the one-liner is not enough, so it is neither the first thing they read nor rendered verbatim at the top. Write it anyway and write it well: they arrive 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.
|
|
178
192
|
|
|
179
193
|
So write **prose**, roughly 10–15 lines, for a reader who has none of your context:
|
|
180
194
|
|
|
@@ -183,7 +197,7 @@ So write **prose**, roughly 10–15 lines, for a reader who has none of your con
|
|
|
183
197
|
- **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.
|
|
184
198
|
- **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.
|
|
185
199
|
|
|
186
|
-
Findings belong in `report_finding`, not here — your observations
|
|
200
|
+
Findings belong in `report_finding`, not here — your observations sit inside the same disclosure as this prose, so repeating them costs the reader twice. One honest line about the headline problem is right; the catalogue is not.
|
|
187
201
|
|
|
188
202
|
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.
|
|
189
203
|
|
|
@@ -209,5 +223,5 @@ When that happens: run the step 4 cleanup for whatever you got as far as startin
|
|
|
209
223
|
- **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
224
|
- **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
225
|
- **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.**
|
|
226
|
+
- **Never write the digest as a log.** Its first line is the standalone lap account the page renders on arrival; after it comes the lap's prose summary, which the human opens behind a disclosure.
|
|
213
227
|
- **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.
|
|
@@ -4,6 +4,12 @@ You are running a bounded verification pass on `{{FEATURE_BRANCH}}` against `{{B
|
|
|
4
4
|
|
|
5
5
|
{{DRIVE_AVAILABILITY}}
|
|
6
6
|
|
|
7
|
+
## How you run
|
|
8
|
+
|
|
9
|
+
You run **non-interactively** — your agent CLI in print/exec mode, no terminal, no human. So:
|
|
10
|
+
|
|
11
|
+
- **Signal completion.** Print exactly `<promise>COMPLETE</promise>` as the last line of your final message, whether the pass went well or you could not run it at all. It is the only completion signal there is, and it is read from your message — a marker written into a file is invisible, and without one in your message this same pass runs again from the top.
|
|
12
|
+
|
|
7
13
|
## What landed
|
|
8
14
|
|
|
9
15
|
{{LANDED_FIXES}}
|
|
@@ -30,10 +36,12 @@ Run digests:
|
|
|
30
36
|
|
|
31
37
|
In **Drive mode**, call `mcp__runcastle__review_drive({ action: "start" })`, start the recorder at `{{WALKTHROUGH_PATH}}`, and walk every acceptance criterion's user-facing surface once at pace. Keep the recorder running for the whole tour. Scrutinise only the landed fixes: check whether each listed repro step still reproduces and inspect the surfaces those fixes touched. Report anything plainly broken during the tour, but do not hunt for unrelated defects. Stop the recorder and drive when finished.
|
|
32
38
|
|
|
39
|
+
{{DRIVE_INSTRUCTIONS}}
|
|
40
|
+
|
|
33
41
|
In **Gates mode**, read each fix diff against its finding and run the configured gates exactly once. Do not perform a second two-axis review of the whole branch.
|
|
34
42
|
|
|
35
43
|
{{GATE_NOTES}}
|
|
36
44
|
|
|
37
45
|
Report findings through `mcp__runcastle__report_finding` as usual. Verification findings remain open for the human and never mint fix tickets. The ordinary review auto-fix cap is {{AUTO_FIX_CAP}}.
|
|
38
46
|
|
|
39
|
-
Write `{{DIGEST_PATH}}`. Its first line must name the inherited mode and say "verification pass" (for example, `Drive verification pass`). Summarise which fixes held, which did not, and anything plainly broken on the tour. If the pass cannot run at all, write `{{BLOCKED_PATH}}` with the precise reason instead.
|
|
47
|
+
Write `{{DIGEST_PATH}}`. Its first line must name the inherited mode and say "verification pass" (for example, `Drive verification pass`). Summarise which fixes held, which did not, and anything plainly broken on the tour. No `<promise>` markers inside the digest — the completion signal is a line in your message, never a line in this file. If the pass cannot run at all, write `{{BLOCKED_PATH}}` with the precise reason instead. Either way, the file you write is the last thing you do before signalling COMPLETE.
|
|
@@ -19,7 +19,7 @@ Your system prompt carries the per-session facts — the repo path, which keys a
|
|
|
19
19
|
|
|
20
20
|
**Ask before you act.** Anything that starts or stops a service, creates or migrates a database, installs software, or writes outside the repo needs the human to agree first: say what you are about to run and why, then wait. Their own stack is running next to yours.
|
|
21
21
|
|
|
22
|
-
## The
|
|
22
|
+
## The eight keys
|
|
23
23
|
|
|
24
24
|
Four describe the drive loop and can only be settled here:
|
|
25
25
|
|
|
@@ -33,6 +33,10 @@ Three describe the **sandbox** a burn agent works in, and no amount of running t
|
|
|
33
33
|
- **`verifyCommands`** — the exact typecheck/test/lint lines a burn agent should use, one per line. Unset, agents guess workspace filter names and burn whole suite runs discovering the right one.
|
|
34
34
|
- **`knownFailures`** — what already fails on the main branch, so an agent can tell its own breakage from the repo's. Free text; a count plus the suite names is enough.
|
|
35
35
|
|
|
36
|
+
The eighth is what a later agent needs once the app is actually up:
|
|
37
|
+
|
|
38
|
+
- **`driveInstructions`** — free text describing how to **exercise** this app in a drive, injected verbatim into every drive-mode review and verification prompt. What belongs in it: the sample project, seeded account or scratch data a driver should use and may freely change; how to reach the deep states worth reviewing rather than only the front page; and what a driver may and may not touch inside the running app. Write it as standing instructions from the project's owner — they authorize actions *inside the app under test* and nothing else, so do not write anything meant to relax a reviewing agent's own rules. Its evidence is the dry-run drive below: you just drove this app, so record what you had to know to get anywhere. Unset, a review agent boots the app cold, finds nothing it is allowed to touch, and verifies nothing.
|
|
39
|
+
|
|
36
40
|
## The drive contract
|
|
37
41
|
|
|
38
42
|
A drive is a script **you** write, committed to the project, plus the two things only the server can do. Everything else — ports, database names, redis indexes, compose project names, URLs — the script computes for itself. Runcastle mandates these seven points and nothing else:
|
|
@@ -42,6 +42,8 @@ Close the batch with **one review ticket** (`kind: "review"`), blocked by every
|
|
|
42
42
|
|
|
43
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
|
+
The server enforces this too, so a refusal here is the seatbelt working, not a bug: G3 refuses a lap whose tickets include no `kind: "review"` one, and `emit_tickets` refuses a batch outright when a ticket is *titled* like the review but carries another kind — set the kind (or retitle it) and re-emit.
|
|
46
|
+
|
|
45
47
|
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
48
|
|
|
47
49
|
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.
|