@juzser/blacksmith 0.1.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.
Files changed (172) hide show
  1. package/.claude/agents/auditor.md +146 -0
  2. package/.claude/agents/coder.md +164 -0
  3. package/.claude/agents/grader.md +110 -0
  4. package/.claude/agents/merger.md +107 -0
  5. package/.claude/agents/planner.md +92 -0
  6. package/.claude/agents/researcher.md +105 -0
  7. package/.claude/agents/reviewer.md +171 -0
  8. package/.claude/agents/scribe.md +72 -0
  9. package/.claude/agents/security-reviewer.md +130 -0
  10. package/.claude/agents/spec-reviewer.md +215 -0
  11. package/.claude/agents/tester.md +121 -0
  12. package/.claude/agents/uiux.md +126 -0
  13. package/.claude/agents/verifier.md +103 -0
  14. package/.claude/agents/wave-runner.md +74 -0
  15. package/LICENSE +21 -0
  16. package/README.md +389 -0
  17. package/factory/orchestrator/dist/actors.js +46 -0
  18. package/factory/orchestrator/dist/agents-registry.js +308 -0
  19. package/factory/orchestrator/dist/args.js +84 -0
  20. package/factory/orchestrator/dist/artifacts.js +111 -0
  21. package/factory/orchestrator/dist/attribution.js +160 -0
  22. package/factory/orchestrator/dist/audit.js +812 -0
  23. package/factory/orchestrator/dist/autonomy.js +151 -0
  24. package/factory/orchestrator/dist/budgetAlarm.js +366 -0
  25. package/factory/orchestrator/dist/budgets.js +196 -0
  26. package/factory/orchestrator/dist/claims.js +633 -0
  27. package/factory/orchestrator/dist/cli.js +3185 -0
  28. package/factory/orchestrator/dist/commit.js +152 -0
  29. package/factory/orchestrator/dist/coverage.js +188 -0
  30. package/factory/orchestrator/dist/crossFinding.js +479 -0
  31. package/factory/orchestrator/dist/crosscheck.js +396 -0
  32. package/factory/orchestrator/dist/daemon.js +707 -0
  33. package/factory/orchestrator/dist/db/projector.js +1317 -0
  34. package/factory/orchestrator/dist/db/queries.js +1714 -0
  35. package/factory/orchestrator/dist/db/schema.js +305 -0
  36. package/factory/orchestrator/dist/delegation.js +400 -0
  37. package/factory/orchestrator/dist/diffstat.js +164 -0
  38. package/factory/orchestrator/dist/dispatchAudit.js +275 -0
  39. package/factory/orchestrator/dist/dotenv.js +72 -0
  40. package/factory/orchestrator/dist/effort.js +202 -0
  41. package/factory/orchestrator/dist/epic.js +1018 -0
  42. package/factory/orchestrator/dist/epicWidth.js +238 -0
  43. package/factory/orchestrator/dist/errorIssues.js +249 -0
  44. package/factory/orchestrator/dist/errors.js +11 -0
  45. package/factory/orchestrator/dist/escalation.js +500 -0
  46. package/factory/orchestrator/dist/events.js +1015 -0
  47. package/factory/orchestrator/dist/findingAge.js +91 -0
  48. package/factory/orchestrator/dist/findingContext.js +103 -0
  49. package/factory/orchestrator/dist/findings.js +1156 -0
  50. package/factory/orchestrator/dist/gate.js +911 -0
  51. package/factory/orchestrator/dist/gh.js +146 -0
  52. package/factory/orchestrator/dist/git.js +87 -0
  53. package/factory/orchestrator/dist/goalCheck.js +380 -0
  54. package/factory/orchestrator/dist/graph.js +61 -0
  55. package/factory/orchestrator/dist/hookDecision.js +106 -0
  56. package/factory/orchestrator/dist/immutability.js +171 -0
  57. package/factory/orchestrator/dist/impact.js +280 -0
  58. package/factory/orchestrator/dist/integration.js +141 -0
  59. package/factory/orchestrator/dist/judgePreflight.js +155 -0
  60. package/factory/orchestrator/dist/judges.js +310 -0
  61. package/factory/orchestrator/dist/lessonAudit.js +399 -0
  62. package/factory/orchestrator/dist/lessons.js +1329 -0
  63. package/factory/orchestrator/dist/mcp.js +555 -0
  64. package/factory/orchestrator/dist/paths.js +82 -0
  65. package/factory/orchestrator/dist/plan.js +502 -0
  66. package/factory/orchestrator/dist/planQuorum.js +421 -0
  67. package/factory/orchestrator/dist/policy.js +1308 -0
  68. package/factory/orchestrator/dist/policyHook.js +28 -0
  69. package/factory/orchestrator/dist/preconditions.js +47 -0
  70. package/factory/orchestrator/dist/projects.js +134 -0
  71. package/factory/orchestrator/dist/prompts.js +57 -0
  72. package/factory/orchestrator/dist/provenance.js +201 -0
  73. package/factory/orchestrator/dist/providers/api-transport.js +117 -0
  74. package/factory/orchestrator/dist/providers/cli-transport.js +208 -0
  75. package/factory/orchestrator/dist/providers/index.js +54 -0
  76. package/factory/orchestrator/dist/providers/schema-validate.js +152 -0
  77. package/factory/orchestrator/dist/providers/types.js +49 -0
  78. package/factory/orchestrator/dist/queue.js +263 -0
  79. package/factory/orchestrator/dist/quorum.js +347 -0
  80. package/factory/orchestrator/dist/quorumEscalations.js +132 -0
  81. package/factory/orchestrator/dist/results.js +65 -0
  82. package/factory/orchestrator/dist/roadmap.js +437 -0
  83. package/factory/orchestrator/dist/runtime.js +86 -0
  84. package/factory/orchestrator/dist/sameMistakeKpi.js +243 -0
  85. package/factory/orchestrator/dist/sandbox.js +165 -0
  86. package/factory/orchestrator/dist/scaffold.js +373 -0
  87. package/factory/orchestrator/dist/scheduler.js +408 -0
  88. package/factory/orchestrator/dist/schemas.js +195 -0
  89. package/factory/orchestrator/dist/security.js +222 -0
  90. package/factory/orchestrator/dist/severity.js +293 -0
  91. package/factory/orchestrator/dist/spec.js +376 -0
  92. package/factory/orchestrator/dist/specChange.js +497 -0
  93. package/factory/orchestrator/dist/stack.js +324 -0
  94. package/factory/orchestrator/dist/symbols.js +966 -0
  95. package/factory/orchestrator/dist/taskEvents.js +399 -0
  96. package/factory/orchestrator/dist/taskId.js +126 -0
  97. package/factory/orchestrator/dist/taxonomy.js +113 -0
  98. package/factory/orchestrator/dist/testSelect.js +129 -0
  99. package/factory/orchestrator/dist/testerAudit.js +264 -0
  100. package/factory/orchestrator/dist/testgate.js +171 -0
  101. package/factory/orchestrator/dist/usage.js +874 -0
  102. package/factory/orchestrator/dist/waivers.js +228 -0
  103. package/factory/orchestrator/dist/waveBudget.js +223 -0
  104. package/factory/orchestrator/dist/waveConcurrency.js +250 -0
  105. package/factory/orchestrator/dist/waveNext.js +210 -0
  106. package/factory/orchestrator/dist/waveSchedule.js +146 -0
  107. package/factory/orchestrator/dist/worktree.js +207 -0
  108. package/factory/orchestrator/drizzle/0000_broken_rockslide.sql +183 -0
  109. package/factory/orchestrator/drizzle/0001_luxuriant_zaladane.sql +1 -0
  110. package/factory/orchestrator/drizzle/0002_yellow_wild_pack.sql +8 -0
  111. package/factory/orchestrator/drizzle/0003_damp_riptide.sql +12 -0
  112. package/factory/orchestrator/drizzle/0004_broad_lady_vermin.sql +1 -0
  113. package/factory/orchestrator/drizzle/0005_romantic_jocasta.sql +2 -0
  114. package/factory/orchestrator/drizzle/0006_bent_madelyne_pryor.sql +16 -0
  115. package/factory/orchestrator/drizzle/0007_overjoyed_goliath.sql +1 -0
  116. package/factory/orchestrator/drizzle/0008_smart_iron_patriot.sql +2 -0
  117. package/factory/orchestrator/drizzle/0009_agents_epic_id.sql +2 -0
  118. package/factory/orchestrator/drizzle/0010_milestone_kind.sql +1 -0
  119. package/factory/orchestrator/drizzle/meta/_journal.json +83 -0
  120. package/factory/policies/budgets.yml +262 -0
  121. package/factory/policies/crosscheck.yml +308 -0
  122. package/factory/policies/delegation.yml +44 -0
  123. package/factory/policies/effort.yml +142 -0
  124. package/factory/policies/guardrails.yml +306 -0
  125. package/factory/policies/lessons.md +239 -0
  126. package/factory/policies/scheduler.yml +90 -0
  127. package/factory/policies/sensitive-paths.yml +148 -0
  128. package/factory/policies/severity.yml +83 -0
  129. package/factory/policies/stack.yml +60 -0
  130. package/factory/policies/taxonomy.yml +340 -0
  131. package/factory/policies/worktree.yml +95 -0
  132. package/factory/scaffold/base/.github/workflows/ci.yml +34 -0
  133. package/factory/scaffold/base/.gitignore.tmpl +11 -0
  134. package/factory/scaffold/base/AGENTS.md +33 -0
  135. package/factory/scaffold/base/README.md +25 -0
  136. package/factory/scaffold/base/biome.json.tmpl +30 -0
  137. package/factory/scaffold/base/package.json +25 -0
  138. package/factory/scaffold/base/pnpm-workspace.yaml.tmpl +16 -0
  139. package/factory/scaffold/base/src/index.ts +4 -0
  140. package/factory/scaffold/base/test/index.test.ts +8 -0
  141. package/factory/scaffold/base/tsconfig.json +20 -0
  142. package/factory/scaffold/base/tsconfig.test.json +9 -0
  143. package/factory/scaffold/base/vitest.config.ts +29 -0
  144. package/factory/scaffold/mcp/mcp.manifest.json +22 -0
  145. package/factory/scaffold/mcp/package.fragment.json +9 -0
  146. package/factory/scaffold/mcp/src/mcp/README.md +63 -0
  147. package/factory/scaffold/mcp/src/mcp/guard.ts +110 -0
  148. package/factory/scaffold/mcp/src/mcp/redact.ts +69 -0
  149. package/factory/scaffold/mcp/src/mcp/server.ts +55 -0
  150. package/factory/scaffold/mcp/src/mcp/tools/health.ts +60 -0
  151. package/factory/scaffold/mcp/test/mcp/guard.test.ts +108 -0
  152. package/factory/scaffold/mcp/test/mcp/redact.test.ts +61 -0
  153. package/factory/scaffold/mcp/test/mcp/surface.test.ts +100 -0
  154. package/factory/scaffold/ui/index.html +12 -0
  155. package/factory/scaffold/ui/package.fragment.json +13 -0
  156. package/factory/scaffold/ui/src/App.vue +10 -0
  157. package/factory/scaffold/ui/src/main.ts +5 -0
  158. package/factory/scaffold/ui/src/shims.d.ts +11 -0
  159. package/factory/scaffold/ui/vite.config.ts +20 -0
  160. package/factory/scaffold/ui-tailwind/package.fragment.json +6 -0
  161. package/factory/scaffold/ui-tailwind/vite.config.ts +26 -0
  162. package/factory/specs/schema/event.schema.json +82 -0
  163. package/factory/specs/schema/finding-evidence.schema.json +45 -0
  164. package/factory/specs/schema/finding.schema.json +115 -0
  165. package/factory/specs/schema/grader-verdict.schema.json +50 -0
  166. package/factory/specs/schema/judge-verdict.schema.json +19 -0
  167. package/factory/specs/schema/lesson.schema.json +85 -0
  168. package/factory/specs/schema/mcp-manifest.schema.json +230 -0
  169. package/factory/specs/schema/result.schema.json +81 -0
  170. package/factory/specs/schema/spec-change-request.schema.json +46 -0
  171. package/factory/specs/schema/task-spec.schema.json +134 -0
  172. package/package.json +98 -0
