@juzser/blacksmith 0.2.0 → 0.4.0
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/.claude/agents/auditor.md +3 -0
- package/.claude/agents/grader.md +12 -5
- package/.claude/agents/reviewer.md +3 -0
- package/.claude/agents/security-reviewer.md +3 -0
- package/.claude/agents/spec-reviewer.md +3 -0
- package/.claude/agents/verifier.md +3 -0
- package/.claude/skills/bs/audit.md +25 -9
- package/.claude/skills/bs/dispatch.md +60 -7
- package/.claude/skills/bs/plan.md +33 -1
- package/.claude/skills/bs/run.md +18 -13
- package/.claude/skills/bs/wave.md +68 -10
- package/README.md +4 -4
- package/factory/orchestrator/dist/agentsSync.js +178 -0
- package/factory/orchestrator/dist/audit.js +134 -17
- package/factory/orchestrator/dist/autonomy.js +25 -0
- package/factory/orchestrator/dist/budgets.js +91 -2
- package/factory/orchestrator/dist/claims.js +8 -4
- package/factory/orchestrator/dist/cli.js +394 -26
- package/factory/orchestrator/dist/crossFinding.js +20 -0
- package/factory/orchestrator/dist/daemon.js +230 -41
- package/factory/orchestrator/dist/db/projector.js +93 -36
- package/factory/orchestrator/dist/db/queries.js +58 -35
- package/factory/orchestrator/dist/db/schema.js +24 -0
- package/factory/orchestrator/dist/dispatchAudit.js +10 -2
- package/factory/orchestrator/dist/dispatchLint.js +132 -0
- package/factory/orchestrator/dist/epic.js +192 -39
- package/factory/orchestrator/dist/epicWidth.js +25 -20
- package/factory/orchestrator/dist/errorIssues.js +209 -24
- package/factory/orchestrator/dist/eventOrder.js +102 -0
- package/factory/orchestrator/dist/events.js +73 -91
- package/factory/orchestrator/dist/findingContext.js +1 -13
- package/factory/orchestrator/dist/findings.js +132 -11
- package/factory/orchestrator/dist/gh.js +29 -6
- package/factory/orchestrator/dist/git.js +20 -2
- package/factory/orchestrator/dist/harness.js +92 -10
- package/factory/orchestrator/dist/hookDecision.js +320 -37
- package/factory/orchestrator/dist/impact.js +24 -2
- package/factory/orchestrator/dist/integration.js +11 -1
- package/factory/orchestrator/dist/issueReporter.js +415 -0
- package/factory/orchestrator/dist/judgeStopHook.js +181 -0
- package/factory/orchestrator/dist/judges.js +1 -1
- package/factory/orchestrator/dist/lessons.js +46 -18
- package/factory/orchestrator/dist/logCache.js +291 -0
- package/factory/orchestrator/dist/paths.js +10 -0
- package/factory/orchestrator/dist/plan.js +138 -4
- package/factory/orchestrator/dist/planQuorum.js +1 -1
- package/factory/orchestrator/dist/policy.js +57 -11
- package/factory/orchestrator/dist/projects.js +12 -1
- package/factory/orchestrator/dist/queue.js +477 -29
- package/factory/orchestrator/dist/scheduler.js +51 -0
- package/factory/orchestrator/dist/severity.js +40 -8
- package/factory/orchestrator/dist/spec.js +70 -0
- package/factory/orchestrator/dist/taskEvents.js +13 -4
- package/factory/orchestrator/dist/taskStatus.js +74 -0
- package/factory/orchestrator/dist/taxonomy.js +11 -0
- package/factory/orchestrator/dist/testgate.js +32 -3
- package/factory/orchestrator/dist/usage.js +42 -9
- package/factory/orchestrator/dist/waivers.js +60 -9
- package/factory/orchestrator/dist/waveConcurrency.js +29 -0
- package/factory/orchestrator/dist/waveNext.js +12 -10
- package/factory/orchestrator/dist/waveSchedule.js +84 -0
- package/factory/orchestrator/dist/worktree.js +19 -6
- package/factory/orchestrator/drizzle/0012_issue_reports_error_issues.sql +20 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +7 -0
- package/factory/policies/budgets.yml +9 -2
- package/factory/policies/crosscheck.yml +2 -2
- package/factory/policies/lessons.md +298 -0
- package/factory/policies/scheduler.yml +27 -2
- package/factory/policies/taxonomy.yml +10 -3
- package/factory/specs/roadmap.md +70 -23
- package/package.json +8 -8
|
@@ -5,6 +5,9 @@ model: sonnet
|
|
|
5
5
|
effort: high
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Auditor
|
package/.claude/agents/grader.md
CHANGED
|
@@ -5,6 +5,9 @@ model: sonnet
|
|
|
5
5
|
effort: low
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Grader
|
|
@@ -43,7 +46,9 @@ edit does not save a round-trip, it costs the whole one.
|
|
|
43
46
|
rubric — nothing broader.
|
|
44
47
|
- Bounce back to the worker with specific, itemized gaps (not vibes).
|
|
45
48
|
- **Max 2 rounds.** After that, pass whatever exists through to the gates —
|
|
46
|
-
the gates, not the grader, decide final pass/fail.
|
|
49
|
+
the gates, not the grader, decide final pass/fail. The re-scope path after a
|
|
50
|
+
round-2 `fail` is `.claude/skills/bs/dispatch.md`'s "Round counting and
|
|
51
|
+
escalation" — read it there rather than here.
|
|
47
52
|
- Grader never edits code and never talks to the operator.
|
|
48
53
|
- **Never compact your context** (`budgets.yml` `context_window`,
|
|
49
54
|
`narrowing_roles`). You grade evidence rather than build on it; a
|
|
@@ -101,10 +106,12 @@ harness counts the tokens; the dispatcher stamps them.
|
|
|
101
106
|
{"status": "done", "overall": "fail", "round": 2, "artifact_path": "state/results/<task-id>.grader-r2.json"}
|
|
102
107
|
```
|
|
103
108
|
|
|
104
|
-
Two rounds is a hard stop, not a suggestion. A `fail` at round 2
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
Two rounds is a hard stop, not a suggestion. A `fail` at round 2 is re-scoped
|
|
110
|
+
through dispatch.md's "Round counting and escalation" (plan propose/approve a
|
|
111
|
+
successor task id, then `worktree create --from`); you do not open round 3 on
|
|
112
|
+
this id, and you do not soften the verdict to avoid the stop. The schema caps
|
|
113
|
+
`round` at 2, so a round-3 file does not quietly pass the gate — it blocks it
|
|
114
|
+
as invalid.
|
|
108
115
|
|
|
109
116
|
## What the gate does with this file
|
|
110
117
|
|
|
@@ -5,6 +5,9 @@ model: sonnet
|
|
|
5
5
|
effort: medium
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Reviewer
|
|
@@ -5,6 +5,9 @@ model: sonnet
|
|
|
5
5
|
effort: high
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Security Reviewer
|
|
@@ -5,6 +5,9 @@ model: sonnet
|
|
|
5
5
|
effort: high
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Spec Reviewer
|
|
@@ -5,6 +5,9 @@ model: opus
|
|
|
5
5
|
effort: xhigh
|
|
6
6
|
tools: Read, Grep, Glob, Bash
|
|
7
7
|
maxTurns: 15
|
|
8
|
+
hooks:
|
|
9
|
+
Stop:
|
|
10
|
+
- hooks: [{type: command, command: "[ -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" ] && \"$CLAUDE_PROJECT_DIR/.claude/hooks/judge-stop.sh\" || exit 0"}]
|
|
8
11
|
---
|
|
9
12
|
|
|
10
13
|
# Verifier
|
|
@@ -218,10 +218,19 @@ smith audit cut <project-dir> --epic <epic-id> --title "<milestone title>" \
|
|
|
218
218
|
```
|
|
219
219
|
|
|
220
220
|
It stamps the epic id onto every accepted finding, emits `audit-cut`,
|
|
221
|
-
and prints two strings; **it edits no file**.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
221
|
+
and prints two strings; **it edits no file**. Both belong to the audited
|
|
222
|
+
project, so both are written under the **work root** of step 1 and never
|
|
223
|
+
into the factory's own checkout: paste `milestone` into
|
|
224
|
+
`<work-root>/factory/specs/roadmap.md` as the next milestone block — it
|
|
225
|
+
already carries `- project: <basename>` and `- kind: product` — and write
|
|
226
|
+
`spec` to `<work-root>/factory/specs/active/<epic-id>/epic-spec.md`. If
|
|
227
|
+
that roadmap does not exist yet, create it: the parser
|
|
228
|
+
(`factory/orchestrator/src/roadmap.ts`) asks only that milestones be `##`
|
|
229
|
+
blocks, so a title line above the first one is a whole file. A milestone
|
|
230
|
+
for someone else's project is a declaration *they* made, and a factory
|
|
231
|
+
that keeps those in its own repository ships them to everyone who clones
|
|
232
|
+
it — which is also what step 7's `.gitignore` question is about, since
|
|
233
|
+
the work root is where these two files now live. `audit.nothing-accepted`
|
|
225
234
|
means step 7 accepted nothing: there is no epic to cut, and closing is
|
|
226
235
|
the right next move. One audit cuts one epic; findings accepted after a
|
|
227
236
|
cut belong to the next audit's cut, not to a second cut from this one.
|
|
@@ -245,8 +254,15 @@ is already gone closes with `verified: false` and no refusal.
|
|
|
245
254
|
The epic is now an ordinary roadmap milestone: run `/bs plan` on it
|
|
246
255
|
([`plan.md`](plan.md)), then `/bs run`. When that run reaches its epic-close
|
|
247
256
|
step, it runs
|
|
248
|
-
`smith audit resolve <project-dir> --epic <epic-id> --session <session-id> --causal-parent <event-id
|
|
249
|
-
which appends `fixed` for
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
257
|
+
`smith audit resolve <project-dir> --epic <epic-id> --session <session-id> --causal-parent <event-id> [--specs-dir <dir>]`,
|
|
258
|
+
which reads the epic's newest plan and appends `fixed` only for a carried
|
|
259
|
+
finding some task in it still claims — the rest come back `deferred`, still
|
|
260
|
+
`accepted`, because the plan scoped them out on purpose. Repeatable;
|
|
261
|
+
`audit.unknown-epic` if the id was never cut from this store, `audit.no-plan`
|
|
262
|
+
if no plan can be found (refuses rather than guess). The default search is
|
|
263
|
+
the work root's specs dir; when this project's plans live elsewhere, pass
|
|
264
|
+
`--specs-dir` naming the same specs dir the epic was run from. `--except
|
|
265
|
+
<fp[,fp...]>` forces specific fingerprints into `deferred` even when a task
|
|
266
|
+
claims them. That is the only step of an audit that runs outside this
|
|
267
|
+
playbook, and it is why the store, not this transcript, is where a finding's
|
|
268
|
+
life is kept.
|
|
@@ -11,7 +11,7 @@ task spec or the one question · the **absolute** worktree path · the path
|
|
|
11
11
|
claims it may touch · its token cap · **its turn budget, copied verbatim
|
|
12
12
|
from the template's `maxTurns`**. That last one is why it is listed: Claude
|
|
13
13
|
Code enforces the template's `maxTurns` on every `Agent`-tool dispatch
|
|
14
|
-
(dogfood-
|
|
14
|
+
(measured on two dogfood runs, 2026-09-07 and 2026-09-11),
|
|
15
15
|
and the agent cannot see how many turns it has left. A prompt that promises
|
|
16
16
|
more than the template is a fiction the agent plans against and gets cut in
|
|
17
17
|
the middle of (a planner told 40 under a template saying 20 stopped twice
|
|
@@ -19,6 +19,22 @@ with nothing written). So state the template's number, never a higher one,
|
|
|
19
19
|
and tell every role that owes a file to write it before it refines it. A
|
|
20
20
|
role that keeps running out is a template to raise, not a prompt to inflate.
|
|
21
21
|
|
|
22
|
+
Read that number from `.claude/agents/<role>.md` as the file stands now, at
|
|
23
|
+
dispatch time — not from memory, an earlier dispatch, or a doc that quotes
|
|
24
|
+
it. `smith agents sync` may have rewritten it locally from
|
|
25
|
+
`SMITH_MAXTURNS_<ROLE>` (an uncommitted, per-box edit), and Claude Code
|
|
26
|
+
enforces what the file says. A sync reaches only agents spawned after it.
|
|
27
|
+
|
|
28
|
+
State it on its own line, verbatim — `Turn budget: 40` — and, on a judge
|
|
29
|
+
dispatch, the declared-artifact line below verbatim too. `smith dispatch
|
|
30
|
+
lint <prompt-file> --role <role> --task <id> --session <id>` reads a
|
|
31
|
+
composed prompt back and checks both against the template and the ledger,
|
|
32
|
+
before the agent ever runs. It fails closed: a number that does not match
|
|
33
|
+
the template — higher (the promise-more-than-the-template mistake above) or
|
|
34
|
+
lower — a missing turn-budget line, a template it cannot read at all, and a
|
|
35
|
+
judge prompt missing or mismatching its artifact line are each a lint
|
|
36
|
+
failure, not a maybe.
|
|
37
|
+
|
|
22
38
|
## Splice the compiled lessons into every prompt (agent-interviews.md N-9, P9-2)
|
|
23
39
|
|
|
24
40
|
Before you dispatch, run
|
|
@@ -145,10 +161,30 @@ memory of its previous attempt and will happily report round 1 forever.
|
|
|
145
161
|
reason). An unlogged escalation is a cost you cannot attribute later — and
|
|
146
162
|
`model_tier` alone cannot even tell you *which* frontier model you escalated
|
|
147
163
|
to, since opus and fable share the tier.
|
|
148
|
-
- **The grader's 2-round cap is a hard stop, not a ladder rung.** At a
|
|
149
|
-
`fail` the
|
|
150
|
-
|
|
151
|
-
|
|
164
|
+
- **The grader's 2-round cap is a hard stop, not a ladder rung.** At a
|
|
165
|
+
round-2 `fail` the operator re-scopes through a concrete, logged path, not
|
|
166
|
+
a bare re-dispatch:
|
|
167
|
+
1. `smith plan propose` with a `supersede` pairing the failing task id to a
|
|
168
|
+
new one (`PlanChanges.supersede`, spec.ts's `amendPlan`) — the operator
|
|
169
|
+
approves the re-scoping, this command only records the proposal.
|
|
170
|
+
2. `smith plan approve` the proposed version. This is what writes the
|
|
171
|
+
`successors{old->new}` pairing (spec.ts's `taskSuccessors`) that
|
|
172
|
+
everything below checks against.
|
|
173
|
+
3. `smith worktree create --from <old-task-id> --session <id> ...` to cut
|
|
174
|
+
the successor's branch from the predecessor's HEAD instead of
|
|
175
|
+
integration — refused as `worktree.not-a-successor` unless step 2 logged
|
|
176
|
+
that exact pairing.
|
|
177
|
+
4. Rerun wave steps 5-7 (dispatch, review, gate) under the new task id. The
|
|
178
|
+
grader starts that id at round 1 — the ledger's round counter is per
|
|
179
|
+
`(task_id, role)`, and a new id has never opened a round.
|
|
180
|
+
5. Gate with `--plan` naming the new plan version.
|
|
181
|
+
|
|
182
|
+
A same-id re-dispatch of round 3 is never legal, superseded or not: the cap
|
|
183
|
+
binds the id, and a kept-id supersede (same task_id, new claims/criteria)
|
|
184
|
+
does not reset the round either — only a **new** task id starts a fresh
|
|
185
|
+
ledger. Do not re-dispatch the grader on the old id, and do not escalate the
|
|
186
|
+
*grader* — the gates decide pass/fail, and a third grading round on the same
|
|
187
|
+
id only buys a more expensive opinion.
|
|
152
188
|
- **Never escalate a judge to break a tie with another judge.** That is what
|
|
153
189
|
the cross-check quorum is for (`crosscheck.yml`); a bigger critic is still
|
|
154
190
|
one critic.
|
|
@@ -210,8 +246,8 @@ stamp) and `<epic>/plan-v<n>` (a plan version, the ref `plan quorum`
|
|
|
210
246
|
stamps). Anything else — `<epic>/plan-draft`, `<epic>/spec-review-r27` —
|
|
211
247
|
folds a real row that nothing can ever move on, because no planner or
|
|
212
248
|
spec-reviewer dispatch produces the `wave-merged` or `gate-outcome` that
|
|
213
|
-
would: twenty-one of
|
|
214
|
-
|
|
249
|
+
would: on one dogfooded product epic, twenty-one of its twenty-four
|
|
250
|
+
non-terminal rows were these.
|
|
215
251
|
|
|
216
252
|
So: the closing spec-reviewer, the goal-check spec-reviewer, the planner
|
|
217
253
|
rendering a verdict and the scribe are dispatched against
|
|
@@ -318,6 +354,12 @@ true one on the record. `--no-findings` records an operator
|
|
|
318
354
|
*attestation* rather than a review — use it only for a judge that ran outside
|
|
319
355
|
the factory; a judge that genuinely found nothing writes `[]` and reports.
|
|
320
356
|
|
|
357
|
+
Tell the judge the exact path on its own line, verbatim —
|
|
358
|
+
`Declared artifact: /abs/path/<task-id>.reviewer.json` — the spelling `smith
|
|
359
|
+
dispatch lint` checks the composed prompt against once the dispatch above
|
|
360
|
+
has landed in the ledger. Missing, relative, or a path that does not match
|
|
361
|
+
what `--artifact` declared are each a lint failure, not a maybe.
|
|
362
|
+
|
|
321
363
|
## Dispatching the security-reviewer (agent-interviews.md N-7)
|
|
322
364
|
|
|
323
365
|
Do not eyeball the path list — ask:
|
|
@@ -347,6 +389,17 @@ exceptions — today one, `wave-runner` — and each of them earns it by opening
|
|
|
347
389
|
session of its own against your dispatch's event id before it dispatches
|
|
348
390
|
anything.
|
|
349
391
|
|
|
392
|
+
Run `smith issues report --session <session-id> --state-dir <dir> [--epic
|
|
393
|
+
<id>]` right after any of the three things this log can hold: the
|
|
394
|
+
`error-logged` you just wrote, a `gate-outcome` that `smith gate run` records
|
|
395
|
+
with outcome `blocked`, or a `task-added` whose payload sets `task_status:
|
|
396
|
+
failed`. The reporting verb re-reads the whole session lineage log and folds
|
|
397
|
+
all three source event types, so calling it once after any of them covers
|
|
398
|
+
the others too; a repeated call over the same error finds the recorded
|
|
399
|
+
`issue-reported` outcome and moves on, so calling it again is never a
|
|
400
|
+
mistake. A non-zero exit is logged and does not fail the dispatch that owns
|
|
401
|
+
this log; the run keeps going.
|
|
402
|
+
|
|
350
403
|
## The task id goes on the event, not in the payload
|
|
351
404
|
|
|
352
405
|
`smith event append` reads `task_id` at the top level of the JSON, beside
|
|
@@ -44,7 +44,26 @@ there means "not looked at", not "looked at and clean".
|
|
|
44
44
|
— a *different model* than the planner's, per its own frontmatter — to
|
|
45
45
|
hunt spec gaps/ambiguities/missing-nonfunctional clauses
|
|
46
46
|
(`docs/standards/agent-constraints.md` "planner"; `severity.yml`: most
|
|
47
|
-
spec gaps land S2, blocking sign-off).
|
|
47
|
+
spec gaps land S2, blocking sign-off). Name the review focus in the
|
|
48
|
+
dispatch itself, as a short list of at most six items, so findings come
|
|
49
|
+
back tagged to one of them:
|
|
50
|
+
|
|
51
|
+
1. Claims and dependency edges, cross-checked against
|
|
52
|
+
`smith claims impact`.
|
|
53
|
+
2. TDD-ability -- a named failing test per task, before its code.
|
|
54
|
+
3. Nonfunctional and security clauses.
|
|
55
|
+
4. Budget and diff-cap fit.
|
|
56
|
+
5. Acceptance-criterion coverage -- every epic criterion maps to a task.
|
|
57
|
+
6. From round 2 on, only the previous round's findings plus any task
|
|
58
|
+
that changed since then.
|
|
59
|
+
|
|
60
|
+
When `size.small` reads true on the draft (`smith wave schedule` or
|
|
61
|
+
`smith plan ingest`'s `parallelism.size`, run against the draft plan
|
|
62
|
+
file), recommend effort tier `small` -- single-pass spec review -- to
|
|
63
|
+
the operator unless a security trigger floors it first, and say why in
|
|
64
|
+
the same message: a plan that cannot spread past a few tasks and a
|
|
65
|
+
handful of claim paths does not need a second review round to find what
|
|
66
|
+
one pass already covers.
|
|
48
67
|
4. Planner fixes flagged issues; repeat 2–3 until the spec-reviewer has
|
|
49
68
|
nothing S1/S2 left — or exactly once when `profile.specReviewRounds` is
|
|
50
69
|
`single-pass` (`small`), where the planner fixes what came back and
|
|
@@ -127,6 +146,11 @@ there means "not looked at", not "looked at and clean".
|
|
|
127
146
|
decide whether to re-slice, and say which you chose when you present the
|
|
128
147
|
plan.
|
|
129
148
|
|
|
149
|
+
The same JSON also carries `size` -- `{tasks, claims, small}` over live
|
|
150
|
+
tasks only -- the block `plan ingest` prints again under `parallelism`
|
|
151
|
+
at step 7; `small` is true at or under 3 live tasks and 10 distinct
|
|
152
|
+
claim paths, and this is where the step 3 tier read gets confirmed.
|
|
153
|
+
|
|
130
154
|
Beside the schedule, the read that names what it only counts:
|
|
131
155
|
|
|
132
156
|
```bash
|
|
@@ -163,6 +187,14 @@ there means "not looked at", not "looked at and clean".
|
|
|
163
187
|
UI check found behind two epics. It is idempotent, so run it again on a
|
|
164
188
|
resumed session; read `added` and `edges` back, and say so when either is
|
|
165
189
|
0 on a plan that has tasks or edges.
|
|
190
|
+
|
|
191
|
+
Read `parallelism.widest` back from that same output, too. `parallel_with`
|
|
192
|
+
underneath it is claims-and-edges only -- import-graph crossings stay
|
|
193
|
+
`wave schedule --repo`'s job, not this key's -- so it can only ever name
|
|
194
|
+
a width that job would not contradict. A `widest` of 1 on a
|
|
195
|
+
plan of two or more tasks means every task the wave loop will ever run
|
|
196
|
+
sits behind some claim or edge that serializes it: flag that to the
|
|
197
|
+
operator now, before a run discovers it as a stalled wave.
|
|
166
198
|
8. If this epic opens a new roadmap milestone, add it to
|
|
167
199
|
`factory/specs/roadmap.md` (planner-maintained, architecture §12) — a
|
|
168
200
|
roadmap change is itself a scope change and needs the same operator nod.
|
package/.claude/skills/bs/run.md
CHANGED
|
@@ -123,8 +123,9 @@ under it, which is the wrong `--state-dir`, or a wave session opened without
|
|
|
123
123
|
done; a green gate on serialized work is exactly the outcome the two
|
|
124
124
|
playbooks are written to prevent.
|
|
125
125
|
|
|
126
|
-
11. Repeat until every task in the live plan version is
|
|
127
|
-
`
|
|
126
|
+
11. Repeat until every task in the live plan version is `completed`/`waived`,
|
|
127
|
+
or `superseded` by a successor that is itself terminal-OK (recursively —
|
|
128
|
+
a successor chain counts too). Dispatch the **`planner`** again for
|
|
128
129
|
the epic verdict against acceptance criteria — gaps found → a NEW
|
|
129
130
|
`plan-v(n+1)` with inferred tasks (never a live-graph mutation,
|
|
130
131
|
architecture §12), auto-scheduled at confidence ≥0.8 else parked for an
|
|
@@ -165,10 +166,9 @@ playbooks are written to prevent.
|
|
|
165
166
|
13-16 write. The envelope leaves the flag optional, and an omitted one
|
|
166
167
|
stamps the record `plan_version: 1` — so on an epic that amended, the
|
|
167
168
|
check, the review and the close all claim to have verified a plan that
|
|
168
|
-
no longer exists.
|
|
169
|
-
check and its closing spec review both stamped v1
|
|
170
|
-
|
|
171
|
-
the flag, says v3. Read the version off `smith plan ingest`'s receipt and
|
|
169
|
+
no longer exists. One dogfooded product epic closed at v3 with its
|
|
170
|
+
integration check and its closing spec review both stamped v1; the goal
|
|
171
|
+
check, passed the flag, said v3. Read the version off `smith plan ingest`'s receipt and
|
|
172
172
|
pass it every time.
|
|
173
173
|
13. Dispatch the **`spec-reviewer`** again — this time against the code.
|
|
174
174
|
The pre-code review at `/bs plan` step 3 read the spec against nothing;
|
|
@@ -276,8 +276,8 @@ playbooks are written to prevent.
|
|
|
276
276
|
provider is `active` in `crosscheck.yml`: codex spends the operator's
|
|
277
277
|
ChatGPT quota, DeepSeek spends prepaid credit, and step 16 runs the
|
|
278
278
|
verdict again before it writes, so a clean close is two spends, not one
|
|
279
|
-
(
|
|
280
|
-
integration ref,
|
|
279
|
+
(one dogfooded epic wrote two `quorum-decision`s against its
|
|
280
|
+
integration ref, one from the verdict and one from the close).
|
|
281
281
|
Nothing in the `quorum-decision` payload names the purse, so say which
|
|
282
282
|
one it is to the operator before the first call, not after the second.
|
|
283
283
|
16. Record the close. The verdict above is a read-only probe and writes
|
|
@@ -293,17 +293,22 @@ playbooks are written to prevent.
|
|
|
293
293
|
yourself** — closing over a hold is the operator's call; ask for it and
|
|
294
294
|
quote the blockers. If the epic was cut by `/bs audit`
|
|
295
295
|
([`audit.md`](audit.md) step 10), follow the close with
|
|
296
|
-
`smith audit resolve <project-dir> --epic <epic> --session <session-id> --causal-parent <event-id
|
|
297
|
-
so every finding
|
|
298
|
-
audit store — the
|
|
296
|
+
`smith audit resolve <project-dir> --epic <epic> --session <session-id> --causal-parent <event-id> [--specs-dir <dir>]`
|
|
297
|
+
so every finding this plan still claims is marked `fixed` in the
|
|
298
|
+
project's audit store — the rest come back `deferred`, left exactly as
|
|
299
|
+
they were, because the plan scoped them out on purpose. The store, not
|
|
300
|
+
the epic, is where a finding's life ends. `resolve` reads the epic's
|
|
301
|
+
newest plan from the work root's specs dir by default; when this
|
|
302
|
+
project's plans live elsewhere, pass `--specs-dir` naming the same specs
|
|
303
|
+
dir the epic was run from, or it refuses rather than guess.
|
|
299
304
|
17. Open **one integration PR per epic** with the scribe-written body
|
|
300
305
|
(`/bs report`'s playbook, [`report.md`](report.md)) — screenshots, test
|
|
301
306
|
results, reviewer verdict, waivers granted, timeline link. The head is
|
|
302
307
|
`smith/<epic>/integration`. The base is the target repo's `main` unless
|
|
303
308
|
the epic was cut from another epic's integration branch, in which case
|
|
304
309
|
the PR stacks on that branch and the operator merges the parent's PR
|
|
305
|
-
first —
|
|
306
|
-
|
|
310
|
+
first — a child epic cut from `smith/<parent>/integration` opens its PR
|
|
311
|
+
against that branch, behind the parent's PR; once the parent has merged
|
|
307
312
|
and its branch is deleted, GitHub retargets the child to `main`. The
|
|
308
313
|
operator reviews on GitHub; this session never merges to `main`
|
|
309
314
|
(`docs/standards/guardrails.md`).
|
|
@@ -33,6 +33,14 @@ both:
|
|
|
33
33
|
its waves, and a window spent on this wave's dispatches is a window the
|
|
34
34
|
epic does not have for the wave after next (D13).
|
|
35
35
|
|
|
36
|
+
After any `error-logged` this wave writes — a worker that died, a judge turn
|
|
37
|
+
that failed, a gate refusal recorded as an error — or a `smith gate run`
|
|
38
|
+
that came back `blocked` (its `gate-outcome` event with outcome `blocked`),
|
|
39
|
+
or a task the wave marks `failed` (its `task-added` event with payload
|
|
40
|
+
`task_status: failed`), the wave runs the reporting verb once, per
|
|
41
|
+
[`dispatch.md`](dispatch.md)'s paragraph of this same heading, which owns
|
|
42
|
+
the rule.
|
|
43
|
+
|
|
36
44
|
Which `<event-id>` depends on how you were started, and the difference is
|
|
37
45
|
not cosmetic — it is the edge an audit walks:
|
|
38
46
|
|
|
@@ -47,14 +55,27 @@ not cosmetic — it is the edge an audit walks:
|
|
|
47
55
|
anything else and the check reports you as `unverifiable` — not as a
|
|
48
56
|
pass — however well the wave ran. Open it **before** your first dispatch,
|
|
49
57
|
for the same reason: a grant is earned by owning the log first.
|
|
58
|
+
- **You are taking over a wave whose runner died or capped**: continue from
|
|
59
|
+
that runner's last event, in a session of your own. Do not write into its
|
|
60
|
+
log. One session has one author, and `smith delegation check` reads exactly
|
|
61
|
+
that: dispatches appended to a dead delegate's log by whoever picked the
|
|
62
|
+
wave up are reported as violations, correctly, because from the log's side
|
|
63
|
+
they cannot be told apart from an agent narrating its own work. Open your
|
|
64
|
+
own instead:
|
|
65
|
+
`smith session start <wave-id>-takeover --continues <dead-session>#<n>`.
|
|
66
|
+
That keeps the chain whole — the epic's folded reads still see every
|
|
67
|
+
dispatch on both sides of the handover — and it makes the takeover a fact
|
|
68
|
+
in the log rather than something a reader has to infer from two agents and
|
|
69
|
+
one timeline.
|
|
50
70
|
|
|
51
|
-
|
|
52
|
-
and `--continues` is the whole of what makes that true.
|
|
53
|
-
at the epic tier folds the lineage rather than one
|
|
54
|
-
|
|
55
|
-
`
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
Whatever the case, one rule holds: **the log you write is the log the
|
|
72
|
+
epic reads**, and `--continues` is the whole of what makes that true.
|
|
73
|
+
Every deciding read at the epic tier folds the lineage rather than one
|
|
74
|
+
session — `wave audit`, `budget alarm`, `tester check`,
|
|
75
|
+
`judge outstanding`, `escalation check`, `dispatch check`,
|
|
76
|
+
`delegation check` — so a dispatch recorded in a wave session is visible
|
|
77
|
+
from the epic session that admitted it, and is *not* visible from a
|
|
78
|
+
sibling wave's. Open a wave session without `--continues` and
|
|
58
79
|
none of those verbs can see your work: they will not error, they will answer
|
|
59
80
|
about a wave that appears never to have run.
|
|
60
81
|
|
|
@@ -126,6 +147,28 @@ one thing this playbook never asks you to.
|
|
|
126
147
|
carries `keeps_exports`, restate the promise in the dispatch in one line:
|
|
127
148
|
the file list, and "keep every existing export's name and declaration;
|
|
128
149
|
adding is fine".
|
|
150
|
+
|
|
151
|
+
Once every coder of the wave has been dispatched — this fan-out has gone
|
|
152
|
+
out for every admitted task — audit the wave's own parallelism while it
|
|
153
|
+
can still be corrected: `smith wave audit --session <id> --epic <epic>`.
|
|
154
|
+
`wave check` is the step-1 gate that certified, before any dispatch, that
|
|
155
|
+
these tasks could run together; `wave audit` reads the log back after
|
|
156
|
+
dispatch and says whether they did.
|
|
157
|
+
It is a read, so it costs nothing against "No lockstep barrier" above and
|
|
158
|
+
waits for no task. Read the `verdict` field (`WAVE_VERDICTS`,
|
|
159
|
+
`waveConcurrency.ts`), not only the exit code — `partial` also exits 0:
|
|
160
|
+
- `serialized` or `partial` — the wave is not running the width it was
|
|
161
|
+
admitted at, and steps 5–7 have not gone out yet, so it can still be
|
|
162
|
+
fixed: dispatch every remaining phase of this wave as one message of
|
|
163
|
+
parallel calls, per "One message, many dispatches" above, and record
|
|
164
|
+
the verdict as an operator-visible event — `error-logged` with error
|
|
165
|
+
`contract.constraint-decay` (`taxonomy.yml`): the wave-runner stopped
|
|
166
|
+
honoring that section's standing constraint.
|
|
167
|
+
- `unobserved` — the log holds no dispatch for any task this wave
|
|
168
|
+
admitted. That is a defect in the log, not in how the wave ran; record
|
|
169
|
+
it the same way, as `error-logged` with error `execution.env-failure`.
|
|
170
|
+
- `parallel` or `single` — nothing further; the wave ran as wide as it
|
|
171
|
+
was admitted.
|
|
129
172
|
5. Dispatch **`tester`** (`.claude/agents/tester.md`) for missing unit
|
|
130
173
|
coverage and epic-level e2e/screenshots.
|
|
131
174
|
- Then the **uiux visual pass**, but only when all three hold: the task
|
|
@@ -143,7 +186,8 @@ one thing this playbook never asks you to.
|
|
|
143
186
|
runs; it never decides pass/fail itself. At one round the grader scores
|
|
144
187
|
once and a failed criterion is the coder's bounce, not a re-grade. Its result file is an **input to
|
|
145
188
|
step 7**, not a note to the operator: pass it as `--grader` or the rubric
|
|
146
|
-
gates nothing (D-34).
|
|
189
|
+
gates nothing (D-34). A round-2 `fail` re-scopes via dispatch.md's "Round
|
|
190
|
+
counting and escalation", not a round 3 on this id.
|
|
147
191
|
7. Run the gate pipeline:
|
|
148
192
|
`smith gate run <task-id> --worktree <dir> --checks checks.json --result
|
|
149
193
|
result.json --grader state/results/<task-id>.grader-r<round>.json
|
|
@@ -217,8 +261,18 @@ one thing this playbook never asks you to.
|
|
|
217
261
|
— see "Round counting and escalation" above. Then have the log check
|
|
218
262
|
you: `smith escalation check <session-id> --task <task-id>`, which
|
|
219
263
|
exits 1 if the rung you just climbed is not evidenced.
|
|
220
|
-
10. Gate outcome `pass`/`pass-with-waivers-pending` → before admitting,
|
|
221
|
-
|
|
264
|
+
10. Gate outcome `pass`/`pass-with-waivers-pending` → before admitting, audit
|
|
265
|
+
the wave's own parallelism: `smith wave audit --session <id> --epic
|
|
266
|
+
<epic>`. It reads the log back and says whether the tasks admitted
|
|
267
|
+
together actually ran together — `parallel` when every admitted task was
|
|
268
|
+
in flight at once, `partial` when two or more overlapped but never all,
|
|
269
|
+
`serialized` when work is recorded but no two tasks ever overlapped,
|
|
270
|
+
`single` when the wave admitted one task (nothing to be parallel about),
|
|
271
|
+
and `unobserved` when the wave was admitted and the log shows no work for
|
|
272
|
+
any of its tasks. Exit 1 on `serialized`, exit 2 on `unobserved` — either
|
|
273
|
+
is a fact for the wave-loop's hand-back, not a reason to hold the merge:
|
|
274
|
+
report the verdict and keep going to admission. Then ask what the diff
|
|
275
|
+
did to everyone outside the claims, and whether it
|
|
222
276
|
kept what the spec promised:
|
|
223
277
|
`smith claims impact <worktree-dir> <spec.json>`. Exit 1 means a
|
|
224
278
|
`proven` break — this task removed an export a file outside its claims
|
|
@@ -250,6 +304,10 @@ one thing this playbook never asks you to.
|
|
|
250
304
|
auto-resolve a semantic conflict silently (`worktree.yml`
|
|
251
305
|
`conflict_resolution_ladder`).
|
|
252
306
|
|
|
307
|
+
An `integration-dirty` outcome names a `worktree` holding
|
|
308
|
+
`smith/<epic>/integration` with uncommitted tracked changes (`dirty`):
|
|
309
|
+
commit or stash those there, then re-run `smith queue run`.
|
|
310
|
+
|
|
253
311
|
Once the wave is merged, check the epic's spend — `smith budget alarm
|
|
254
312
|
<session-id> [--epic <epic>]`. Exit 1 means either the epic crossed
|
|
255
313
|
`alarm_ratio` (re-plan the remaining work to fit, or ask the operator —
|
package/README.md
CHANGED
|
@@ -331,7 +331,7 @@ runs, plus branch protection — not by trust. Full rules:
|
|
|
331
331
|
**[`docs/standards/guardrails.md`](docs/standards/guardrails.md)**.
|
|
332
332
|
|
|
333
333
|
- **Secrets are environment-only.** `.env.example` is the only committed env
|
|
334
|
-
file (variable names, never
|
|
334
|
+
file (variable names, never a secret's value), and the event logger redacts
|
|
335
335
|
credential-shaped strings before write.
|
|
336
336
|
- **Only you merge to `main`.** No agent may push or merge to a protected
|
|
337
337
|
branch, and force-push is refused on every branch, protected or not — an
|
|
@@ -391,9 +391,9 @@ runbook is written; the hosted UI stays deferred. Beside the phases, `/bs audit`
|
|
|
391
391
|
is built: an existing project can be read on four axes and one epic cut from
|
|
392
392
|
what you accept.
|
|
393
393
|
|
|
394
|
-
The CLI is on npm as `@juzser/blacksmith`, at `0.
|
|
395
|
-
`smith` and `smith-run`, the second being what runs a
|
|
396
|
-
`cli` harness such as Codex. `0.1.1` was the first version that ran beside
|
|
394
|
+
The CLI is on npm as `@juzser/blacksmith`, at `0.4.0` — two binaries,
|
|
395
|
+
`smith` and `smith-run`, the second (since `0.2.0`) being what runs a
|
|
396
|
+
rendered turn on a `cli` harness such as Codex. `0.1.1` was the first version that ran beside
|
|
397
397
|
you and knew it was a package, rather than out of the clone-shaped install
|
|
398
398
|
`0.1.0` was. The package is the binaries and what they
|
|
399
399
|
read. The dashboard, the docs, the test suite and `/bs` itself come from a
|