@juzser/blacksmith 0.1.0 → 0.2.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/coder.md +9 -3
- package/.claude/agents/grader.md +13 -5
- package/.claude/agents/merger.md +2 -0
- package/.claude/agents/planner.md +22 -1
- package/.claude/agents/researcher.md +3 -1
- package/.claude/agents/reviewer.md +9 -2
- package/.claude/agents/security-reviewer.md +15 -7
- package/.claude/agents/spec-reviewer.md +12 -3
- package/.claude/agents/tester.md +5 -2
- package/.claude/agents/uiux.md +10 -3
- package/.claude/agents/verifier.md +8 -3
- package/.claude/skills/bs/SKILL.md +119 -0
- package/.claude/skills/bs/audit.md +252 -0
- package/.claude/skills/bs/dispatch.md +394 -0
- package/.claude/skills/bs/lessons.md +73 -0
- package/.claude/skills/bs/mcp.md +29 -0
- package/.claude/skills/bs/new.md +35 -0
- package/.claude/skills/bs/plan.md +172 -0
- package/.claude/skills/bs/report.md +129 -0
- package/.claude/skills/bs/run.md +327 -0
- package/.claude/skills/bs/status.md +54 -0
- package/.claude/skills/bs/ui.md +19 -0
- package/.claude/skills/bs/waivers.md +13 -0
- package/.claude/skills/bs/wave.md +267 -0
- package/README.md +136 -79
- package/factory/orchestrator/dist/actors.js +4 -3
- package/factory/orchestrator/dist/agents-registry.js +96 -19
- package/factory/orchestrator/dist/artifacts.js +36 -4
- package/factory/orchestrator/dist/budgets.js +7 -5
- package/factory/orchestrator/dist/claims.js +27 -1
- package/factory/orchestrator/dist/cli.js +196 -27
- package/factory/orchestrator/dist/crosscheck.js +11 -0
- package/factory/orchestrator/dist/daemon.js +30 -5
- package/factory/orchestrator/dist/db/projector.js +272 -90
- package/factory/orchestrator/dist/db/queries.js +83 -14
- package/factory/orchestrator/dist/db/schema.js +7 -0
- package/factory/orchestrator/dist/events.js +88 -4
- package/factory/orchestrator/dist/harness.js +516 -0
- package/factory/orchestrator/dist/impact.js +76 -5
- package/factory/orchestrator/dist/judges.js +49 -8
- package/factory/orchestrator/dist/lessons.js +4 -4
- package/factory/orchestrator/dist/mcp.js +4 -3
- package/factory/orchestrator/dist/paths.js +169 -15
- package/factory/orchestrator/dist/plan.js +61 -1
- package/factory/orchestrator/dist/planQuorum.js +36 -8
- package/factory/orchestrator/dist/providers/api-transport.js +62 -5
- package/factory/orchestrator/dist/providers/cli-transport.js +7 -73
- package/factory/orchestrator/dist/providers/index.js +1 -0
- package/factory/orchestrator/dist/providers/schema-validate.js +58 -7
- package/factory/orchestrator/dist/providers/types.js +5 -0
- package/factory/orchestrator/dist/roadmap.js +3 -3
- package/factory/orchestrator/dist/run-cli.js +130 -0
- package/factory/orchestrator/dist/runner.js +264 -0
- package/factory/orchestrator/dist/scaffold.js +3 -2
- package/factory/orchestrator/dist/spawn.js +84 -0
- package/factory/orchestrator/dist/stack.js +10 -2
- package/factory/orchestrator/dist/templateFragments.js +178 -0
- package/factory/orchestrator/dist/usage.js +30 -9
- package/factory/orchestrator/dist/waveNext.js +42 -14
- package/factory/orchestrator/dist/waveSchedule.js +7 -1
- package/factory/orchestrator/dist/workroot.js +113 -0
- package/factory/orchestrator/drizzle/0011_findings_spec_ref.sql +3 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +7 -0
- package/factory/policies/budgets.yml +7 -4
- package/factory/policies/crosscheck.yml +10 -8
- package/factory/policies/harness.yml +82 -0
- package/factory/policies/lessons.md +122 -0
- package/factory/policies/severity.yml +1 -1
- package/factory/policies/taxonomy.yml +6 -2
- package/factory/specs/roadmap.md +154 -0
- package/factory/specs/schema/task-spec.schema.json +5 -0
- package/package.json +10 -7
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# `/bs lessons` — review pending lesson candidates
|
|
2
|
+
|
|
3
|
+
[`dispatch.md`](dispatch.md) binds every agent this playbook dispatches;
|
|
4
|
+
none of it is restated here.
|
|
5
|
+
|
|
6
|
+
1. `smith lessons candidates [--session <id>] [--db state/smith.db]` —
|
|
7
|
+
pending candidates with their statement, type, scope, and evidence/
|
|
8
|
+
provenance event ids.
|
|
9
|
+
2. Present each to the operator. Approve, edit, or reject is **always**
|
|
10
|
+
their call — nothing here self-modifies an agent
|
|
11
|
+
(architecture §9.4, the memory-poisoning safety boundary).
|
|
12
|
+
- **Approve**: `smith lessons approve <lesson-id> --session <id>
|
|
13
|
+
--plan-version <n> --causal-parent <event-id> --actor operator
|
|
14
|
+
[--note "<why>"]`.
|
|
15
|
+
- **Edit then approve**: add `--statement`, `--lesson-type` and/or
|
|
16
|
+
`--lesson-scope` to the same call — it writes the `lesson-edited`
|
|
17
|
+
first and chains the approval onto it, one commit. A `--statement`
|
|
18
|
+
goes through **the same novelty gate `raise` uses** (P9-34): if the
|
|
19
|
+
new text duplicates another lesson the call exits 1 with
|
|
20
|
+
`lessons.edit-not-novel` and writes **nothing**. Report that to the
|
|
21
|
+
operator with the id it duplicates and let them choose — approve the
|
|
22
|
+
lesson it duplicates, reword, or re-run with `--accept-duplicate`,
|
|
23
|
+
which lands it and records `novelty_override` on the event. Never add
|
|
24
|
+
`--accept-duplicate` on your own initiative.
|
|
25
|
+
- **Read the `novelty` block on every approval** (P9-35). The gate
|
|
26
|
+
catches copy-paste and one-word re-raises — since P9-35 (a) the
|
|
27
|
+
threshold is corrected per pair for the shorter statement's length —
|
|
28
|
+
but two changed words, containment and any real rewording all pass it,
|
|
29
|
+
so the printed `mostSimilarLessonId` and score are the real
|
|
30
|
+
near-duplicate check, and the operator is the one making it. Quote the
|
|
31
|
+
score with the bar the block reports, not the configured threshold;
|
|
32
|
+
they differ whenever the correction applied. An
|
|
33
|
+
approval that lands non-novel text exits 1 *with the transition
|
|
34
|
+
applied*: surface it, do not retry it. The UI's Edit action runs the
|
|
35
|
+
same gate since P9-36 — but it has no `--accept-duplicate` control, so
|
|
36
|
+
a duplicate the operator decides to keep has to come back to the CLI.
|
|
37
|
+
- **Reject**: `smith lessons reject <lesson-id> …` — transitions to
|
|
38
|
+
`invalidated`, the same status the UI's reject action uses
|
|
39
|
+
(`ui/server/src/app.ts`'s `/reject` route); there is no separate
|
|
40
|
+
operator-rejection status in taxonomy.yml's `lesson_status`.
|
|
41
|
+
- `invalidated`, `novelty-rejected` and `superseded` are **terminal**
|
|
42
|
+
(`LEGAL_LESSON_TRANSITIONS`, `lessons.ts`). Reviving a rejected lesson
|
|
43
|
+
means raising it again with its own provenance — the command refuses
|
|
44
|
+
`lessons.illegal-transition` rather than rewriting the decision.
|
|
45
|
+
3. Rebuild the projection so the change is visible:
|
|
46
|
+
`smith db apply --db state/smith.db --session <id>`.
|
|
47
|
+
4. Periodically run `smith dream [--since <iso-date>]` to extract new raw
|
|
48
|
+
candidates from decision checkpoints (plan sign-offs, waiver decisions,
|
|
49
|
+
escalations, gate blocks) before this review — it needs the same
|
|
50
|
+
`--session/--plan-version/--causal-parent` envelope. Candidates it
|
|
51
|
+
raises carry `needs_distillation: true`; dispatch **`scribe`**
|
|
52
|
+
(`.claude/agents/scribe.md`) to turn a promising raw one into a
|
|
53
|
+
checkable, principle-level statement before presenting it, rather than
|
|
54
|
+
showing the operator raw event text.
|
|
55
|
+
5. Once a batch is approved, recompile the committed file:
|
|
56
|
+
`smith lessons compile [--session <id>] [--db state/smith.db]` —
|
|
57
|
+
regenerates `factory/policies/lessons.md` from every `approved` lesson,
|
|
58
|
+
sectioned by scope (architecture §9.5). Commit the regenerated file — it
|
|
59
|
+
is the file every later dispatch reads (`smith lessons for-dispatch`), so
|
|
60
|
+
an approved-but-uncompiled lesson reaches nobody.
|
|
61
|
+
6. After a compile — or whenever `lessons.md` has grown enough that nobody
|
|
62
|
+
reads it — ask which entries still earn their place:
|
|
63
|
+
`smith lessons audit <session-id> [--lessons <file>] [--state-dir <dir>]`.
|
|
64
|
+
It **recommends only**; every removal is still the operator's call, the
|
|
65
|
+
same boundary step 2 draws. Read the two evidence classes apart
|
|
66
|
+
(operator-guide/lessons-and-daemon.md §10b): `retire`/`unreachable` is
|
|
67
|
+
structural — an earlier entry shadows this one, provable from the corpus
|
|
68
|
+
text alone — while `idle`/`rescope` needs a log showing the entry was
|
|
69
|
+
actually loaded and still did not fire. `no-evidence` means the audit
|
|
70
|
+
could not see enough, and is **never** a reason to drop an entry.
|
|
71
|
+
Contradictions are reported,
|
|
72
|
+
not resolved: two entries that disagree are a question for the operator,
|
|
73
|
+
not something a tool should pick a winner in.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# `/bs mcp <project>` — layer the MCP surface on
|
|
2
|
+
|
|
3
|
+
Every project leaving the factory ships an MCP surface
|
|
4
|
+
(`docs/standards/mcp.md`). It is due **late** — at the mandatory
|
|
5
|
+
`<project> — mcp surface` milestone, once the tools worth exposing are known.
|
|
6
|
+
Running this at `smith new` time would produce a manifest declaring nothing,
|
|
7
|
+
which is the rubber stamp the standard exists to prevent.
|
|
8
|
+
|
|
9
|
+
1. Run `smith mcp init <project>`. It layers `src/mcp/`, `test/mcp/`, and a
|
|
10
|
+
root `mcp.manifest.json` onto the already-scaffolded project, merges the
|
|
11
|
+
`mcp:serve` script and the pinned SDK dependency into its `package.json`,
|
|
12
|
+
and appends the `mcp surface` milestone to `factory/specs/roadmap.md`.
|
|
13
|
+
It refuses if the target has no `package.json` (run `/bs new` first) or if
|
|
14
|
+
a manifest already exists — re-scaffolding would discard declared tools and
|
|
15
|
+
their operator sign-off.
|
|
16
|
+
2. The scaffold ships one read-only tool (`project_health`) as the worked
|
|
17
|
+
example. Every tool added after it is **declared in the manifest first**,
|
|
18
|
+
with a mutation class and matching annotations; anything that is not
|
|
19
|
+
`read-only` needs `approval: { operator, date, milestone }` — an operator
|
|
20
|
+
signature, taken at this milestone. Never sign one yourself.
|
|
21
|
+
3. Tools that wrap a guardrail-gated action (deploy, outbound send, writes to
|
|
22
|
+
`main`) are not allowed at all (mcp.md MCP-S3). A signed `destructive` tool
|
|
23
|
+
is permission to act inside the project, never a way around an operator
|
|
24
|
+
gate.
|
|
25
|
+
4. Run `smith mcp check <project>` before closing anything under that
|
|
26
|
+
milestone. Exit 0 means green; exit 1 prints one `{ rule, path, message }`
|
|
27
|
+
per violation. `smith epic close` runs the same check and refuses while it
|
|
28
|
+
is red — the only way past it is `--override-rationale`, which is the
|
|
29
|
+
operator's call and their name in the event log, never yours.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# `/bs new <project> [--ui]` — scaffold a target project
|
|
2
|
+
|
|
3
|
+
1. Ask where the project should live, then run `smith new <project> [--ui]
|
|
4
|
+
[--target-dir <dir>]`. Without `--target-dir` it lands beside the clone, in
|
|
5
|
+
`<repo-parent>/<project>` — or, when `smith` is an installed package rather
|
|
6
|
+
than a clone, in the directory you run it from, never inside the package.
|
|
7
|
+
Either way that is a default rather than a requirement —
|
|
8
|
+
the answer becomes the `<project-dir>` every later command takes, so take
|
|
9
|
+
it here rather than assuming it six steps in. The call
|
|
10
|
+
copies `factory/scaffold/` (TS strict, Biome, Vitest, CI) and layers
|
|
11
|
+
whatever `factory/policies/stack.yml` answered for: `--ui` adds the
|
|
12
|
+
frontend, generates `src/styles/main.css`, and vendors the named design
|
|
13
|
+
system into `design/` if there is one. Then it installs and runs the
|
|
14
|
+
project's own gates, commits it on a `setup` branch, and registers a
|
|
15
|
+
bootstrap milestone in `factory/specs/roadmap.md` — all in one call.
|
|
16
|
+
An answer the templates cannot build (`frontend: react`) makes it **refuse
|
|
17
|
+
before creating anything**, rather than quietly handing over the frontend
|
|
18
|
+
they do ship. `smith stack check` says in advance which answers are
|
|
19
|
+
honoured, merely recorded, or refused.
|
|
20
|
+
2. The gate run is `pnpm install` then `lint`, `typecheck`, `test:coverage`,
|
|
21
|
+
`build` — `ci.yml`'s order, so the lockfile lands in the first commit and no
|
|
22
|
+
epic ever needs a serial `task-0-toolchain` (P9-19). It takes a minute or
|
|
23
|
+
two. Read `toolchain` in the JSON result:
|
|
24
|
+
- `verified` — every gate passed; plan the first epic against it.
|
|
25
|
+
- `failed` — `failedStep` names the gate, its `output` is the tail, and
|
|
26
|
+
`command` is the exact line to re-run by hand. The command exits **1** and
|
|
27
|
+
the tree is left in place to fix. Do not plan an epic against it.
|
|
28
|
+
- `skipped` — only when `--skip-toolchain` was passed (offline). Nothing was
|
|
29
|
+
proven; say so rather than reporting a green.
|
|
30
|
+
3. The JSON result's `commands.ghRepoCreate` and `commands.push` are for the
|
|
31
|
+
**operator to run themselves** — never execute them from this session
|
|
32
|
+
(guardrails.md: only the operator pushes a brand-new remote/creates the
|
|
33
|
+
repo; this skill only prints what to run).
|
|
34
|
+
4. Tell the operator: target dir, branch (`setup`), the `toolchain` verdict, and
|
|
35
|
+
the two commands.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# `/bs plan <goal>` — draft or re-plan an epic
|
|
2
|
+
|
|
3
|
+
[`dispatch.md`](dispatch.md) binds every agent this playbook dispatches;
|
|
4
|
+
none of it is restated here.
|
|
5
|
+
|
|
6
|
+
The planner-session playbook (architecture §3, §12):
|
|
7
|
+
|
|
8
|
+
**Pick the effort tier before step 1.** It is chosen per *epic*, not per
|
|
9
|
+
project — the same repo runs a `small` internal-tool epic and a `huge`
|
|
10
|
+
one — and it scales steps 3–4 below plus most of `/bs run`. Ask, do not
|
|
11
|
+
recall:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
smith effort show --effort <small|medium|huge> # no plan file exists yet
|
|
15
|
+
smith effort show --plan factory/specs/active/<epic>/plan-vN.json
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`profile` is what this epic buys, and every step below that a tier touches
|
|
19
|
+
says which field decides it. `invariants` is what no tier may touch: the
|
|
20
|
+
gate pipeline, the integration check, claim disjointness and worktree
|
|
21
|
+
isolation, the security-reviewer's own triggers, the operator's sign-off,
|
|
22
|
+
the epic verdict, the event log and the escalation ladder run identically at
|
|
23
|
+
every tier. A `small` epic is faster because it deliberates less, never
|
|
24
|
+
because it verifies less — a tier that skipped tests would not be cheap,
|
|
25
|
+
just unverified.
|
|
26
|
+
|
|
27
|
+
Omit `--effort` and the epic takes `effort.yml`'s `default_tier`. Read
|
|
28
|
+
`effective`, not `requested`: an epic whose live tasks fire `crosscheck.yml`'s
|
|
29
|
+
`plan_quorum` security triggers is floored at `security_floor` no matter what
|
|
30
|
+
was asked for, and `floorApplied: true` says so. An internal tool that
|
|
31
|
+
touches auth is not a small epic. Without `--plan` the floor is *not
|
|
32
|
+
evaluated* — `securityFloorEvaluated: false`, and an empty `securityTriggers`
|
|
33
|
+
there means "not looked at", not "looked at and clean".
|
|
34
|
+
|
|
35
|
+
1. **Static analysis for claims first.** Before any decomposition, get the
|
|
36
|
+
target repo's import/dependency graph so claims are computed, not
|
|
37
|
+
guessed (architecture §5) — dispatch `researcher`
|
|
38
|
+
(`.claude/agents/researcher.md`) for an unfamiliar repo, or do it
|
|
39
|
+
directly with Grep/Read for a small one.
|
|
40
|
+
2. Dispatch a **`planner`** session (`.claude/agents/planner.md`, frontier
|
|
41
|
+
tier) with the goal + the claims analysis. It drafts the epic spec and
|
|
42
|
+
task specs (`factory/specs/schema/task-spec.schema.json` shape).
|
|
43
|
+
3. Dispatch a **`spec-reviewer`** session (`.claude/agents/spec-reviewer.md`)
|
|
44
|
+
— a *different model* than the planner's, per its own frontmatter — to
|
|
45
|
+
hunt spec gaps/ambiguities/missing-nonfunctional clauses
|
|
46
|
+
(`docs/standards/agent-constraints.md` "planner"; `severity.yml`: most
|
|
47
|
+
spec gaps land S2, blocking sign-off).
|
|
48
|
+
4. Planner fixes flagged issues; repeat 2–3 until the spec-reviewer has
|
|
49
|
+
nothing S1/S2 left — or exactly once when `profile.specReviewRounds` is
|
|
50
|
+
`single-pass` (`small`), where the planner fixes what came back and
|
|
51
|
+
anything still S1/S2 goes to the operator with the spec at step 5 instead
|
|
52
|
+
of round-tripping. Then run the plan quorum before sign-off — it
|
|
53
|
+
evaluates `factory/policies/crosscheck.yml`'s `plan_quorum.triggers`
|
|
54
|
+
(budget ≥50% of the epic cap, `case: infra`, security-sensitive, low
|
|
55
|
+
confidence) for you:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
smith plan quorum --plan <the draft's plan.json> --plan-version <n> \
|
|
59
|
+
--session <session-id> --causal-parent <event-id> \
|
|
60
|
+
--confidence <your own 0–1 confidence in this plan> \
|
|
61
|
+
--out <scratch>/quorum-v<n>.json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`--plan` hands over the draft itself: at this step nothing has been
|
|
65
|
+
written to `factory/specs/active/<epic>/` yet — that is step 6, on
|
|
66
|
+
approval — so the verb cannot read a `plan-v<n>.json` that does not
|
|
67
|
+
exist. (`--epic <epic>` instead of `--plan` critiques a version already
|
|
68
|
+
filed.) The draft's own `epic_id`/`version` must be the ones the command
|
|
69
|
+
names, or it refuses (`plan.identity-mismatch`) rather than record one
|
|
70
|
+
plan's identity with another plan's triggers. `--out` keeps the outcome
|
|
71
|
+
— three rationales of several kB each — where step 5 can hand it to the
|
|
72
|
+
operator whole instead of quoting a terminal.
|
|
73
|
+
|
|
74
|
+
**Nothing runs this for you — you run it here** when
|
|
75
|
+
`profile.planQuorum` is `always` (`huge`). At `when-triggered` (`medium`,
|
|
76
|
+
`small`) run it only when you can already name the trigger from the plan
|
|
77
|
+
you just wrote — budget ≥50% of the epic cap, `case: infra`, a
|
|
78
|
+
security-sensitive clause, or your own confidence below 0.8. The command
|
|
79
|
+
is local and free either way; what the tier is buying back is the step,
|
|
80
|
+
not the tokens, because the two cross-provider judges are trigger-gated
|
|
81
|
+
inside `runPlanQuorum` at every tier. Exit 0 = nothing needs
|
|
82
|
+
the operator. Exit 1 (`critiqued`/`escalated`) is critique-only: never
|
|
83
|
+
rewrite the plan silently, surface the critique to the operator at step
|
|
84
|
+
5. If the output is `endorsed` with a non-empty `triggers` array, a
|
|
85
|
+
trigger fired but no external provider is `enabled` in `crosscheck.yml`
|
|
86
|
+
— say that plainly to the operator rather than signing off as if a
|
|
87
|
+
cross-provider quorum happened.
|
|
88
|
+
5. **Present the epic spec + acceptance criteria to the operator.** Nothing
|
|
89
|
+
executes before they sign off (architecture §1; agent-constraints.md
|
|
90
|
+
"planner: autonomy — spec sign-off per epic").
|
|
91
|
+
6. On approval, write task specs to
|
|
92
|
+
`factory/specs/active/<epic>/plan-v1.json` and validate:
|
|
93
|
+
`smith plan validate factory/specs/active/<epic>/plan-v1.json` must
|
|
94
|
+
report `{"valid":true}` before anything else touches this plan. Write the
|
|
95
|
+
tier onto the plan file as a top-level `"effort": "<tier>"` — that is
|
|
96
|
+
where `/bs run` reads it, and `smith plan amend` carries it into
|
|
97
|
+
v(n+1) so a re-plan is not a fresh choice. Omit the field to take the
|
|
98
|
+
policy default; a value that is not `small`/`medium`/`huge` fails
|
|
99
|
+
validation rather than degrading to it.
|
|
100
|
+
|
|
101
|
+
Then read the plan's parallelism ceiling before anyone is dispatched
|
|
102
|
+
against it:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
smith wave schedule factory/specs/active/<epic>/plan-v1.json \
|
|
106
|
+
--session <session-id> --repo <project-dir>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`valid: true` says the plan is well-formed; this says whether it can ever
|
|
110
|
+
run wide. It replays the wave loop to exhaustion and reports `depth` (how
|
|
111
|
+
many sequential rounds) and `widest` (the most tasks any round starts —
|
|
112
|
+
the ceiling beyond which more agents buy nothing). Exit 1 means the plan
|
|
113
|
+
**stalls** and cannot be finished as written: fix it here, not by watching
|
|
114
|
+
`/bs run` hang. Exit 2 means it runs but loses width to `constraints` —
|
|
115
|
+
tasks whose dependencies were satisfied and were held back only by how you
|
|
116
|
+
drew the claims. That is a plan-time cost and this is the last step that
|
|
117
|
+
can pay it cheaply; a `widest: 1` plan serializes the whole epic while
|
|
118
|
+
every gate downstream reports a healthy wave of one. Deferrals for
|
|
119
|
+
`dependency-pending` never appear there, because a chain of real
|
|
120
|
+
dependencies is the shape of the work and not a defect. Exit 2 whose
|
|
121
|
+
`constraints` name `symbol-coupled` is a **re-plan round**, not
|
|
122
|
+
information: hand the planner the constraint list — the file pairs from
|
|
123
|
+
the deferral detail — and ask, per pair, for a dependency edge, a
|
|
124
|
+
`keeps_exports` promise on the producer, or a re-slice.
|
|
125
|
+
`claim-overlap` / `serialize-hotspot` constraints are the re-slice case
|
|
126
|
+
above. Exit 2 with no such constraint remains information, not a stop —
|
|
127
|
+
decide whether to re-slice, and say which you chose when you present the
|
|
128
|
+
plan.
|
|
129
|
+
|
|
130
|
+
Beside the schedule, the read that names what it only counts:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
smith claims impact --plan factory/specs/active/<epic>/plan-v1.json \
|
|
134
|
+
<task-id>... --repo <project-dir>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Its `crossings` are the file pairs a `symbol-coupled` constraint points
|
|
138
|
+
at; `promised` holds the ones a producer's `keeps_exports` already
|
|
139
|
+
answers, which the schedule admits and the diff is later checked against.
|
|
140
|
+
7. Log the sign-off itself as a decision checkpoint (this is exactly what
|
|
141
|
+
`smith dream`'s "plan sign-off" extraction looks for, `lessons.ts`):
|
|
142
|
+
`smith event append '{"session_id":"...","actor":"operator",
|
|
143
|
+
"event_type":"plan-version-created","plan_version":1,
|
|
144
|
+
"causal_parent":"...","payload":{"epic_id":"<epic>","version":1,
|
|
145
|
+
"note":"<operator's own words>"}}'`.
|
|
146
|
+
|
|
147
|
+
Then write the backlog that signature approved into the log, hung off
|
|
148
|
+
the sign-off event:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
smith plan ingest factory/specs/active/<epic>/plan-v1.json \
|
|
152
|
+
--session <session-id> --plan-version 1 --causal-parent <sign-off event id>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This is where a task starts existing as far as the log — and so the DB,
|
|
156
|
+
the Kanban, the Flow graph and every dashboard number — is concerned
|
|
157
|
+
(D-46, D-254): one `task-added` per task, one `edges-recorded` for the
|
|
158
|
+
DAG. Nothing downstream runs it for you, and nothing refuses to run
|
|
159
|
+
without it: `wave next` reads the plan file, so an un-ingested plan still
|
|
160
|
+
runs, and its task rows then spring into being as a side effect of the
|
|
161
|
+
first wave or gate event to name an id — with no epic, no claims, no
|
|
162
|
+
budget and no edges, which is the flat, half-empty board the 2026-09-14
|
|
163
|
+
UI check found behind two epics. It is idempotent, so run it again on a
|
|
164
|
+
resumed session; read `added` and `edges` back, and say so when either is
|
|
165
|
+
0 on a plan that has tasks or edges.
|
|
166
|
+
8. If this epic opens a new roadmap milestone, add it to
|
|
167
|
+
`factory/specs/roadmap.md` (planner-maintained, architecture §12) — a
|
|
168
|
+
roadmap change is itself a scope change and needs the same operator nod.
|
|
169
|
+
Give it a `- goal:` line and list the epic under `- epics:`. That line is
|
|
170
|
+
load-bearing, not documentation: it is the only text the spec-vs-goal gate
|
|
171
|
+
can grade the plan against (`/bs run` step 14), and a milestone without one
|
|
172
|
+
holds every epic it owns.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# `/bs report` — the scribe's progress digest
|
|
2
|
+
|
|
3
|
+
[`dispatch.md`](dispatch.md) binds every agent this playbook dispatches;
|
|
4
|
+
none of it is restated here.
|
|
5
|
+
|
|
6
|
+
The scribe-template digest playbook (agent-constraints.md "scribe (digest
|
|
7
|
+
duties, v3.2)"), plus running the scheduler first — a report that omits
|
|
8
|
+
pending proposals lets them sit invisible instead of surfacing them.
|
|
9
|
+
|
|
10
|
+
1. **Ask what the factory is answerable for, then run the scheduler.**
|
|
11
|
+
`smith projects list` reads the roadmap's `- project:` bullets — the
|
|
12
|
+
register `smith new` writes to — and prints the factory itself plus every
|
|
13
|
+
project it built that has a checkout, ending in the `--project` line to
|
|
14
|
+
pass on. Do not assemble that list from memory: the maintenance pass
|
|
15
|
+
reads one lockfile per flag and reports one proposal per repo, so a repo
|
|
16
|
+
left off the line is not reported as missing, it is simply never
|
|
17
|
+
mentioned. (The daemon raises `unwatched-project` for a child project with
|
|
18
|
+
a checkout that is left off the line — not for the factory itself, which is in
|
|
19
|
+
the pass by default, and not for a declared project with no checkout at
|
|
20
|
+
all, which `smith projects list` marks with `?` instead of leaving it
|
|
21
|
+
off the printed list. The two surfaces no longer answer the same
|
|
22
|
+
question.) Then run `smith scheduler run
|
|
23
|
+
[--dry] --session <id> [--project <dir>...]` with those flags — a
|
|
24
|
+
deterministic pass over the event log, it never dispatches an agent
|
|
25
|
+
itself (`factory/policies/scheduler.yml`, architecture §12). Read its
|
|
26
|
+
`proposals` and route each kind before writing the digest:
|
|
27
|
+
- `recheck-proposed` → don't act on it silently; tick it into the next
|
|
28
|
+
`/bs plan` sign-off as an `origin: recheck` task, same spec/sign-off
|
|
29
|
+
flow as any other. Re-running the scheduler never duplicates an
|
|
30
|
+
already-pending proposal for the same task (idempotent by design) —
|
|
31
|
+
it re-proposes only after that recheck is resolved (a real recheck
|
|
32
|
+
task created for it, or explicitly declined).
|
|
33
|
+
- `maintenance-proposed` → read `projectDir` first: one pass can raise
|
|
34
|
+
several of these, one per `--project`, and they are not
|
|
35
|
+
interchangeable. Then check `autoSchedulable`: `true` (patch/
|
|
36
|
+
minor-only version bumps, `scheduler.yml`'s
|
|
37
|
+
`auto_schedule_confidence`) can go straight into the next `/bs plan`
|
|
38
|
+
without a fresh conversation; `false` (a major-version bump is
|
|
39
|
+
present) still needs one.
|
|
40
|
+
- `growth-review-due` → this is a TRIGGER only, never a scope proposal
|
|
41
|
+
itself (architecture §12). Open a fresh `/bs plan <goal>` session
|
|
42
|
+
where the planner reads the living spec/analytics/recheck outcomes
|
|
43
|
+
and proposes new epics — the operator's tick is required regardless
|
|
44
|
+
of confidence, same as any other plan sign-off.
|
|
45
|
+
2. **Ask who may say yes.** `smith scheduler admit --session <id>
|
|
46
|
+
[--project <dir>...]`, with the same flag line step 1 printed, re-reads
|
|
47
|
+
the same proposals and classifies
|
|
48
|
+
each one `auto` or `operator` against `scheduler.yml`'s `autonomy:`
|
|
49
|
+
block (`src/autonomy.ts`). It enacts nothing — the split is printed so
|
|
50
|
+
it can be read and argued with before anything moves.
|
|
51
|
+
- `decision: auto` → dispatchable through `/bs run`'s ordinary wave
|
|
52
|
+
flow without a fresh sign-off. It is still a wave: same worktrees,
|
|
53
|
+
same gates, same reviewer, and the **PR is still merged by a
|
|
54
|
+
person**. That merge is the backstop that makes auto-dispatch safe
|
|
55
|
+
to widen, so never bypass it because the scheduler said `auto`.
|
|
56
|
+
- `decision: operator` → it waits, and `code` names the rule that held
|
|
57
|
+
it: `autonomy-disabled`, `growth-never-auto`, `kind-not-whitelisted`,
|
|
58
|
+
`reason-not-whitelisted`, `below-confidence-floor`, or
|
|
59
|
+
`security-surface`. Report the `reason` verbatim in the digest — it
|
|
60
|
+
is written in the terms an operator would use to argue with it.
|
|
61
|
+
- Every rule in that file can only **deny**. There is no branch that
|
|
62
|
+
promotes something the whitelist did not name, so "what runs without
|
|
63
|
+
me?" is answerable by reading `scheduler.yml` alone.
|
|
64
|
+
- **Never widen the whitelist to clear a denial mid-run.** Editing
|
|
65
|
+
`autonomy.auto_dispatch_kinds`, `auto_dispatch_recheck_reasons` or
|
|
66
|
+
`confidence_floor` is an operator decision about standing policy, not
|
|
67
|
+
a way past one proposal — and a `security-surface` denial is the one
|
|
68
|
+
nothing in the file can lift.
|
|
69
|
+
3. Gather `smith stats overview [--session <id>]` and `smith stats roadmap
|
|
70
|
+
[--session <id>]` (milestone progress + budget burn per milestone).
|
|
71
|
+
4. **Read back the disagreements.** `smith judge escalations --session
|
|
72
|
+
<id>` folds the lineage for `quorum-decision` events whose latest word
|
|
73
|
+
was `escalate` — a gate finding, an epic verdict or a plan critique the
|
|
74
|
+
cross-provider quorum could not settle. It exits `1` on an open
|
|
75
|
+
`disagreement` and `2` when the only thing open is
|
|
76
|
+
`insufficient-providers`, so **exit 2 is not a failure to fix here**: it
|
|
77
|
+
is one fact about `crosscheck.yml`'s gating arithmetic, already collapsed
|
|
78
|
+
to `ungated.count` plus a hint, and it belongs in the digest as a single
|
|
79
|
+
line. Report each `disagreement` individually — two providers read the
|
|
80
|
+
same thing and said different words, and nothing else in the pipeline
|
|
81
|
+
will raise it again. An entry with `held: false` goes first: the quorum
|
|
82
|
+
did not settle it and the work went ahead regardless (that includes a
|
|
83
|
+
`mode: shadow` disagreement, which the gate outcome never reported to
|
|
84
|
+
anyone). Resolving one is an operator reading, never this session
|
|
85
|
+
deciding on its own which provider was right.
|
|
86
|
+
5. **Read back the parallelism.** `smith wave audit --session <id>
|
|
87
|
+
[--epic <id>]` folds every `wave-admitted` against the
|
|
88
|
+
`dispatch_decision` intervals underneath it and says whether a wave
|
|
89
|
+
admitted N wide actually *ran* N wide. `wave check` only ever certified
|
|
90
|
+
that it *could*, so without this the digest reports a factory running
|
|
91
|
+
many agents in parallel on the strength of a permission slip. Exit `1`
|
|
92
|
+
is a wave whose tasks never once overlapped — report it with the epic
|
|
93
|
+
id, because a serialized run is the failure this whole design exists to
|
|
94
|
+
prevent, not a slow day. Exit `2` is a wave admitted with no dispatch
|
|
95
|
+
under it at all: that is "cannot tell", not "ran narrow", and it usually
|
|
96
|
+
means the wrong `--state-dir` or a run whose agents wrote elsewhere —
|
|
97
|
+
check before reporting it as a stall. A `partial` verdict is **not** a
|
|
98
|
+
finding; put `widest` in the digest as the one number that says how wide
|
|
99
|
+
this factory has ever actually run.
|
|
100
|
+
6. Dispatch **`scribe`** (`.claude/agents/scribe.md`, small tier) with that
|
|
101
|
+
JSON plus step 2's admissions as input: shipped / in-flight / blocked /
|
|
102
|
+
budget burn / next milestone / **N rechecks pending, M maintenance
|
|
103
|
+
bumps auto-schedulable** (never silently dropped), ≤300 words, linking
|
|
104
|
+
into the dashboard (`smith ui serve`'s URL) — never paraphrase numbers
|
|
105
|
+
the query didn't return.
|
|
106
|
+
7. This fires automatically on a weekly cadence and immediately on any
|
|
107
|
+
milestone completion (architecture §12) — for an ad hoc `/bs report`,
|
|
108
|
+
the same digest, just on demand.
|
|
109
|
+
8. Sending it to Slack is an **outbound send** — the permission layer
|
|
110
|
+
prompts on the `curl`/webhook call; never fire it without that prompt
|
|
111
|
+
resolving (`docs/standards/guardrails.md` "Deploy + outbound"). Print
|
|
112
|
+
the digest to the operator regardless, whether or not the Slack send is
|
|
113
|
+
approved.
|
|
114
|
+
|
|
115
|
+
**Provider calibration note (Phase 8).** While any provider in
|
|
116
|
+
`factory/policies/crosscheck.yml` is still `mode: shadow`, run
|
|
117
|
+
`smith stats providers [--session <id>] [--since <iso-date>]` alongside the
|
|
118
|
+
scheduler pass and fold a one-line mention into the digest when a provider
|
|
119
|
+
has accumulated enough runs to review (`runs`, `verdicts`, `agreementRate`,
|
|
120
|
+
`schemaFailureRate`, `transportFailureRate`, `failuresByCode` per provider —
|
|
121
|
+
`docs/runbooks/providers.md`'s calibration procedure has the promotion
|
|
122
|
+
threshold). Report `verdicts` alongside `agreementRate`: a `null` rate means
|
|
123
|
+
no run ever answered, which is a transport problem to fix, not a provider
|
|
124
|
+
that disagrees (D-168). When the rate is `null`, name the top entry in
|
|
125
|
+
`failuresByCode` in the digest line — `provider.missing-api-key` is an unset
|
|
126
|
+
environment variable and the whole repair, where `provider.invalid-output`
|
|
127
|
+
is the prompt (D-253). Promoting a provider to
|
|
128
|
+
`mode: active` is always an **operator edit** of `crosscheck.yml`, never
|
|
129
|
+
something this session does on the digest's say-so.
|