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