@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,239 @@
1
+ # Compiled Lessons
2
+
3
+ > Generated, committed file. This is the compiled output of the approved
4
+ > lesson queue — the operator approves candidates in the UI (Lessons page,
5
+ > architecture §10); the scribe compiles approvals here, sectioned by scope.
6
+ > Never hand-edit an entry's content directly; edit the source lesson and
7
+ > recompile, so `valid_from`/`superseded_by`/provenance stay accurate.
8
+
9
+ ## Schema
10
+
11
+ Every entry below is one lesson (`factory/specs/schema/lesson.schema.json`):
12
+
13
+ - **Typed, one type per entry, never mixed** — `lesson_type`: `fact` (stable
14
+ truth about a repo/stack, e.g. "D1 lacks X"), `event` (dated occurrence,
15
+ e.g. "epic-7 hit deadlock via Y"), or `rule` (imperative, checkable
16
+ principle, e.g. "never edit lockfiles in workers").
17
+ - **Principle-level only** (`lesson_level: principle`) — instance-level
18
+ transcripts are rejected at the novelty gate before reaching this file;
19
+ naive experience accumulation measurably degrades agents (architecture §9,
20
+ §17).
21
+ - **Bi-temporal fields**: `valid_from` (when the lesson took effect) and
22
+ `superseded_by` (the lesson_id that replaced it, or null) — a lesson is
23
+ never deleted or silently edited, only superseded or `invalidated` with a
24
+ pointer to the invalidating event.
25
+ - **Provenance**: `provenance_event_ids` — the event-log entries that
26
+ produced the lesson, so every entry here is traceable back to a decision
27
+ checkpoint or logged error, never asserted from nowhere.
28
+ - **Injection is step-wise, not global preamble**: each entry's `lesson_scope`
29
+ (`agent-role` | `claim-path` | `case-type` | `stack-wide` | `security`)
30
+ determines where it is surfaced — e.g. a coder gets claim-path-scoped rules
31
+ at dispatch, a merger gets integration rules at queue time. Standing
32
+ architectural constraints are re-asserted in every task contract, never
33
+ stated once per epic (constraint-decay countermeasure).
34
+
35
+ Entries are grouped by `lesson_scope` below; a scope with no approved lesson
36
+ renders as an empty section rather than disappearing, so the set of scopes
37
+ this file can carry is visible whether or not anything occupies them.
38
+
39
+ ### Same-mistake entry format (Phase 4, `factory/orchestrator/src/severity.ts`)
40
+
41
+ The severity gate's same-mistake escalation (architecture §9.7, §11) parses
42
+ this file's compiled entries at gate time — match = a `rule`-typed entry's
43
+ scope covers the file the new finding touches AND its `finding_category`
44
+ equals the new finding's category. So the scribe compiles each `rule` entry
45
+ as a level-3 heading followed by a flat `key: value` bullet list, terminated
46
+ by the next heading or end of file (a blank line does NOT end the entry —
47
+ see the multi-line `statement` below, whose continuation line is indented
48
+ and gets folded back onto the bullet it follows), e.g.:
49
+
50
+ ```
51
+ ### Never hand-edit a lockfile in a worker
52
+
53
+ - lesson_id: lesson-2026-08-01-003
54
+ - finding_category: maintainability
55
+ - claim_path: **/pnpm-lock.yaml
56
+ - statement: Lockfiles are regenerable and regenerated by the merge queue;
57
+ a worker editing one directly is always a mistake, not a judgment call.
58
+ ```
59
+
60
+ `claim_path` is a glob (matched with `picomatch`, same engine as
61
+ `claims.ts`); required for `claim-path`-scoped entries, and treated as
62
+ `**` (covers every file) for `stack-wide`- and `security`-scoped entries
63
+ where it is omitted. `agent-role`/`case-type`-scoped entries do not
64
+ participate in this per-file match (no file to check against) and are parsed
65
+ but never matched by `severity.ts` — they exist here for prompt injection
66
+ only.
67
+
68
+ ### Every scope carries its own selector
69
+
70
+ Three of the five scopes are *selectors*, and a selector needs something to
71
+ select on. Each names its own bullet, validated against `taxonomy.yml`:
72
+
73
+ | scope | selector bullet | taxonomy dimension |
74
+ | --- | --- | --- |
75
+ | `claim-path` | `claim_path` | — (a glob) |
76
+ | `agent-role` | `agent_role` | `agent` |
77
+ | `case-type` | `case_type` | `case` |
78
+ | `stack-wide` | none — applies to every dispatch | — |
79
+ | `security` | none — cross-role by design | — |
80
+
81
+ At dispatch, an `agent-role` entry reaches only the role its `agent_role`
82
+ names, and a `case-type` entry only a task whose `case` its `case_type`
83
+ names. An entry in one of those scopes with **no** selector reaches NOBODY —
84
+ it is inert, not universal, and `smith lessons for-dispatch` reports it as
85
+ such. `smith lessons raise` refuses to mint one; the entries that predate
86
+ the selector (D-129) are the only ones that can still be in that state.
87
+
88
+ Two kinds of entry are therefore injected at dispatch and still never
89
+ escalate anything — by design, not by accident:
90
+
91
+ - an `agent-role`- or `case-type`-scoped entry, per the paragraph above; and
92
+ - **any entry with no `finding_category`**, whatever its scope — the match
93
+ above is an equality against the new finding's category, so an entry naming
94
+ no category is skipped before its claim path is ever consulted.
95
+
96
+ A broad principle usually belongs in the second kind. An entry that pairs a
97
+ category with `claim_path: **` escalates *every* repeat finding of that
98
+ category anywhere in the repo — a gate that fires on everything distinguishes
99
+ nothing.
100
+
101
+ ## agent-role
102
+
103
+ ### lesson-raised-8c05427c2840: A check that silently borrows its tools from the inspector is measuri...
104
+
105
+ - lesson_id: lesson-raised-8c05427c2840
106
+ - agent_role: grader
107
+ - statement: A check that silently borrows its tools from the inspector is measuring the inspector.
108
+
109
+ ### lesson-dream-dogfood-demo-rpg-1-40: A judge's output contract fixes where the verdict sits as strictly as...
110
+
111
+ - lesson_id: lesson-dream-dogfood-demo-rpg-1-40
112
+ - agent_role: grader
113
+ - statement: A judge's output contract fixes where the verdict sits as strictly as what it says: a correct verdict at the wrong key is read as no verdict at all.
114
+
115
+ ## claim-path
116
+
117
+ ### lesson-raised-3b5746704cfc: A function that computes a filesystem path and hands it to a child pr...
118
+
119
+ - lesson_id: lesson-raised-3b5746704cfc
120
+ - claim_path: **
121
+ - statement: A function that computes a filesystem path and hands it to a child process running with a different cwd must resolve it to absolute first.
122
+
123
+ ### lesson-raised-8460b7c5cd04: A `**/name*/**` glob matches a directory, never a file of that name.
124
+
125
+ - lesson_id: lesson-raised-8460b7c5cd04
126
+ - claim_path: **
127
+ - statement: A `**/name*/**` glob matches a directory, never a file of that name.
128
+
129
+ ### lesson-raised-a8ca3a355263: An identifier that is parsed rather than passed will eventually be pa...
130
+
131
+ - lesson_id: lesson-raised-a8ca3a355263
132
+ - claim_path: **
133
+ - statement: An identifier that is parsed rather than passed will eventually be parsed by two functions that disagree, and the disagreement surfaces at the join — the last step, and the most expensive place to find it.
134
+
135
+ ### lesson-raised-fe5cf8b630fe: A wrapper that collapses a child's exit signal into an exit code has ...
136
+
137
+ - lesson_id: lesson-raised-fe5cf8b630fe
138
+ - claim_path: **
139
+ - statement: A wrapper that collapses a child's exit signal into an exit code has deleted the only evidence that distinguishes a crash from a failure, and every diagnosis downstream of it will be about the wrong subsystem.
140
+
141
+ ## case-type
142
+
143
+ _(none yet)_
144
+
145
+ ## stack-wide
146
+
147
+ ### lesson-raised-53d48e95c31f: Measured spend is a floor, not a total; a check that treats it as a t...
148
+
149
+ - lesson_id: lesson-raised-53d48e95c31f
150
+ - statement: Measured spend is a floor, not a total; a check that treats it as a total reports "under budget" most confidently on exactly the runs whose unrecorded half is what blew the budget.
151
+
152
+ ### lesson-raised-8a3f8df1fc0e: A differential acceptance criterion must state what the failing outpu...
153
+
154
+ - lesson_id: lesson-raised-8a3f8df1fc0e
155
+ - statement: A differential acceptance criterion must state what the failing output says under the hypothesis and under the null; if the two are the same text, the criterion is vacuous.
156
+
157
+ ### lesson-raised-cbdae7931913: A constraint stated only in a prompt is a request; if the plan writes...
158
+
159
+ - lesson_id: lesson-raised-cbdae7931913
160
+ - statement: A constraint stated only in a prompt is a request; if the plan writes it down like a limit, something has to be able to say no.
161
+
162
+ ### lesson-raised-f6b72d19c070: When one stage verifies state A and the next ships state B, the pipel...
163
+
164
+ - lesson_id: lesson-raised-f6b72d19c070
165
+ - statement: When one stage verifies state A and the next ships state B, the pipeline is correct only by coincidence.
166
+
167
+ ### lesson-raised-c60ff6d8cd89: A supervisor that cannot tell silence from assent will eventually mis...
168
+
169
+ - lesson_id: lesson-raised-c60ff6d8cd89
170
+ - statement: A supervisor that cannot tell silence from assent will eventually mistake a corpse for a quorum.
171
+
172
+ ### lesson-raised-c599f971488d: Never ask a component for a fact it has no instrument to measure; it ...
173
+
174
+ - lesson_id: lesson-raised-c599f971488d
175
+ - statement: Never ask a component for a fact it has no instrument to measure; it will not refuse, it will estimate, and the estimate will look exactly like data.
176
+
177
+ ### lesson-raised-e0befb1eb07f: A controlled vocabulary that is referenced but never shown is a vocab...
178
+
179
+ - lesson_id: lesson-raised-e0befb1eb07f
180
+ - statement: A controlled vocabulary that is referenced but never shown is a vocabulary the writer will reinvent.
181
+
182
+ ### lesson-raised-26ace63a7a67: Plan immutability is a promise to the builder, not to reality; a syst...
183
+
184
+ - lesson_id: lesson-raised-26ace63a7a67
185
+ - statement: Plan immutability is a promise to the builder, not to reality; a system that can only blame the builder will deadlock the moment the plan is what is wrong.
186
+
187
+ ### lesson-raised-4b7fa22305e5: Two features that each refuse to guess can still deadlock, because re...
188
+
189
+ - lesson_id: lesson-raised-4b7fa22305e5
190
+ - statement: Two features that each refuse to guess can still deadlock, because refusing is not the same as agreeing on who decides; a system that mints work in one component and validates it in another must share one answer to "does this task exist", not two correct ones.
191
+
192
+ ### lesson-dream-dogfood-demo-rpg-1-31: Producing a file and delivering it are separate acts: the artifact ch...
193
+
194
+ - lesson_id: lesson-dream-dogfood-demo-rpg-1-31
195
+ - statement: Producing a file and delivering it are separate acts: the artifact check resolves every declared path under the task's artifact home, so a Result that names a file living only in the worktree is indistinguishable from one that produced nothing.
196
+
197
+ ### lesson-dream-dogfood-demo-rpg-1-182: An acceptance criterion that has already been graded is a record of w...
198
+
199
+ - lesson_id: lesson-dream-dogfood-demo-rpg-1-182
200
+ - statement: An acceptance criterion that has already been graded is a record of what was checked, so a defect in its wording is corrected by an appended note, never by superseding the text the grader actually read.
201
+
202
+ ### lesson-raised-7c35d8a04a94: A command that creates an obligation must be validated against the co...
203
+
204
+ - lesson_id: lesson-raised-7c35d8a04a94
205
+ - statement: A command that creates an obligation must be validated against the command that discharges it for the same role, or accepting the registration is a deadlock rather than a contract.
206
+
207
+ ### lesson-raised-5111dfe40703: Judges may run concurrently against one worktree only while all of th...
208
+
209
+ - lesson_id: lesson-raised-5111dfe40703
210
+ - statement: Judges may run concurrently against one worktree only while all of them are read-only; the moment any probe must write, the whole set must be serialized, because the isolation protocol is per-judge and assumes no overlap.
211
+
212
+ ### lesson-raised-3bd5fc1b8057: A worktree verifier that compares before and after cannot see an edit...
213
+
214
+ - lesson_id: lesson-raised-3bd5fc1b8057
215
+ - statement: A worktree verifier that compares before and after cannot see an edit that was reverted in between, so a clean verdict is evidence about the endpoints and never evidence that a concurrent reader saw a clean tree.
216
+
217
+ ### lesson-raised-039f35d42340: A result produced during a contaminated window may be readmitted only...
218
+
219
+ - lesson_id: lesson-raised-039f35d42340
220
+ - statement: A result produced during a contaminated window may be readmitted only if its evidence axis is disjoint from every mutated path and each claim is re-verified against committed git objects rather than the working tree.
221
+
222
+ ### lesson-raised-576ea7016b55: A dispatch prompt that spells out schema field names becomes a second...
223
+
224
+ - lesson_id: lesson-raised-576ea7016b55
225
+ - statement: A dispatch prompt that spells out schema field names becomes a second, drifting copy of the schema, and the agent will faithfully emit the names it was given rather than the ones the validator knows.
226
+
227
+ ### lesson-raised-818285deeda6: A missing required field must fail at the boundary with an error that...
228
+
229
+ - lesson_id: lesson-raised-818285deeda6
230
+ - statement: A missing required field must fail at the boundary with an error that names it; passed downstream it surfaces as an unhandled TypeError inside a helper that never knew which field was absent.
231
+
232
+ ### lesson-raised-b8db8efe922d: An agent that owes a file should write it before refining it: the dec...
233
+
234
+ - lesson_id: lesson-raised-b8db8efe922d
235
+ - statement: An agent that owes a file should write it before refining it: the declared-artifact check catches an agent that ended on an intention only after the tokens are spent, and if that agent could write to shared state, only after the damage has spread.
236
+
237
+ ## security
238
+
239
+ _(none yet)_
@@ -0,0 +1,90 @@
1
+ # Blacksmith — scheduler policy
2
+ #
3
+ # Knobs for `factory/orchestrator/src/scheduler.ts` (architecture §12
4
+ # "Recheck scheduling" + "Scheduled growth passes"; `smith scheduler run`).
5
+ # A deterministic pass over the event log that only ever emits PROPOSAL
6
+ # events — it never dispatches an agent or widens scope on its own.
7
+
8
+ recheck:
9
+ # architecture §12: "re-open a recheck task when (a) N later merges touch
10
+ # its claim paths, (b) T days elapse, or (c) its confidence score at
11
+ # completion was below a threshold."
12
+ merge_threshold: 5 # (a) N later merges touching the same claim paths
13
+ days_elapsed: 14 # (b) T days since the feature completed
14
+ confidence_threshold: 0.6 # (c) completion confidence below this triggers a recheck
15
+
16
+ maintenance:
17
+ # agent-constraints.md "planner / Growth passes": maintenance-pass
18
+ # proposals may auto-schedule at high confidence; product-growth never
19
+ # does. Confidence here is scheduler.ts's own deterministic heuristic
20
+ # (major-version bumps present -> lower confidence), not a model verdict.
21
+ auto_schedule_confidence: 0.8
22
+ major_bump_confidence: 0.5
23
+ minor_or_patch_confidence: 0.9
24
+
25
+ growth:
26
+ # architecture §12 "product-growth pass": the scheduler only emits the
27
+ # growth-review-due TRIGGER event on this cadence — the planner session
28
+ # is the one that reads the living spec/analytics and proposes scope, and
29
+ # that proposal always waits for an operator tick regardless of confidence.
30
+ cadence_days: 30
31
+
32
+ lessons:
33
+ # architecture §9.3 novelty gate: cheap deterministic similarity
34
+ # (normalized word-shingle Jaccard) against existing candidate + approved
35
+ # lesson statements. >= this score is "clearly redundant" -> auto
36
+ # novelty-rejected, no LLM call. Below it, Phase 7 queues the candidate as
37
+ # novel; the "uncertain -> one LLM merge step" middle tier architecture §9
38
+ # describes (SAGE) is a documented future upgrade, not built here.
39
+ novelty_jaccard_threshold: 0.8
40
+ shingle_size: 3
41
+ # Correct that threshold for how long the two statements are before
42
+ # comparing them (P9-35 (a)). A statement has n-s+1 shingles, and changing
43
+ # one word destroys s of them, so nothing shorter than ~29 words can score
44
+ # 0.8 against its own near-copy: at a fixed bar, restating a shorter lesson
45
+ # with one word changed read as a new lesson. Set false for one bar per
46
+ # pair; below 2*shingle_size+1 words the correction stands aside either way,
47
+ # because there a one-word edit and a coincidence score the same.
48
+ novelty_length_aware: true
49
+
50
+ autonomy:
51
+ # Who says yes to what this pass proposes. The scheduler decides WHAT is
52
+ # due; this block decides what may proceed without an operator tick, and
53
+ # `smith scheduler admit` (src/autonomy.ts) applies it. That command still
54
+ # enacts nothing — it prints the classification so it can be read and
55
+ # argued with before anything moves.
56
+ #
57
+ # The operator's standing decision, 2026-09-02: auto-dispatch with a
58
+ # whitelist. Rechecks and maintenance may run themselves; growth review
59
+ # and anything touching a security surface always wait; PRs are still
60
+ # merged by a person, which is the backstop that makes this safe to widen.
61
+ enabled: true
62
+
63
+ # Nothing outside this list is ever auto-dispatched, and listing
64
+ # `growth-review-due` would not change that: architecture §12 keeps scope
65
+ # with the operator unconditionally, so autonomy.ts denies it whatever this
66
+ # says. The list is a ceiling, never a floor.
67
+ auto_dispatch_kinds: [recheck, maintenance]
68
+
69
+ # Rechecks are whitelisted BY REASON, and this is the one knob in the file
70
+ # that is easy to get backwards. A RecheckProposal's `confidence` is the
71
+ # COMPLETED TASK's confidence, and a low one is why the recheck exists at
72
+ # all — gating rechecks on confidence the way maintenance is gated would
73
+ # hold back precisely the rechecks worth running. So:
74
+ # merge-threshold — N later merges touched its claims; re-running the
75
+ # same checks against moved ground is routine.
76
+ # time-elapsed — T days passed; likewise routine.
77
+ # low-confidence — the work itself was uncertain when it completed.
78
+ # Left out: that is a judgement about quality, and it
79
+ # is the operator who should read it first.
80
+ # One unlisted reason holds the whole proposal — a recheck is dispatched
81
+ # once and carries every reason with it.
82
+ auto_dispatch_recheck_reasons: [merge-threshold, time-elapsed]
83
+
84
+ # Maintenance only. Matches maintenance.auto_schedule_confidence above,
85
+ # repeated rather than imported for the same reason crosscheck.yml repeats
86
+ # its own copy: "auto-schedulable" and "may run unattended" are allowed to
87
+ # diverge later, and the day they do, one of them moving must not move the
88
+ # other by accident. scheduler.ts scores a major-version bump at 0.5
89
+ # precisely so a person reads it.
90
+ confidence_floor: 0.8
@@ -0,0 +1,148 @@
1
+ # Sensitive claim paths — the security-reviewer's dispatch trigger.
2
+ #
3
+ # The security-reviewer is conditional dispatch only (agent-constraints.md:
4
+ # security-reviewer). Trigger 1 of its three is "the task's claims intersect
5
+ # sensitive paths", and until this file existed that intersection was a
6
+ # judgment call made fresh on every dispatch — which is the same as saying
7
+ # some tasks got a security review because the dispatcher happened to
8
+ # recognise the path, and others did not (agent-interviews.md N-7).
9
+ #
10
+ # Scope note: this file is about *paths*. crosscheck.yml's `security_keywords`
11
+ # is about *nonfunctional clause text* and gates plan quorum, not
12
+ # security-reviewer dispatch. Two different questions, deliberately two lists —
13
+ # a task can claim `src/auth/**` without writing the word "auth" anywhere in
14
+ # its clauses, and that is exactly the task worth catching.
15
+ #
16
+ # HOST: `smith security triggers --task <spec.json>` reads this file and
17
+ # returns the triggers that fired, with the claim and the glob that fired each
18
+ # one (factory/orchestrator/src/security.ts, punch list P9-4). The dispatcher
19
+ # in `.claude/skills/bs/dispatch.md` runs that verb rather than eyeballing the
20
+ # list. Match semantics live with the host; the two rules worth knowing before
21
+ # editing globs below are stated inline.
22
+
23
+ version: 1
24
+
25
+ # Matched against a task spec's `claims[]` globs, not against the diff: the
26
+ # review is dispatched before the diff is judged, and a claim is the earliest
27
+ # honest signal that a task is allowed to touch one of these paths.
28
+ #
29
+ # Match semantics: a task fires the trigger when any of its claims *overlaps*
30
+ # any glob here — not when it is contained by one. A claim of `src/**` overlaps
31
+ # `src/auth/**` and must fire, even though it is the wider pattern.
32
+ # Containment-only matching is the failure mode where a broadly scoped task
33
+ # escapes the review that a narrowly scoped one gets. The direct consequence:
34
+ # an open-ended `<dir>/**` claim fires most of the directory globs below,
35
+ # because such a task really could add `<dir>/auth/session.ts` tomorrow.
36
+ #
37
+ # Every directory entry (`**/auth/**`) needs a file-level sibling
38
+ # (`**/*auth*.{ts,...}`), because half the real world puts the whole concern in
39
+ # one file: `src/parse.ts`, not `src/parse/index.ts`. Measured on a real epic,
40
+ # the directory-only version of this list scored one hit for six tasks, and the
41
+ # one hit was the wrong one (dogfood-envkit-findings.md D-25).
42
+ globs:
43
+ # Authentication, authorization, session handling. `*auth*` also catches
44
+ # `oauth`, and `authors.ts` in a blog — firing on a false friend costs one
45
+ # review; missing `src/auth.ts` costs the review that mattered.
46
+ - "**/auth/**"
47
+ - "**/authn/**"
48
+ - "**/authz/**"
49
+ - "**/*auth*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
50
+ - "**/session/**"
51
+ - "**/*session*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
52
+ - "**/middleware/**"
53
+ - "**/*middleware*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
54
+ - "**/guard*/**"
55
+ - "**/*guard*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
56
+ - "**/permission*/**"
57
+ - "**/*permission*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
58
+ - "**/*rbac*"
59
+
60
+ # Secrets, keys, credentials, and the config surfaces that carry them.
61
+ - "**/secret*/**"
62
+ - "**/*secret*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
63
+ - "**/credential*/**"
64
+ - "**/*credential*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
65
+ - "**/*.env*" # matched with dot:true, so a bare `.env` fires
66
+ - "**/config/secrets*"
67
+ - "**/keys/**"
68
+ - "**/*keystore*"
69
+
70
+ # Cryptography — including "helpers" wrapping a library, which is where the
71
+ # mistakes actually live.
72
+ - "**/crypto/**"
73
+ - "**/*crypt*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
74
+ - "**/*hash*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
75
+ - "**/*signature*"
76
+ - "**/*jwt*"
77
+
78
+ # Input parsing and deserialization — the untrusted-data boundary.
79
+ # `*parse*`, not `*parser*`: the file that exists is `src/parse.ts`.
80
+ - "**/parse*/**"
81
+ - "**/*parse*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
82
+ - "**/serializ*/**"
83
+ - "**/deserializ*/**"
84
+ - "**/*serializ*.{ts,tsx,js,jsx,py,go,rs,rb,java}" # also catches deserialize*
85
+ - "**/upload*/**"
86
+ - "**/*upload*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
87
+ - "**/sanitiz*/**"
88
+ - "**/*sanitiz*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
89
+ - "**/validat*/**"
90
+ - "**/*validat*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
91
+
92
+ # Network boundary — anything that accepts or originates a request.
93
+ - "**/api/**"
94
+ - "**/routes/**"
95
+ - "**/*route*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
96
+ - "**/handlers/**"
97
+ - "**/*handler*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
98
+ - "**/controllers/**"
99
+ - "**/*controller*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
100
+ - "**/graphql/**"
101
+ - "**/*graphql*"
102
+ - "**/webhook*/**"
103
+ - "**/*webhook*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
104
+ - "**/cors*"
105
+
106
+ # Data access — injection surface and the blast radius of a bad query.
107
+ - "**/migrations/**"
108
+ - "**/*migration*.{ts,tsx,js,jsx,py,go,rs,rb,java,sql}"
109
+ - "**/*.sql"
110
+ - "**/db/**"
111
+ - "**/repositor*/**"
112
+ - "**/*repositor*.{ts,tsx,js,jsx,py,go,rs,rb,java}"
113
+
114
+ # Process and supply-chain boundary. Lockfiles are listed three ways because
115
+ # `**/*.lock` alone misses `pnpm-lock.yaml` and `package-lock.json` — the
116
+ # lockfiles a JS project actually has.
117
+ - "**/Dockerfile*"
118
+ - "**/.github/workflows/**"
119
+ - "**/*.lock"
120
+ - "**/*.lockb"
121
+ - "**/*lock*.{yaml,json}"
122
+ - "**/package.json" # a dependency bump is a supply-chain event; kept whole until a host can read the diff
123
+ - "**/scripts/**"
124
+
125
+ # Paths that match a glob above but are not worth a security review. Kept
126
+ # short on purpose: every entry here is a hole, and a long exclusion list is
127
+ # how a trigger quietly stops firing.
128
+ #
129
+ # Exclusions are checked after globs and are *containment*, not overlap: a
130
+ # claim is silenced only when it lies entirely inside one of these. Overlap
131
+ # would let `**/*.test.ts` silence `src/**`, which is the same escape hatch the
132
+ # match semantics above exist to close.
133
+ exclude:
134
+ - "**/*.test.{ts,tsx,js,jsx,py,go,rs,rb,java}"
135
+ - "**/*.spec.{ts,tsx,js,jsx,py,go,rs,rb,java}"
136
+ - "**/__tests__/**"
137
+ - "**/*.md"
138
+ - "**/*.snap"
139
+
140
+ # The other two triggers, recorded here so the whole dispatch condition reads
141
+ # from one file even though only the first is path-based.
142
+ other_triggers:
143
+ # taxonomy.yml `case` vocabulary, matched against the task spec's own `case`
144
+ # — the only place a case is recorded today. Read under the older
145
+ # `epic_cases` spelling too.
146
+ cases: [infra]
147
+ epic_tags: [security] # a security-tagged epic reviews every task; operator-supplied, nothing in the schema carries tags yet
148
+ scheduled_recheck: true # scheduler.yml may re-open a sensitive claim path
@@ -0,0 +1,83 @@
1
+ # Blacksmith — severity policy
2
+ #
3
+ # S1..S4 gate rules (architecture §11, agent-constraints.md "reviewer /
4
+ # verifier", guardrails.md). Severity values themselves are taxonomy-owned
5
+ # (factory/policies/taxonomy.yml: severity) — this file defines what each
6
+ # value *does* at the gate, not the vocabulary.
7
+
8
+ levels:
9
+ S1-stop-the-line:
10
+ blocks_merge: true
11
+ semantics: stop-the-line
12
+ classes:
13
+ # guardrails.md: violations are S1 unless stated otherwise
14
+ - repo corruption
15
+ - secret leak
16
+ - guardrail breach (push to main/master, force-push, history rewrite
17
+ on a shared branch, merge to main by the factory, destructive git ops
18
+ outside a worktree, deploy without operator approval, autonomous
19
+ outbound send)
20
+ - out-of-claim edit that touches a guardrail-protected file
21
+ on_trigger: >
22
+ stop the run immediately; no bounded retry; operator notified
23
+ synchronously (not batched).
24
+
25
+ S2-major:
26
+ blocks_merge: true
27
+ semantics: hard block, bounce to coder on the same branch
28
+ classes:
29
+ - security / data-loss
30
+ - broken core flow
31
+ - a11y WCAG AA failure
32
+ - new flaky test introduced by the task
33
+ - behavioral-drift touching a core flow
34
+ on_trigger: >
35
+ bounce to coder on the same branch; after 2 failed rounds, escalate
36
+ model tier (sonnet -> opus, budgets.yml); after 3, escalate to
37
+ operator.
38
+
39
+ S3-minor:
40
+ blocks_merge: false
41
+ semantics: waivable — batched to operator at epic end
42
+ classes:
43
+ - visual regression vs the uiux spec
44
+ - performance regression > 20%
45
+ - over-engineering (default severity — see rule below)
46
+ - behavioral-drift not touching a core flow
47
+ - everything minor-but-real that doesn't meet an S2 class
48
+ on_trigger: >
49
+ does not block; queued into a single batched waiver question at epic
50
+ end ("ignore these?"). Waiver answers are stored by finding
51
+ fingerprint, keyed for reuse — the same finding is never asked twice,
52
+ and waived findings are suppressed in future reviews of the same code.
53
+
54
+ S4-nit:
55
+ blocks_merge: false
56
+ semantics: logged, never asked
57
+ classes:
58
+ - style/naming nits the project's linter does not catch
59
+ on_trigger: log only; no operator interaction.
60
+
61
+ rules:
62
+ over_engineering_default: S3
63
+ over_engineering_note: >
64
+ Enforced by the reviewer's over-engineering lens per agent-constraints.md
65
+ coder effort discipline (YAGNI). Findings surface as S3 with a proposed
66
+ simplification, waiver-batched like any other S3.
67
+ same_mistake_escalation: >
68
+ A finding matching an approved lesson (finding_status match against
69
+ factory/policies/lessons.md by claim path / case type) is auto-escalated
70
+ one severity level and tagged judgment.same-mistake — including
71
+ over-engineering S3 -> S2 once a matching lesson is approved.
72
+ waiver_semantics: >
73
+ Only S3/S4 findings are ever waived. S1/S2 cannot be waived; they must be
74
+ fixed or the task returns through the escalation ladder
75
+ (budgets.yml: escalation_ladder). A waiver is keyed by finding
76
+ fingerprint (finding.schema.json) and, once granted, suppresses that
77
+ exact fingerprint in future reviews of the same code — it is never
78
+ re-asked.
79
+ block_semantics: >
80
+ "Blocks merge" means the merge-queue gate rejects the task's admission
81
+ into smith/<epic>/integration until the finding's finding_status reaches
82
+ fix-verified (fix landed and re-passed the gate) or, for S3/S4, waived.
83
+ A review firing without uptake is not a closed finding.
@@ -0,0 +1,60 @@
1
+ # Blacksmith — stack answers
2
+ #
3
+ # What the operator answered when they installed this clone (INSTALL.md
4
+ # Step 6, "The stack interview"). Read by `factory/orchestrator/src/stack.ts`
5
+ # via `smith stack show`, and through it by the scaffolder and by every agent
6
+ # that needs to know what this operator builds with.
7
+ #
8
+ # This file used to be a document. `docs/standards/stack.md` shipped one
9
+ # operator's 2026-08-03 answers — Vue, Cloudflare, Drizzle, a private design
10
+ # system — written as if they were the product, and every clone of a public
11
+ # repo inherited them. They are answers, so they live here as data, and the
12
+ # defaults below are the ones that assume least: `none` wherever an unanswered
13
+ # question would otherwise put words in the operator's mouth.
14
+ #
15
+ # Not every answer is executable. The shipped templates implement a subset —
16
+ # `smith stack check` prints which of your answers they honour and which are
17
+ # recorded for the agents to read but not built into `smith new`. Nothing here
18
+ # silently pretends: an answer the templates cannot honour makes `smith new`
19
+ # refuse rather than scaffold something else.
20
+
21
+ # ── Language ────────────────────────────────────────────────────────
22
+ # What the coder writes. `typescript` is the only value the shipped templates
23
+ # scaffold; any other value is recorded, and `smith new` refuses rather than
24
+ # handing you a TypeScript project you did not ask for.
25
+ language: typescript # typescript | javascript | python | go | rust | other
26
+
27
+ # ── Frontend ────────────────────────────────────────────────────────
28
+ # `none` is the default because most projects are not UI projects, and the
29
+ # base template is a plain library. `smith new --ui` needs a value the
30
+ # templates implement — today that is `vue` and nothing else.
31
+ frontend: none # none | vue | react | svelte | solid | vite-vanilla | other
32
+
33
+ # The design system a UI project builds against. `none` means the project owns
34
+ # its own components, which is what a new project has on day one, and what the
35
+ # uiux agent grounds its specs in when there is nothing else to ground them in.
36
+ #
37
+ # Naming one changes two things: the uiux agent is told to spec against it
38
+ # instead of inventing patterns, and `design_system_source` (if set) is
39
+ # vendor-copied into each scaffolded UI project. Vendored, never referenced
40
+ # from an external repo — a design system you cannot build offline is a
41
+ # dependency on someone else's uptime.
42
+ design_system: none # none | <name>
43
+ design_system_source: '' # path to a directory to vendor into <project>/design/, or empty
44
+
45
+ # The utility layer under the components.
46
+ styling: plain-css # plain-css | tailwind | css-modules | vanilla-extract | other
47
+
48
+ # ── Backend / runtime ───────────────────────────────────────────────
49
+ backend: none # none | node | deno | bun | cloudflare-workers | other
50
+ database: none # none | sqlite | postgres | mysql | d1 | other
51
+ orm: none # none | drizzle | prisma | kysely | other
52
+
53
+ # ── Repo shape + tooling ────────────────────────────────────────────
54
+ package_manager: pnpm # pnpm | npm | yarn | bun
55
+ repo_shape: single # single | monorepo
56
+ lint: biome # biome | eslint-prettier | none
57
+ test_unit: vitest # vitest | jest | node-test | none
58
+ test_e2e: playwright # playwright | cypress | none
59
+ ci: github-actions # github-actions | gitlab-ci | circleci | none
60
+ hosting: unspecified # free text — where this operator deploys, or `unspecified`