@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.
- package/.claude/agents/auditor.md +146 -0
- package/.claude/agents/coder.md +164 -0
- package/.claude/agents/grader.md +110 -0
- package/.claude/agents/merger.md +107 -0
- package/.claude/agents/planner.md +92 -0
- package/.claude/agents/researcher.md +105 -0
- package/.claude/agents/reviewer.md +171 -0
- package/.claude/agents/scribe.md +72 -0
- package/.claude/agents/security-reviewer.md +130 -0
- package/.claude/agents/spec-reviewer.md +215 -0
- package/.claude/agents/tester.md +121 -0
- package/.claude/agents/uiux.md +126 -0
- package/.claude/agents/verifier.md +103 -0
- package/.claude/agents/wave-runner.md +74 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/factory/orchestrator/dist/actors.js +46 -0
- package/factory/orchestrator/dist/agents-registry.js +308 -0
- package/factory/orchestrator/dist/args.js +84 -0
- package/factory/orchestrator/dist/artifacts.js +111 -0
- package/factory/orchestrator/dist/attribution.js +160 -0
- package/factory/orchestrator/dist/audit.js +812 -0
- package/factory/orchestrator/dist/autonomy.js +151 -0
- package/factory/orchestrator/dist/budgetAlarm.js +366 -0
- package/factory/orchestrator/dist/budgets.js +196 -0
- package/factory/orchestrator/dist/claims.js +633 -0
- package/factory/orchestrator/dist/cli.js +3185 -0
- package/factory/orchestrator/dist/commit.js +152 -0
- package/factory/orchestrator/dist/coverage.js +188 -0
- package/factory/orchestrator/dist/crossFinding.js +479 -0
- package/factory/orchestrator/dist/crosscheck.js +396 -0
- package/factory/orchestrator/dist/daemon.js +707 -0
- package/factory/orchestrator/dist/db/projector.js +1317 -0
- package/factory/orchestrator/dist/db/queries.js +1714 -0
- package/factory/orchestrator/dist/db/schema.js +305 -0
- package/factory/orchestrator/dist/delegation.js +400 -0
- package/factory/orchestrator/dist/diffstat.js +164 -0
- package/factory/orchestrator/dist/dispatchAudit.js +275 -0
- package/factory/orchestrator/dist/dotenv.js +72 -0
- package/factory/orchestrator/dist/effort.js +202 -0
- package/factory/orchestrator/dist/epic.js +1018 -0
- package/factory/orchestrator/dist/epicWidth.js +238 -0
- package/factory/orchestrator/dist/errorIssues.js +249 -0
- package/factory/orchestrator/dist/errors.js +11 -0
- package/factory/orchestrator/dist/escalation.js +500 -0
- package/factory/orchestrator/dist/events.js +1015 -0
- package/factory/orchestrator/dist/findingAge.js +91 -0
- package/factory/orchestrator/dist/findingContext.js +103 -0
- package/factory/orchestrator/dist/findings.js +1156 -0
- package/factory/orchestrator/dist/gate.js +911 -0
- package/factory/orchestrator/dist/gh.js +146 -0
- package/factory/orchestrator/dist/git.js +87 -0
- package/factory/orchestrator/dist/goalCheck.js +380 -0
- package/factory/orchestrator/dist/graph.js +61 -0
- package/factory/orchestrator/dist/hookDecision.js +106 -0
- package/factory/orchestrator/dist/immutability.js +171 -0
- package/factory/orchestrator/dist/impact.js +280 -0
- package/factory/orchestrator/dist/integration.js +141 -0
- package/factory/orchestrator/dist/judgePreflight.js +155 -0
- package/factory/orchestrator/dist/judges.js +310 -0
- package/factory/orchestrator/dist/lessonAudit.js +399 -0
- package/factory/orchestrator/dist/lessons.js +1329 -0
- package/factory/orchestrator/dist/mcp.js +555 -0
- package/factory/orchestrator/dist/paths.js +82 -0
- package/factory/orchestrator/dist/plan.js +502 -0
- package/factory/orchestrator/dist/planQuorum.js +421 -0
- package/factory/orchestrator/dist/policy.js +1308 -0
- package/factory/orchestrator/dist/policyHook.js +28 -0
- package/factory/orchestrator/dist/preconditions.js +47 -0
- package/factory/orchestrator/dist/projects.js +134 -0
- package/factory/orchestrator/dist/prompts.js +57 -0
- package/factory/orchestrator/dist/provenance.js +201 -0
- package/factory/orchestrator/dist/providers/api-transport.js +117 -0
- package/factory/orchestrator/dist/providers/cli-transport.js +208 -0
- package/factory/orchestrator/dist/providers/index.js +54 -0
- package/factory/orchestrator/dist/providers/schema-validate.js +152 -0
- package/factory/orchestrator/dist/providers/types.js +49 -0
- package/factory/orchestrator/dist/queue.js +263 -0
- package/factory/orchestrator/dist/quorum.js +347 -0
- package/factory/orchestrator/dist/quorumEscalations.js +132 -0
- package/factory/orchestrator/dist/results.js +65 -0
- package/factory/orchestrator/dist/roadmap.js +437 -0
- package/factory/orchestrator/dist/runtime.js +86 -0
- package/factory/orchestrator/dist/sameMistakeKpi.js +243 -0
- package/factory/orchestrator/dist/sandbox.js +165 -0
- package/factory/orchestrator/dist/scaffold.js +373 -0
- package/factory/orchestrator/dist/scheduler.js +408 -0
- package/factory/orchestrator/dist/schemas.js +195 -0
- package/factory/orchestrator/dist/security.js +222 -0
- package/factory/orchestrator/dist/severity.js +293 -0
- package/factory/orchestrator/dist/spec.js +376 -0
- package/factory/orchestrator/dist/specChange.js +497 -0
- package/factory/orchestrator/dist/stack.js +324 -0
- package/factory/orchestrator/dist/symbols.js +966 -0
- package/factory/orchestrator/dist/taskEvents.js +399 -0
- package/factory/orchestrator/dist/taskId.js +126 -0
- package/factory/orchestrator/dist/taxonomy.js +113 -0
- package/factory/orchestrator/dist/testSelect.js +129 -0
- package/factory/orchestrator/dist/testerAudit.js +264 -0
- package/factory/orchestrator/dist/testgate.js +171 -0
- package/factory/orchestrator/dist/usage.js +874 -0
- package/factory/orchestrator/dist/waivers.js +228 -0
- package/factory/orchestrator/dist/waveBudget.js +223 -0
- package/factory/orchestrator/dist/waveConcurrency.js +250 -0
- package/factory/orchestrator/dist/waveNext.js +210 -0
- package/factory/orchestrator/dist/waveSchedule.js +146 -0
- package/factory/orchestrator/dist/worktree.js +207 -0
- package/factory/orchestrator/drizzle/0000_broken_rockslide.sql +183 -0
- package/factory/orchestrator/drizzle/0001_luxuriant_zaladane.sql +1 -0
- package/factory/orchestrator/drizzle/0002_yellow_wild_pack.sql +8 -0
- package/factory/orchestrator/drizzle/0003_damp_riptide.sql +12 -0
- package/factory/orchestrator/drizzle/0004_broad_lady_vermin.sql +1 -0
- package/factory/orchestrator/drizzle/0005_romantic_jocasta.sql +2 -0
- package/factory/orchestrator/drizzle/0006_bent_madelyne_pryor.sql +16 -0
- package/factory/orchestrator/drizzle/0007_overjoyed_goliath.sql +1 -0
- package/factory/orchestrator/drizzle/0008_smart_iron_patriot.sql +2 -0
- package/factory/orchestrator/drizzle/0009_agents_epic_id.sql +2 -0
- package/factory/orchestrator/drizzle/0010_milestone_kind.sql +1 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +83 -0
- package/factory/policies/budgets.yml +262 -0
- package/factory/policies/crosscheck.yml +308 -0
- package/factory/policies/delegation.yml +44 -0
- package/factory/policies/effort.yml +142 -0
- package/factory/policies/guardrails.yml +306 -0
- package/factory/policies/lessons.md +239 -0
- package/factory/policies/scheduler.yml +90 -0
- package/factory/policies/sensitive-paths.yml +148 -0
- package/factory/policies/severity.yml +83 -0
- package/factory/policies/stack.yml +60 -0
- package/factory/policies/taxonomy.yml +340 -0
- package/factory/policies/worktree.yml +95 -0
- package/factory/scaffold/base/.github/workflows/ci.yml +34 -0
- package/factory/scaffold/base/.gitignore.tmpl +11 -0
- package/factory/scaffold/base/AGENTS.md +33 -0
- package/factory/scaffold/base/README.md +25 -0
- package/factory/scaffold/base/biome.json.tmpl +30 -0
- package/factory/scaffold/base/package.json +25 -0
- package/factory/scaffold/base/pnpm-workspace.yaml.tmpl +16 -0
- package/factory/scaffold/base/src/index.ts +4 -0
- package/factory/scaffold/base/test/index.test.ts +8 -0
- package/factory/scaffold/base/tsconfig.json +20 -0
- package/factory/scaffold/base/tsconfig.test.json +9 -0
- package/factory/scaffold/base/vitest.config.ts +29 -0
- package/factory/scaffold/mcp/mcp.manifest.json +22 -0
- package/factory/scaffold/mcp/package.fragment.json +9 -0
- package/factory/scaffold/mcp/src/mcp/README.md +63 -0
- package/factory/scaffold/mcp/src/mcp/guard.ts +110 -0
- package/factory/scaffold/mcp/src/mcp/redact.ts +69 -0
- package/factory/scaffold/mcp/src/mcp/server.ts +55 -0
- package/factory/scaffold/mcp/src/mcp/tools/health.ts +60 -0
- package/factory/scaffold/mcp/test/mcp/guard.test.ts +108 -0
- package/factory/scaffold/mcp/test/mcp/redact.test.ts +61 -0
- package/factory/scaffold/mcp/test/mcp/surface.test.ts +100 -0
- package/factory/scaffold/ui/index.html +12 -0
- package/factory/scaffold/ui/package.fragment.json +13 -0
- package/factory/scaffold/ui/src/App.vue +10 -0
- package/factory/scaffold/ui/src/main.ts +5 -0
- package/factory/scaffold/ui/src/shims.d.ts +11 -0
- package/factory/scaffold/ui/vite.config.ts +20 -0
- package/factory/scaffold/ui-tailwind/package.fragment.json +6 -0
- package/factory/scaffold/ui-tailwind/vite.config.ts +26 -0
- package/factory/specs/schema/event.schema.json +82 -0
- package/factory/specs/schema/finding-evidence.schema.json +45 -0
- package/factory/specs/schema/finding.schema.json +115 -0
- package/factory/specs/schema/grader-verdict.schema.json +50 -0
- package/factory/specs/schema/judge-verdict.schema.json +19 -0
- package/factory/specs/schema/lesson.schema.json +85 -0
- package/factory/specs/schema/mcp-manifest.schema.json +230 -0
- package/factory/specs/schema/result.schema.json +81 -0
- package/factory/specs/schema/spec-change-request.schema.json +46 -0
- package/factory/specs/schema/task-spec.schema.json +134 -0
- 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`
|