@@ -0,0 +1,340 @@
1
+ # Blacksmith — controlled vocabulary (taxonomy)
2
+ #
3
+ # Machine-readable source of truth. Mirrors docs/specs/black-smith-architecture.md
4
+ # §8 value-for-value; if they diverge, that is a bug — fix both in the same PR.
5
+ #
6
+ # Closed, versioned, multi-dimension controlled vocabulary. Every event, task,
7
+ # error, finding, and lesson carries tags from these dimensions; the event
8
+ # logger rejects unknown tags at write time so analytics stay aggregatable
9
+ # across months of runs. Changing the taxonomy is a PR that bumps `version` —
10
+ # never a runtime write. Analytics may group only by taxonomy dimensions.
11
+
12
+ version: 9
13
+
14
+ # ── Work classification ─────────────────────────────────────────────
15
+ case: [feature, bugfix, refactor, research, spec-review, recheck,
16
+ chore, infra]
17
+ origin: [user, inferred, recheck, lesson, escalation]
18
+ # user — operator asked for it
19
+ # inferred — planner added it to protect acceptance criteria
20
+ # recheck — scheduler re-opened a completed feature
21
+ # lesson — an approved lesson demanded follow-up work
22
+ # escalation— created by the escalation ladder (e.g. re-scope)
23
+
24
+ # ── Actors ──────────────────────────────────────────────────────────
25
+ agent: [planner, spec-reviewer, researcher, coder, tester, grader,
26
+ reviewer, verifier, security-reviewer, merger, scribe, uiux,
27
+ wave-runner, auditor]
28
+ # wave-runner — the only role delegation.yml grants `Agent`: it
29
+ # runs one wave of .claude/skills/bs/wave.md in its own session
30
+ # auditor — one axis of `/bs audit` (performance, code-quality or
31
+ # architecture); the security axis dispatches security-reviewer
32
+
33
+ provider: [claude, codex, deepseek]
34
+ model_tier: [frontier, mid, small] # fable/opus · sonnet · haiku
35
+
36
+ # ── Lifecycle (three distinct state machines — never conflated) ─────
37
+ task_status: [todo, ready, in-progress, grading, reviewing, merging,
38
+ blocked, completed, waived, failed, escalated, superseded]
39
+ # superseded — replaced by a task in a newer plan version
40
+ plan_status: [draft, in-review, active, superseded] # plans are immutable
41
+ run_status: [queued, running, done, dead] # one worker run
42
+
43
+ # ── Graph (event-log first-class, §7) ───────────────────────────────
44
+ edge_type: [artifact, claim-order, spec-clause, regression-test,
45
+ research-brief]
46
+ # artifact — T consumes an output S produced
47
+ # claim-order — serialized because claims overlapped
48
+ # spec-clause — T implements a specific spec clause
49
+ # regression-test— T must keep S's tests green
50
+ # research-brief — T depends on a researcher brief
51
+ edge_provenance: [observed, declared, inferred]
52
+ # observed — runner saw the handoff happen
53
+ # declared — spec stated it up front
54
+ # inferred — reconstructed after the fact (lowest trust)
55
+ graph_event: [plan-version-created, plan-version-superseded,
56
+ task-added, task-split, task-superseded, edge-recorded,
57
+ wave-admitted, wave-merged,
58
+ spec-change-proposed, spec-change-decided]
59
+ # spec-change-proposed — a worker hit a wrong assumption and
60
+ # returned a spec diff. Data, not a
61
+ # command: no plan file moves (D-33)
62
+ # spec-change-decided — the operator approved or rejected
63
+ # one. Approval is what calls the
64
+ # amendment; the version is still cut
65
+ # by `plan amend` alone
66
+
67
+ # ── Gates (event-log first-class, §11 — added Phase 4) ───────────────
68
+ gate_event: [schema-check-result, artifact-check-result,
69
+ commit-check-result, deps-check-result,
70
+ judges-outstanding, grader-verdict, budget-check-result,
71
+ testgate-result, coverage-evidence, integration-check,
72
+ spec-review-recorded, goal-check-recorded, quorum-decision,
73
+ finding-raised, finding-reverified, finding-suppressed,
74
+ finding-transitioned, finding-reattributed,
75
+ severity-decisions, waiver-granted, waiver-denied,
76
+ gate-outcome]
77
+ # schema-check-result — task Result vs result.schema.json
78
+ # artifact-check-result — every artifacts[].path in that
79
+ # Result, resolved against the task's
80
+ # home under state/artifacts/ and
81
+ # checked to exist. Emitted even when
82
+ # the task declared none: a check that
83
+ # only speaks up when it has something
84
+ # to say is indistinguishable, later,
85
+ # from a check that never ran (P9-22)
86
+ # commit-check-result — is there a commit here to score? the
87
+ # worktree is clean and its branch is
88
+ # ahead of the base (D-30, P9-8)
89
+ # deps-check-result — the worktree owns the toolchain its
90
+ # checks are about to run (P9-16d);
91
+ # always logged, including when the
92
+ # project declares nothing to install
93
+ # judges-outstanding — a judge this task dispatched through
94
+ # `smith judge dispatch` never reported
95
+ # back, so the gate refuses to score an
96
+ # unknown: a missing `--evidence` reads
97
+ # identically whether the judge found
98
+ # nothing or died mid-turn. Names each
99
+ # owed role/round. A task that
100
+ # dispatched no judges is unaffected —
101
+ # this refuses only where there is a
102
+ # promise on record (D-31/D-20, P9-11)
103
+ # grader-verdict — the grader's rubric result vs
104
+ # grader-verdict.schema.json, and
105
+ # whether the acceptance criteria were
106
+ # met. Runs BEFORE the test gate: a
107
+ # not-met rubric bounces the diff
108
+ # whatever the suite says (D-34)
109
+ # budget-check-result — declared caps vs measured spend:
110
+ # token_usage off the Result, authored
111
+ # diff lines off git. Recorded, never
112
+ # blocking, and emitted even when the
113
+ # plan declared no budget or the diff
114
+ # could not be measured — "not-declared"
115
+ # and "unmeasurable" are outcomes, not
116
+ # silence (P9-18). "unmeasuredFiles"
117
+ # names the counted paths git gave no
118
+ # lines for, so a cap that passed on a
119
+ # binary file's zero is auditable
120
+ # (D-157)
121
+ # testgate-result — check-command run (test gate)
122
+ # coverage-evidence — the numbers behind the green: which
123
+ # subject files the coverage summary
124
+ # actually measured, and whether it is
125
+ # complete. Emitted after the tests
126
+ # pass and before the findings are
127
+ # judged, because a green run that
128
+ # cannot name a number for the file the
129
+ # acceptance criterion is about has not
130
+ # answered it (D-40, P9-25)
131
+ # integration-check — the check suite run at the PROJECT
132
+ # ROOT against smith/<epic>/integration,
133
+ # pinned to the head sha it covers.
134
+ # Every other gate event above is a
135
+ # claim about a task worktree; this is
136
+ # the only one about the assembled
137
+ # branch, and epic verdict holds
138
+ # without a current passing one (D-42)
139
+ # spec-review-recorded— a spec-reviewer dispatch finished,
140
+ # pinned to the head sha it read.
141
+ # Recorded even when it found nothing,
142
+ # so "ran and was clean" is
143
+ # distinguishable from "never ran"
144
+ # goal-check-recorded — the epic's plan was checked against
145
+ # the goal its roadmap milestone
146
+ # declares, clause by clause. The one
147
+ # gate whose reference text the planner
148
+ # did not author, so a plan that is
149
+ # internally consistent but answers the
150
+ # wrong question still fails it.
151
+ # Carries the goal digest it read, so a
152
+ # reworded goal invalidates the check
153
+ # the same way a new plan version does
154
+ # quorum-decision — one cross-provider quorum case closed:
155
+ # who voted, on what, and whether the
156
+ # finding survived. Emitted exactly once
157
+ # per case, including when the case
158
+ # could not be decided — an
159
+ # `insufficient-providers` outcome is a
160
+ # recorded fact, not an absent one. Runs
161
+ # over findings at the task gate
162
+ # (gate.ts) and over plan-cut and
163
+ # epic-close verdicts (planQuorum.ts,
164
+ # epic.ts)
165
+ # finding-raised — a new finding entered the log
166
+ # finding-reverified — a human re-read an open finding
167
+ # against the current code. Not a
168
+ # finding_status change: `confirmed`
169
+ # cannot be re-entered and `refuted`
170
+ # means the finding was wrong, so
171
+ # "still reproduces" needs an event of
172
+ # its own. It re-dates the finding's
173
+ # evidence, which is what clears the
174
+ # stale-evidence bar on a waiver grant
175
+ # once a wave has merged over its file
176
+ # (P9-15)
177
+ # finding-suppressed — raise attempt matched a waived
178
+ # fingerprint; logged, not appended
179
+ # as a duplicate raised finding
180
+ # finding-transitioned— finding_status state change
181
+ # finding-reattributed— the finding moved to the task that
182
+ # owns the file, or to a follow-up task
183
+ # minted for it when nobody open could
184
+ # take it. Without this event the log
185
+ # shows a finding sitting under a task
186
+ # that was never gated, and no trace of
187
+ # how it got there (attribution.ts)
188
+ # severity-decisions — gate.ts's per-finding severity
189
+ # verdicts for one task (block /
190
+ # waiver-batch / log-only)
191
+ # waiver-granted/-denied — operator waiver-batch answer,
192
+ # keyed by finding fingerprint
193
+ # gate-outcome — the composed gate pipeline's
194
+ # final structured result
195
+
196
+ # ── Errors: grouped two-level classes (always logged as group.class) ─
197
+ error:
198
+ spec: [spec-gap, spec-ambiguity, spec-conflict,
199
+ missing-nonfunctional]
200
+ # missing-nonfunctional — security/validation/authz clause
201
+ # absent from the contract (implicit clauses get dropped)
202
+ contract: [schema-violation, claim-violation, constraint-decay,
203
+ write-root-violation, judge-mutation, uncited-claim,
204
+ unsourced-recommendation, uncommitted-work]
205
+ # constraint-decay — agent stopped honoring a standing
206
+ # architectural constraint mid-epic
207
+ # write-root-violation — a role that works outside a worktree
208
+ # (planner, scribe) wrote outside its declared write root
209
+ # (P9-3); shipped as a code before it was a class
210
+ # judge-mutation — a read-only judge moved the worktree it
211
+ # was judging (P9-5, `smith worktree verify`)
212
+ # uncited-claim — a researcher finding with no citation, or a
213
+ # citation that is neither a repo path with a line number nor
214
+ # a URL actually fetched (P9-6, `smith research check`)
215
+ # unsourced-recommendation — a brief's recommendation names no
216
+ # finding, or names one the brief does not carry, so what came
217
+ # from fetched text is invisible (P9-6)
218
+ # uncommitted-work — a task reported done with work still in
219
+ # the working tree, or with a branch head no further along
220
+ # than the base it was cut from; the gate scored a worktree
221
+ # the queue would have merged as a no-op (D-30, P9-8)
222
+ execution: [test-failure, regression, flaky-test, tool-failure,
223
+ env-failure]
224
+ # regression — previously-passing behavior broken (the
225
+ # dominant multi-round failure mode)
226
+ integration: [merge-conflict-textual, merge-conflict-semantic,
227
+ stack-misorder]
228
+ # semantic — textually clean merge, broken behavior
229
+ economy: [budget-exceeded, diff-cap-exceeded, over-engineering,
230
+ context-overrun]
231
+ judgment: [hallucination, false-positive-finding, missed-finding,
232
+ reward-hacking, same-mistake, provider-disagreement]
233
+ # reward-hacking — letter of the tests, spirit of nothing
234
+ coordination: [deadlock, livelock, starvation]
235
+ memory: [lesson-contamination, lesson-stale, poisoning-suspected]
236
+
237
+ # ── Review ──────────────────────────────────────────────────────────
238
+ finding_category: [correctness, security, a11y, performance, visual-design,
239
+ behavioral-drift, test-coverage, over-engineering,
240
+ maintainability]
241
+ # visual-design — the rendered result departs from the
242
+ # uiux spec. Named for the spec, not for a design system:
243
+ # which one a project uses is an install-time answer in
244
+ # factory/policies/stack.yml, and `none` is one of them.
245
+ # behavioral-drift — changed input validation / error
246
+ # handling relative to surrounding code; invisible to
247
+ # static metrics, the measured driver of agent-code debt
248
+ finding_scope: [diff, spec]
249
+ # diff — the code is wrong; the fix belongs in a task diff
250
+ # spec — the code is right and the PLAN is wrong. Routed to
251
+ # the planner and the operator, never to the task gate:
252
+ # blocking a diff that cannot legally contain the fix is
253
+ # the D-33 deadlock. A finding written before this
254
+ # dimension existed carries no scope and reads as `diff`.
255
+ finding_status: [raised, refuted, confirmed, fix-pending, fix-landed,
256
+ fix-verified, waived, expired, amend-pending, amended]
257
+ # closes only at fix-verified, waived or amended — a review
258
+ # that fired without uptake is not a closed finding
259
+ # amended — a spec finding whose criterion moved in a new
260
+ # plan version. Spec-scoped only, and the one exit for an
261
+ # S1/S2 spec finding, which is categorically unwaivable
262
+ # amend-pending — that plan version has been cut and cites
263
+ # the finding, but the task ids the amendment added or
264
+ # superseded have not landed yet. A spec finding's
265
+ # `fix-pending`, and reachable only from raised/confirmed.
266
+ # Without it `amended` was reachable at plan-write time, so
267
+ # the unwaivable class closed on a sentence (D-127)
268
+ severity: [S1-stop-the-line, S2-major, S3-minor, S4-nit]
269
+ # S1 — repo corruption, secret leak, guardrail breach
270
+ # S2 — blocks merge (security/data-loss, broken core
271
+ # flow, a11y AA failure, new flaky test)
272
+ # S3 — real but waivable; batched to operator at epic end
273
+ # S4 — nits the project's linter misses; logged, never asked
274
+
275
+ # ── Lessons / memory (typed — one type per entry, never mixed) ──────
276
+ lesson_type: [fact, event, rule]
277
+ # fact — stable truth about a repo/stack ("D1 lacks X")
278
+ # event — dated occurrence ("epic-7 hit deadlock via Y")
279
+ # rule — imperative, checkable principle ("never edit
280
+ # lockfiles in workers")
281
+ lesson_level: [principle] # instance-level (transcript) entries are
282
+ # rejected at the gate — they cause
283
+ # capability collapse when accumulated
284
+ lesson_status: [candidate, novelty-rejected, pending-approval, approved,
285
+ superseded, invalidated]
286
+ lesson_scope: [agent-role, claim-path, case-type, stack-wide, security]
287
+ # `security` cuts across roles: coder, reviewer
288
+ # and security-reviewer all want the same auth
289
+ # lesson, so it is not an agent-role lesson
290
+
291
+ # ── Dimension rules (§8 "Dimension rules", normative) ────────────────
292
+ # 1. Required dimensions per record type (validated at write):
293
+ # task -> case + origin + task_status
294
+ # dispatch -> agent + provider + model_tier + model
295
+ # `model` is the concrete model id, presence-checked only,
296
+ # NOT a closed dimension: model names change monthly and a
297
+ # frozen enum would reject next month's model or, worse,
298
+ # get the field dropped instead. The tier alone can't
299
+ # answer "did the critic run on the finder's model?" —
300
+ # opus and fable are both `frontier` (P9-23).
301
+ # error -> error(group.class) + severity + task ref
302
+ # finding -> finding_category + severity + finding_status
303
+ # lesson -> lesson_type + lesson_level + lesson_status + lesson_scope
304
+ # + provenance event ids
305
+ # edge -> edge_type + edge_provenance
306
+ # 2. One value per dimension — a record needing two values is two records
307
+ # or a wrongly-cut dimension; fix the taxonomy by PR, don't overload tags.
308
+ # 3. Renames are supersessions — a value is never deleted or renamed in
309
+ # place; it's marked deprecated in this file with a `superseded_by`, so
310
+ # old events stay queryable.
311
+ rules:
312
+ required_dimensions:
313
+ task:
314
+ - case
315
+ - origin
316
+ - task_status
317
+ dispatch:
318
+ - agent
319
+ - provider
320
+ - model_tier
321
+ - model
322
+ error:
323
+ - error
324
+ - severity
325
+ - task_ref
326
+ finding:
327
+ - finding_category
328
+ - severity
329
+ - finding_status
330
+ lesson:
331
+ - lesson_type
332
+ - lesson_level
333
+ - lesson_status
334
+ - lesson_scope
335
+ - provenance_event_ids
336
+ edge:
337
+ - edge_type
338
+ - edge_provenance
339
+ one_value_per_dimension: true
340
+ renames_are_supersessions: true
@@ -0,0 +1,95 @@
1
+ # Blacksmith — worktree + merge-queue policy
2
+ #
3
+ # architecture §5 "Worktree partitioning (no overlap, no conflicts)".
4
+ # Conflicts are prevented at planning time, not resolved at merge time.
5
+
6
+ worktree:
7
+ # D-42 correction (phase 9): worktrees live OUTSIDE the project root, as a
8
+ # sibling of it. They used to be at "<project>/wt/<task-id>" — inside
9
+ # the root — and each one is a full checkout carrying the project's
10
+ # own tool config. A tool that walks down from the project root therefore
11
+ # found N+1 root configs and refused to run: the envkit epic's `pnpm lint`
12
+ # exited 1 at the integration root without reading a source file, while all
13
+ # six per-task lint gates were green (from inside a worktree, the siblings
14
+ # are not descendants, so no task gate could see it). A sibling path is one
15
+ # no root-walking tool can reach without climbing up, which retires the
16
+ # class rather than the one tool.
17
+ # Relative to whatever directory the project was handed as, never to this
18
+ # clone: a project beside the repo keeps its worktrees beside the repo too.
19
+ path_pattern: "<project-parent>/.wt/<project>/<task-id>"
20
+ branch_pattern: "smith/<epic>/<task-id>"
21
+ created_from: integration branch head (smith/<epic>/integration), fresh each time
22
+ lifecycle: deleted after merge — a stale worktree is a bug
23
+ one_worktree_per_task: true
24
+
25
+ integration_branch:
26
+ # Phase-3 correction: a bare "smith/<epic>" ref cannot coexist with
27
+ # "smith/<epic>/<task-id>" refs — git's ref namespace is hierarchical, so a
28
+ # leaf ref and a directory prefix of the same name conflict (D/F conflict,
29
+ # confirmed against a real git repo while implementing worktree.ts). The
30
+ # integration branch is therefore a sibling of task branches under the
31
+ # epic's ref prefix, not a leaf at "smith/<epic>" itself.
32
+ pattern: "smith/<epic>/integration"
33
+ rule: workers never touch main/master; only the operator merges the
34
+ integration PR into the target repo's main.
35
+
36
+ claims:
37
+ disjointness_required: true
38
+ computed_from: static analysis (import/dependency graph) over the target
39
+ repo, cut along low-cohesion lines (community detection) — never
40
+ assigned from epic text alone.
41
+ overlap_handling: >
42
+ tasks with overlapping claims are never scheduled concurrently; they
43
+ get a dependency edge (edge_type: claim-order) and run serially instead.
44
+ enforcement: >
45
+ a post-run check diffs the worktree against its declared claims;
46
+ out-of-claim edits fail the gate (error contract.claim-violation,
47
+ severity S3 unless the edit touches a guardrail-protected file, then S1)
48
+ and bounce back to the coder.
49
+
50
+ serialize_always_globs:
51
+ # shared-file hotspots (architecture §5.5) — any task touching these is
52
+ # never scheduled concurrently with another such task.
53
+ globs:
54
+ # Every lockfile, not just the two this repo happens to write: on a
55
+ # yarn or bun project the file two tasks collide over is theirs.
56
+ - "**/pnpm-lock.yaml"
57
+ - "**/package-lock.json"
58
+ - "**/yarn.lock"
59
+ - "**/bun.lock"
60
+ - "**/bun.lockb"
61
+ - "**/*.generated.*"
62
+ - "**/dist/**"
63
+ - "db/migrations/**"
64
+ - "src/routes/**/index.ts" # route registries
65
+ - "src/types/**" # shared types (hub files)
66
+ - "src/config/**" # shared config (hub files)
67
+ - "tests/fixtures/**" # shared fixtures (hub files)
68
+ note: >
69
+ Hub files are structurally central (types, config, shared fixtures,
70
+ route registries) and are never split across concurrent tasks — single
71
+ owner, or regenerated by the merge queue (regenerable files like
72
+ lockfiles are never hand-edited by workers).
73
+
74
+ merge_queue:
75
+ mode: serial
76
+ order: dependency order (topological, per recorded edges)
77
+ admission_steps:
78
+ - rebase task branch onto current smith/<epic>/integration head
79
+ - run the cumulative regression gate (every previously merged task's
80
+ tests in this epic, not just the incoming task)
81
+ - admit on green; reject and bounce on red
82
+ conflict_resolution_ladder:
83
+ - step: automatic rebase attempt
84
+ - step: dispatch merger agent with both diffs + both task specs
85
+ - step: >
86
+ escalate to operator with a side-by-side when merger confidence is
87
+ low or both sides changed the same logic — never auto-resolve a
88
+ semantic conflict silently
89
+ stacked_layers:
90
+ enabled: true
91
+ max_lines_per_layer: 200
92
+ note: >
93
+ workers emit small stacked layers (within the 400-line task diff cap)
94
+ rather than monolithic diffs; the queue lands stacks in dependency
95
+ order (GitHub native stacked PRs).
@@ -0,0 +1,34 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ # `setup` is the branch this project's first commit lands on, and the first
7
+ # one pushed; naming only `main` meant this workflow could not fire at all
8
+ # on a fresh project, because a fresh project has no main yet. Both are
9
+ # named so CI covers the whole life of the repo, not just the half after
10
+ # the first merge.
11
+ branches: [main, setup]
12
+
13
+ jobs:
14
+ check:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: pnpm/action-setup@v4
19
+ - uses: actions/setup-node@v4
20
+ with:
21
+ node-version: 22
22
+ cache: pnpm
23
+ # --frozen-lockfile is safe here: the install runs before the first
24
+ # commit, so pnpm-lock.yaml is already in it.
25
+ - run: pnpm install --frozen-lockfile
26
+ - run: pnpm run lint
27
+ - run: pnpm run typecheck
28
+ - run: pnpm run typecheck:test
29
+ # Runs the suite AND enforces the coverage floor vitest.config.ts
30
+ # declares — a separate `pnpm run test` step would only pay for the suite
31
+ # twice, and leaving coverage out is how a declared floor ends up enforced
32
+ # by nothing at all.
33
+ - run: pnpm run test:coverage
34
+ - run: pnpm run build
@@ -0,0 +1,11 @@
1
+ # dependencies / build
2
+ node_modules/
3
+ dist/
4
+ .wrangler/
5
+ coverage/
6
+
7
+ # local env + editor
8
+ .env
9
+ .env.*
10
+ .DS_Store
11
+ *.log
@@ -0,0 +1,33 @@
1
+ # __PROJECT_NAME__ — Agent Router
2
+
3
+ Thin router (progressive disclosure) — read detail files on demand, do not
4
+ preload this repo's whole context.
5
+
6
+ ## Stack
7
+
8
+ TypeScript, `strict: true`. pnpm. Biome (lint + format). Vitest (unit tests).
9
+ GitHub Actions CI runs lint + typecheck + test + build on every PR
10
+ (`.github/workflows/ci.yml`).
11
+
12
+ ## Layout
13
+
14
+ | Path | What |
15
+ |---|---|
16
+ | `src/` | Application code |
17
+ | `test/` | Vitest unit tests, mirrors `src/` |
18
+
19
+ ## Rules
20
+
21
+ - **TDD.** A failing test exists before the implementation that makes it
22
+ pass — no production code without one.
23
+ - **Strict YAGNI.** Build exactly what the task spec asks for; no unspecced
24
+ abstractions, config options, or drive-by refactors.
25
+ - **Language.** Code, comments, and commits are English.
26
+ - **Commits.** Subject <=72 chars, imperative, why-focused.
27
+
28
+ ## Gate
29
+
30
+ Every change clears the same five steps CI runs, and clears them locally
31
+ first: `pnpm run lint`, `pnpm run typecheck`, `pnpm run typecheck:test`,
32
+ `pnpm run test:coverage`, `pnpm run build`. Green here or it is not ready to
33
+ propose.
@@ -0,0 +1,25 @@
1
+ # __PROJECT_NAME__
2
+
3
+ ## Getting started
4
+
5
+ ```sh
6
+ pnpm install
7
+ pnpm test
8
+ ```
9
+
10
+ ## Checks
11
+
12
+ | Command | What it answers |
13
+ | --- | --- |
14
+ | `pnpm run lint` | Does it meet the style and correctness rules Biome enforces? |
15
+ | `pnpm run typecheck` | Does `src/` typecheck under `strict: true`? |
16
+ | `pnpm run typecheck:test` | Does `test/` typecheck too? |
17
+ | `pnpm run test:coverage` | Does the suite pass, and clear the coverage floor? |
18
+ | `pnpm run build` | Does it compile? |
19
+
20
+ CI runs all five on every pull request. Run them locally first — see
21
+ [`AGENTS.md`](AGENTS.md) for the conventions this project holds itself to.
22
+
23
+ ---
24
+
25
+ Built by blacksmith
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.5.6/schema.json",
3
+ "vcs": {
4
+ "enabled": true,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": true
7
+ },
8
+ "files": {
9
+ "includes": ["*.ts", "src/**/*.ts", "test/**/*.ts", "!dist"]
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "indentStyle": "space",
14
+ "indentWidth": 2,
15
+ "lineWidth": 100
16
+ },
17
+ "linter": {
18
+ "enabled": true,
19
+ "rules": {
20
+ "preset": "recommended"
21
+ }
22
+ },
23
+ "javascript": {
24
+ "formatter": {
25
+ "quoteStyle": "single",
26
+ "semicolons": "always",
27
+ "trailingCommas": "all"
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -p tsconfig.json",
11
+ "typecheck": "tsc --noEmit",
12
+ "typecheck:test": "tsc -p tsconfig.test.json",
13
+ "test": "vitest run",
14
+ "test:coverage": "vitest run --coverage",
15
+ "lint": "biome check ."
16
+ },
17
+ "dependencies": {},
18
+ "devDependencies": {
19
+ "@biomejs/biome": "2.5.6",
20
+ "@types/node": "26.1.2",
21
+ "@vitest/coverage-v8": "4.1.10",
22
+ "typescript": "7.0.2",
23
+ "vitest": "4.1.10"
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ # This project is its own pnpm workspace root, and says so on purpose.
2
+ #
3
+ # pnpm finds a workspace by walking UP from the current directory until it
4
+ # hits a `pnpm-workspace.yaml`. A checkout that sits anywhere below another
5
+ # workspace root inherits it: that root's lockfile gets rewritten, this
6
+ # project's dependencies get linked into that root's `node_modules`, and
7
+ # every check afterwards measures a toolchain this project does not own. A
8
+ # root above with no `packages` is worse still — the same walk kills
9
+ # `pnpm install` outright with ERR_PNPM_INVALID_WORKSPACE_CONFIGURATION
10
+ # before it resolves a single dependency.
11
+ #
12
+ # `.` is the whole list: one package, this one. It stays correct wherever the
13
+ # checkout ends up, including on its own remote with nothing above it.
14
+ # Add entries here if this project ever grows a monorepo of its own.
15
+ packages:
16
+ - '.'
@@ -0,0 +1,4 @@
1
+ /** Scaffold stub — replace with the project's first real module. */
2
+ export function ping(): string {
3
+ return 'pong';
4
+ }
@@ -0,0 +1,8 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ping } from '../src/index.js';
3
+
4
+ describe('ping', () => {
5
+ it('returns pong', () => {
6
+ expect(ping()).toBe('pong');
7
+ });
8
+ });
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "skipLibCheck": true,
11
+ "resolveJsonModule": true,
12
+ "esModuleInterop": true,
13
+ "declaration": true,
14
+ "sourceMap": false,
15
+ "rootDir": "src",
16
+ "outDir": "dist",
17
+ "types": ["node"]
18
+ },
19
+ "include": ["src/**/*.ts"]
20
+ }