@juzser/blacksmith 0.2.0 → 0.4.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 +3 -0
- package/.claude/agents/grader.md +12 -5
- package/.claude/agents/reviewer.md +3 -0
- package/.claude/agents/security-reviewer.md +3 -0
- package/.claude/agents/spec-reviewer.md +3 -0
- package/.claude/agents/verifier.md +3 -0
- package/.claude/skills/bs/audit.md +25 -9
- package/.claude/skills/bs/dispatch.md +60 -7
- package/.claude/skills/bs/plan.md +33 -1
- package/.claude/skills/bs/run.md +18 -13
- package/.claude/skills/bs/wave.md +68 -10
- package/README.md +4 -4
- package/factory/orchestrator/dist/agentsSync.js +178 -0
- package/factory/orchestrator/dist/audit.js +134 -17
- package/factory/orchestrator/dist/autonomy.js +25 -0
- package/factory/orchestrator/dist/budgets.js +91 -2
- package/factory/orchestrator/dist/claims.js +8 -4
- package/factory/orchestrator/dist/cli.js +394 -26
- package/factory/orchestrator/dist/crossFinding.js +20 -0
- package/factory/orchestrator/dist/daemon.js +230 -41
- package/factory/orchestrator/dist/db/projector.js +93 -36
- package/factory/orchestrator/dist/db/queries.js +58 -35
- package/factory/orchestrator/dist/db/schema.js +24 -0
- package/factory/orchestrator/dist/dispatchAudit.js +10 -2
- package/factory/orchestrator/dist/dispatchLint.js +132 -0
- package/factory/orchestrator/dist/epic.js +192 -39
- package/factory/orchestrator/dist/epicWidth.js +25 -20
- package/factory/orchestrator/dist/errorIssues.js +209 -24
- package/factory/orchestrator/dist/eventOrder.js +102 -0
- package/factory/orchestrator/dist/events.js +73 -91
- package/factory/orchestrator/dist/findingContext.js +1 -13
- package/factory/orchestrator/dist/findings.js +132 -11
- package/factory/orchestrator/dist/gh.js +29 -6
- package/factory/orchestrator/dist/git.js +20 -2
- package/factory/orchestrator/dist/harness.js +92 -10
- package/factory/orchestrator/dist/hookDecision.js +320 -37
- package/factory/orchestrator/dist/impact.js +24 -2
- package/factory/orchestrator/dist/integration.js +11 -1
- package/factory/orchestrator/dist/issueReporter.js +415 -0
- package/factory/orchestrator/dist/judgeStopHook.js +181 -0
- package/factory/orchestrator/dist/judges.js +1 -1
- package/factory/orchestrator/dist/lessons.js +46 -18
- package/factory/orchestrator/dist/logCache.js +291 -0
- package/factory/orchestrator/dist/paths.js +10 -0
- package/factory/orchestrator/dist/plan.js +138 -4
- package/factory/orchestrator/dist/planQuorum.js +1 -1
- package/factory/orchestrator/dist/policy.js +57 -11
- package/factory/orchestrator/dist/projects.js +12 -1
- package/factory/orchestrator/dist/queue.js +477 -29
- package/factory/orchestrator/dist/scheduler.js +51 -0
- package/factory/orchestrator/dist/severity.js +40 -8
- package/factory/orchestrator/dist/spec.js +70 -0
- package/factory/orchestrator/dist/taskEvents.js +13 -4
- package/factory/orchestrator/dist/taskStatus.js +74 -0
- package/factory/orchestrator/dist/taxonomy.js +11 -0
- package/factory/orchestrator/dist/testgate.js +32 -3
- package/factory/orchestrator/dist/usage.js +42 -9
- package/factory/orchestrator/dist/waivers.js +60 -9
- package/factory/orchestrator/dist/waveConcurrency.js +29 -0
- package/factory/orchestrator/dist/waveNext.js +12 -10
- package/factory/orchestrator/dist/waveSchedule.js +84 -0
- package/factory/orchestrator/dist/worktree.js +19 -6
- package/factory/orchestrator/drizzle/0012_issue_reports_error_issues.sql +20 -0
- package/factory/orchestrator/drizzle/meta/_journal.json +7 -0
- package/factory/policies/budgets.yml +9 -2
- package/factory/policies/crosscheck.yml +2 -2
- package/factory/policies/lessons.md +298 -0
- package/factory/policies/scheduler.yml +27 -2
- package/factory/policies/taxonomy.yml +10 -3
- package/factory/specs/roadmap.md +70 -23
- package/package.json +8 -8
|
@@ -28,15 +28,7 @@
|
|
|
28
28
|
import { claimsOverlap, readClaimList, readEdgeList, touchesSerializeAlways, } from './claims.js';
|
|
29
29
|
import { topoSort } from './graph.js';
|
|
30
30
|
import { livePlanTasks } from './plan.js';
|
|
31
|
-
|
|
32
|
-
* A task is *done* only at the two statuses epic.ts already calls terminal —
|
|
33
|
-
* `completed` and `waived`. Everything else non-terminal still holds a
|
|
34
|
-
* worktree, so its claims are still spoken for even when nobody is typing in
|
|
35
|
-
* it: `blocked`, `failed` and `escalated` are waiting on a person, not on
|
|
36
|
-
* nothing, and their uncommitted work is exactly what a second agent in the
|
|
37
|
-
* same paths would destroy.
|
|
38
|
-
*/
|
|
39
|
-
const TERMINAL_TASK_STATUSES = new Set(['completed', 'waived']);
|
|
31
|
+
import { TERMINAL_OK_TASK_STATUSES } from './taskStatus.js';
|
|
40
32
|
/** The two statuses that mean "nothing has been dispatched for this yet". */
|
|
41
33
|
const CANDIDATE_TASK_STATUSES = new Set(['todo', 'ready']);
|
|
42
34
|
function nameList(ids) {
|
|
@@ -127,7 +119,17 @@ export function computeNextWave(input) {
|
|
|
127
119
|
for (const record of livePlanTasks(plan)) {
|
|
128
120
|
const id = record.task_id;
|
|
129
121
|
const status = input.statusById?.get(id) ?? String(record.task_status);
|
|
130
|
-
|
|
122
|
+
// *Done* here is the narrow question — the work ended well, so the
|
|
123
|
+
// worktree is free. Its neighbour in taskStatus.ts, TERMINAL_TASK_STATUSES,
|
|
124
|
+
// answers a different one — which rows the log refuses to overwrite — and
|
|
125
|
+
// holds `failed` and `escalated` too. Those are waiting on a person, not
|
|
126
|
+
// on nothing, and their uncommitted work is exactly what a second agent in
|
|
127
|
+
// the same paths would destroy: reading that set here is a data-loss bug,
|
|
128
|
+
// and this file carried its own copy of this one under *that* name until
|
|
129
|
+
// both answers moved to the module that owns the dimension.
|
|
130
|
+
// (`superseded` is in neither conversation: livePlanTasks drops an id
|
|
131
|
+
// whose every record is superseded, so one never reaches this line.)
|
|
132
|
+
if (TERMINAL_OK_TASK_STATUSES.has(status)) {
|
|
131
133
|
done.push(id);
|
|
132
134
|
continue;
|
|
133
135
|
}
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
* Pure, and it writes nothing. Like `waveNext`, admission stays where it was:
|
|
41
41
|
* a round simulated here has been admitted by nobody.
|
|
42
42
|
*/
|
|
43
|
+
import { claimsOverlap, readEdgeList } from './claims.js';
|
|
44
|
+
import { planClaimedTasks } from './plan.js';
|
|
43
45
|
import { computeNextWave, } from './waveNext.js';
|
|
44
46
|
/**
|
|
45
47
|
* Reported in this order, which is the order `computeNextWave` tests them in.
|
|
@@ -150,3 +152,85 @@ export function scheduleWaves(input) {
|
|
|
150
152
|
exitCode: stalled.length > 0 ? 1 : constraints.length > 0 ? 2 : 0,
|
|
151
153
|
};
|
|
152
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Directed reachability over the plan's `depends_on` edges, both ways: the
|
|
157
|
+
* tasks reachable by walking forward (its descendants) and the tasks
|
|
158
|
+
* reachable by walking backward (its ancestors). Two tasks are connected —
|
|
159
|
+
* "a dependency path between them in either direction" — when either set
|
|
160
|
+
* contains the other, which a chain like C -> B -> A catches for A and C
|
|
161
|
+
* even though no edge names that pair directly.
|
|
162
|
+
*/
|
|
163
|
+
function connectedTaskIds(ids, edges) {
|
|
164
|
+
const descendantsOf = new Map();
|
|
165
|
+
const ancestorsOf = new Map();
|
|
166
|
+
for (const id of ids) {
|
|
167
|
+
descendantsOf.set(id, []);
|
|
168
|
+
ancestorsOf.set(id, []);
|
|
169
|
+
}
|
|
170
|
+
for (const edge of edges) {
|
|
171
|
+
if (!ids.has(edge.task) || !ids.has(edge.dependsOn))
|
|
172
|
+
continue;
|
|
173
|
+
descendantsOf.get(edge.dependsOn)?.push(edge.task);
|
|
174
|
+
ancestorsOf.get(edge.task)?.push(edge.dependsOn);
|
|
175
|
+
}
|
|
176
|
+
const reachable = (start, adjacency) => {
|
|
177
|
+
const seen = new Set();
|
|
178
|
+
const stack = [...(adjacency.get(start) ?? [])];
|
|
179
|
+
while (stack.length > 0) {
|
|
180
|
+
const next = stack.pop();
|
|
181
|
+
if (seen.has(next))
|
|
182
|
+
continue;
|
|
183
|
+
seen.add(next);
|
|
184
|
+
for (const n of adjacency.get(next) ?? [])
|
|
185
|
+
if (!seen.has(n))
|
|
186
|
+
stack.push(n);
|
|
187
|
+
}
|
|
188
|
+
return seen;
|
|
189
|
+
};
|
|
190
|
+
const connected = new Map();
|
|
191
|
+
for (const id of ids) {
|
|
192
|
+
connected.set(id, new Set([...reachable(id, descendantsOf), ...reachable(id, ancestorsOf)]));
|
|
193
|
+
}
|
|
194
|
+
return connected;
|
|
195
|
+
}
|
|
196
|
+
const SMALL_MAX_TASKS = 3;
|
|
197
|
+
const SMALL_MAX_CLAIMS = 10;
|
|
198
|
+
/**
|
|
199
|
+
* Pure. Superseded tasks are absent from `planClaimedTasks` already (D-126),
|
|
200
|
+
* so they never enter `widest`, `parallelWith`, or `size` — no separate
|
|
201
|
+
* filter needed here.
|
|
202
|
+
*/
|
|
203
|
+
export function computePlanParallelism(plan, policy) {
|
|
204
|
+
const claimedTasks = planClaimedTasks(plan).filter((t) => t.task_id !== undefined);
|
|
205
|
+
const ids = new Set(claimedTasks.map((t) => t.task_id));
|
|
206
|
+
const edges = readEdgeList(plan.edges);
|
|
207
|
+
const connected = connectedTaskIds(ids, edges);
|
|
208
|
+
const parallelWith = {};
|
|
209
|
+
for (const a of claimedTasks) {
|
|
210
|
+
const withIds = [];
|
|
211
|
+
for (const b of claimedTasks) {
|
|
212
|
+
if (a.task_id === b.task_id)
|
|
213
|
+
continue;
|
|
214
|
+
if (connected.get(a.task_id)?.has(b.task_id))
|
|
215
|
+
continue;
|
|
216
|
+
if (claimsOverlap(a, b).overlaps)
|
|
217
|
+
continue;
|
|
218
|
+
withIds.push(b.task_id);
|
|
219
|
+
}
|
|
220
|
+
parallelWith[a.task_id] = withIds.sort();
|
|
221
|
+
}
|
|
222
|
+
const { widest } = scheduleWaves({ plan, policy });
|
|
223
|
+
const claimPaths = new Set();
|
|
224
|
+
for (const t of claimedTasks)
|
|
225
|
+
for (const c of t.claims)
|
|
226
|
+
claimPaths.add(c);
|
|
227
|
+
return {
|
|
228
|
+
widest,
|
|
229
|
+
parallel_with: parallelWith,
|
|
230
|
+
size: {
|
|
231
|
+
tasks: claimedTasks.length,
|
|
232
|
+
claims: claimPaths.size,
|
|
233
|
+
small: claimedTasks.length <= SMALL_MAX_TASKS && claimPaths.size <= SMALL_MAX_CLAIMS,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
@@ -127,18 +127,31 @@ function ensureIntegrationBranch(projectDir, epic) {
|
|
|
127
127
|
* sibling of whatever directory the project was handed as, never a path of
|
|
128
128
|
* this module's own choosing, so a project outside this clone keeps its
|
|
129
129
|
* worktrees outside it too (see taskWorktreeDir)
|
|
130
|
-
* on branch smith/<epic>/<task-id
|
|
131
|
-
*
|
|
132
|
-
*
|
|
130
|
+
* on branch smith/<epic>/<task-id>.
|
|
131
|
+
*
|
|
132
|
+
* Without `opts.from`, cut from the CURRENT head of smith/<epic>/integration
|
|
133
|
+
* (creating the integration branch from the default branch first if it
|
|
134
|
+
* doesn't exist yet). With `opts.from`, cut from smith/<epic>/<from> instead
|
|
135
|
+
* — the predecessor's branch, commits and all — and integration is never
|
|
136
|
+
* consulted.
|
|
133
137
|
*/
|
|
134
|
-
export function createTaskWorktree(projectDir, epic, taskId) {
|
|
138
|
+
export function createTaskWorktree(projectDir, epic, taskId, opts = {}) {
|
|
135
139
|
if (taskId === RESERVED_TASK_ID) {
|
|
136
140
|
throw new WorktreeError('worktree.reserved-task-id', `Task id "${RESERVED_TASK_ID}" is reserved for the integration branch itself.`, { taskId });
|
|
137
141
|
}
|
|
138
|
-
const integrationBranch = ensureIntegrationBranch(projectDir, epic);
|
|
139
142
|
const branch = taskBranchName(epic, taskId);
|
|
140
143
|
const worktreeDir = taskWorktreeDir(projectDir, epic, taskId);
|
|
141
|
-
|
|
144
|
+
let sourceBranch;
|
|
145
|
+
if (opts.from !== undefined) {
|
|
146
|
+
sourceBranch = taskBranchName(epic, opts.from);
|
|
147
|
+
if (!localBranchExists(projectDir, sourceBranch)) {
|
|
148
|
+
throw new WorktreeError('worktree.from-missing', `Predecessor branch ${sourceBranch} does not exist; cannot cut ${taskId} from it.`, { epic, taskId, from: opts.from, branch: sourceBranch });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
sourceBranch = ensureIntegrationBranch(projectDir, epic);
|
|
153
|
+
}
|
|
154
|
+
git(projectDir, ['worktree', 'add', '-b', branch, worktreeDir, sourceBranch]);
|
|
142
155
|
return { worktreeDir, branch, epic, taskId };
|
|
143
156
|
}
|
|
144
157
|
/** Remove a task's worktree and its local branch after it has merged. */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE `issue_reports` (
|
|
2
|
+
`event_id` text PRIMARY KEY NOT NULL,
|
|
3
|
+
`session_id` text NOT NULL,
|
|
4
|
+
`ts` text NOT NULL,
|
|
5
|
+
`task_ref` text,
|
|
6
|
+
`error_class` text NOT NULL,
|
|
7
|
+
`fingerprint` text NOT NULL,
|
|
8
|
+
`issue_url` text,
|
|
9
|
+
`latest_event_id` text NOT NULL,
|
|
10
|
+
`outcome` text NOT NULL,
|
|
11
|
+
`reason` text,
|
|
12
|
+
`repo_slug` text,
|
|
13
|
+
`source` text NOT NULL,
|
|
14
|
+
`project` text
|
|
15
|
+
);
|
|
16
|
+
--> statement-breakpoint
|
|
17
|
+
CREATE INDEX `issue_reports_session_idx` ON `issue_reports` (`session_id`);--> statement-breakpoint
|
|
18
|
+
CREATE INDEX `issue_reports_fingerprint_idx` ON `issue_reports` (`fingerprint`);--> statement-breakpoint
|
|
19
|
+
CREATE INDEX `issue_reports_outcome_idx` ON `issue_reports` (`outcome`);--> statement-breakpoint
|
|
20
|
+
ALTER TABLE `milestones` ADD `error_issues` integer DEFAULT true NOT NULL;
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
# limits, and the sections that follow say which is which. `max_turns` is no
|
|
65
65
|
# longer among them at all: the turn ceiling is the role template's
|
|
66
66
|
# `maxTurns` (`.claude/agents/<role>.md`), which Claude Code enforces per
|
|
67
|
-
# dispatch (measured 2026-09-07/-11
|
|
67
|
+
# dispatch (measured on two dogfood runs, 2026-09-07/-11 —
|
|
68
68
|
# agent-interviews.md M-4 had called it inert), and a plan cannot raise or
|
|
69
69
|
# lower a role's ceiling. So plan validation rejects it as a task budget
|
|
70
70
|
# field, and the dispatch prompt restates the template's number verbatim.
|
|
@@ -97,7 +97,14 @@ epic:
|
|
|
97
97
|
# Two things this does NOT fix, both worth a
|
|
98
98
|
# follow-up: (1) there is no per-epic override,
|
|
99
99
|
# so a number raised for one epic is raised for
|
|
100
|
-
# every epic black-smith will ever run
|
|
100
|
+
# every epic black-smith will ever run. What
|
|
101
|
+
# exists is a per-BOX override, a different
|
|
102
|
+
# thing: SMITH_EPIC_CAP_TOKENS in the env (or
|
|
103
|
+
# `.env`) replaces this number for every epic
|
|
104
|
+
# run on that box while it is set — the
|
|
105
|
+
# SMITH_EPIC_* / SMITH_TASK_* names in
|
|
106
|
+
# .env.example cover each number in this file
|
|
107
|
+
# that a box may want to move; (2) a
|
|
101
108
|
# large share of that 1.5M was rework — stopped
|
|
102
109
|
# dispatches and re-dispatches that `smith
|
|
103
110
|
# escalation check` recorded as ladder
|
|
@@ -114,13 +114,13 @@ providers:
|
|
|
114
114
|
# Funded for THIS box, 2026-09-04, by the operator who owns the key.
|
|
115
115
|
enabled: auto
|
|
116
116
|
# Promoted shadow -> active by the operator on 2026-09-14, after the
|
|
117
|
-
#
|
|
117
|
+
# epic-final verdict of a dogfooded product epic held on `insufficient-providers`
|
|
118
118
|
# with all three participants at `confirm`: with claude excluded as the
|
|
119
119
|
# finder and deepseek in shadow, the gating pool was codex alone (1 <
|
|
120
120
|
# `quorum_rule.min_providers` 2), so no mechanically-ready epic could ever
|
|
121
121
|
# reach quorum on this box (epic.ts, "exactly 1 active external"). The
|
|
122
122
|
# calibration run it replaced is the recorded shadow verdicts from
|
|
123
|
-
#
|
|
123
|
+
# two dogfooded product epics (docs/runbooks/providers.md §3).
|
|
124
124
|
# Rollback is `mode: shadow` here; nothing else remembers the promotion.
|
|
125
125
|
mode: active
|
|
126
126
|
|
|
@@ -112,6 +112,18 @@ nothing.
|
|
|
112
112
|
- agent_role: grader
|
|
113
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
114
|
|
|
115
|
+
### lesson-raised-75658b0d107b: Write the declared artifact as a parseable skeleton before your secon...
|
|
116
|
+
|
|
117
|
+
- lesson_id: lesson-raised-75658b0d107b
|
|
118
|
+
- agent_role: spec-reviewer
|
|
119
|
+
- statement: Write the declared artifact as a parseable skeleton before your second turn ends and refine it in place; a turn cap that lands on an unwritten artifact discards the whole review, and 15 turns of reading is the usual way to reach it.
|
|
120
|
+
|
|
121
|
+
### lesson-raised-dd1d1b5bcf68: An acceptance criterion that probes a script running under 'set -e' m...
|
|
122
|
+
|
|
123
|
+
- lesson_id: lesson-raised-dd1d1b5bcf68
|
|
124
|
+
- agent_role: planner
|
|
125
|
+
- statement: An acceptance criterion that probes a script running under 'set -e' must name the outer exit status it expects, never an echo the script prints afterwards: errexit ends the script at the first failing command, so a line printed after it is unreachable and the grader can only mark the wording, not the property.
|
|
126
|
+
|
|
115
127
|
## claim-path
|
|
116
128
|
|
|
117
129
|
### lesson-raised-3b5746704cfc: A function that computes a filesystem path and hands it to a child pr...
|
|
@@ -271,6 +283,117 @@ _(none yet)_
|
|
|
271
283
|
- lesson_id: lesson-raised-b8db8efe922d
|
|
272
284
|
- 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.
|
|
273
285
|
|
|
286
|
+
### lesson-raised-1da73f3f36ee: A dispatched agent's turn budget is set by the runtime, not by the di...
|
|
287
|
+
|
|
288
|
+
- lesson_id: lesson-raised-1da73f3f36ee
|
|
289
|
+
- agent_role: planner
|
|
290
|
+
- statement: A dispatched agent's turn budget is set by the runtime, not by the dispatch prompt: stating a larger number in the prompt does not raise it, so an agent that researches before it writes can spend an entire stint and return no artifact at all.
|
|
291
|
+
|
|
292
|
+
### lesson-raised-2fb53a40b114: Register an obligation only from the dispatches whose artifact the di...
|
|
293
|
+
|
|
294
|
+
- lesson_id: lesson-raised-2fb53a40b114
|
|
295
|
+
- finding_category: maintainability
|
|
296
|
+
- statement: Register an obligation only from the dispatches whose artifact the discharging reader can actually accept; a ledger that registers on any declared artifact but discharges on one artifact shape mints obligations the system can never close.
|
|
297
|
+
|
|
298
|
+
### lesson-raised-6a0d232d948d: An agent cut off by the turn cap after writing its placeholder artifa...
|
|
299
|
+
|
|
300
|
+
- lesson_id: lesson-raised-6a0d232d948d
|
|
301
|
+
- statement: An agent cut off by the turn cap after writing its placeholder artifact returns a file that is schema-valid and materially unchanged, so a diff of the artifact reports the round as wasted at precisely the moment the round's work exists but is unspliced; the recoverable signal is the agent's own tool trace, and the recovery is to resume that agent, because re-dispatching discards work the diff could not see.
|
|
302
|
+
|
|
303
|
+
### lesson-raised-c941f4645adb: A rule asserted over text its author has not read will over-reject in...
|
|
304
|
+
|
|
305
|
+
- lesson_id: lesson-raised-c941f4645adb
|
|
306
|
+
- finding_category: correctness
|
|
307
|
+
- agent_role: planner
|
|
308
|
+
- statement: A rule asserted over text its author has not read will over-reject inside that text; if a criterion binds every construct in its task, the sweep of every construct is part of writing it, not a later check.
|
|
309
|
+
|
|
310
|
+
### lesson-raised-33474964213a: Once a document begins to discuss its own markers, counting a marker ...
|
|
311
|
+
|
|
312
|
+
- lesson_id: lesson-raised-33474964213a
|
|
313
|
+
- finding_category: correctness
|
|
314
|
+
- statement: Once a document begins to discuss its own markers, counting a marker by its text stops measuring what the marker marks: prose quoting the marker is indistinguishable from the marker itself, so count by position — a real truncation marker terminates its string — and state which test the count used.
|
|
315
|
+
|
|
316
|
+
### lesson-raised-7670023e5f79: A document that measures itself must take the measurement after the e...
|
|
317
|
+
|
|
318
|
+
- lesson_id: lesson-raised-7670023e5f79
|
|
319
|
+
- finding_category: correctness
|
|
320
|
+
- statement: A document that measures itself must take the measurement after the edit that measurement is part of: a figure computed from the draft being read and written into the draft being produced describes the version it replaced, while reading as a present-tense fact about the version that carries it.
|
|
321
|
+
|
|
322
|
+
### lesson-raised-3b009dfb0e81: A turn-cap notification is evidence about the return channel only: it...
|
|
323
|
+
|
|
324
|
+
- lesson_id: lesson-raised-3b009dfb0e81
|
|
325
|
+
- statement: A turn-cap notification is evidence about the return channel only: it says the agent stopped mid-turn, never that the agent wrote nothing. Stat and parse the declared artifact before recording that a dispatch produced no result.
|
|
326
|
+
|
|
327
|
+
### lesson-raised-1931b084725f: A negative claim built on a substring search is a claim about spellin...
|
|
328
|
+
|
|
329
|
+
- lesson_id: lesson-raised-1931b084725f
|
|
330
|
+
- statement: A negative claim built on a substring search is a claim about spelling, not about content, unless the search is robust to hyphenation, case and whitespace; the reviewer will report a count of zero and the document will say the thing in the next spelling over.
|
|
331
|
+
|
|
332
|
+
### lesson-raised-e89a7a73adbb: A scope sentence placed after the sentence it qualifies will be read ...
|
|
333
|
+
|
|
334
|
+
- lesson_id: lesson-raised-e89a7a73adbb
|
|
335
|
+
- statement: A scope sentence placed after the sentence it qualifies will be read as scoping the sentence before it; a reader who quotes the pair back will attach the scope to the wrong clause and the citation will look sourced.
|
|
336
|
+
|
|
337
|
+
### lesson-raised-e543bb1a5d0b: A claim-confinement check built on `git diff --name-only` must pass `...
|
|
338
|
+
|
|
339
|
+
- lesson_id: lesson-raised-e543bb1a5d0b
|
|
340
|
+
- finding_category: correctness
|
|
341
|
+
- statement: A claim-confinement check built on `git diff --name-only` must pass `--no-renames`: with rename detection on, a committed rename lists only its destination, so moving a file OUT of an unclaimed path INTO a claimed one reports nothing deleted and passes.
|
|
342
|
+
|
|
343
|
+
### lesson-raised-6ea1eb68b2bf: A revision that fixes a defect in one instrument must sweep every sib...
|
|
344
|
+
|
|
345
|
+
- lesson_id: lesson-raised-6ea1eb68b2bf
|
|
346
|
+
- finding_category: correctness
|
|
347
|
+
- statement: A revision that fixes a defect in one instrument must sweep every sibling instrument doing the same job: a plan that names the disease in one task and leaves the other task carrying it reads as a deliberate distinction rather than an oversight, and the second site never gets reviewed again.
|
|
348
|
+
|
|
349
|
+
### lesson-raised-9e3e3f16efec: A common-prefix plus common-suffix comparison can only ever detect ON...
|
|
350
|
+
|
|
351
|
+
- lesson_id: lesson-raised-9e3e3f16efec
|
|
352
|
+
- finding_category: correctness
|
|
353
|
+
- statement: A common-prefix plus common-suffix comparison can only ever detect ONE insertion point, so it reports a legitimate multi-site append as a deletion or rewrite; the exact test for insert-only is whether the old string is a subsequence of the new one.
|
|
354
|
+
|
|
355
|
+
### lesson-raised-e24e9fb2785f: A confinement claim -- 'all of them are here', 'nothing else referenc...
|
|
356
|
+
|
|
357
|
+
- lesson_id: lesson-raised-e24e9fb2785f
|
|
358
|
+
- finding_category: correctness
|
|
359
|
+
- statement: A confinement claim -- 'all of them are here', 'nothing else references this' -- is the one kind of review evidence a reader cannot falsify from the quoted text, so it must be measured independently before it is repeated to the next tier.
|
|
360
|
+
|
|
361
|
+
### lesson-raised-80aae5ddff34: A draft that has survived N rounds of text review has still never bee...
|
|
362
|
+
|
|
363
|
+
- lesson_id: lesson-raised-80aae5ddff34
|
|
364
|
+
- finding_category: correctness
|
|
365
|
+
- statement: A draft that has survived N rounds of text review has still never been mechanically validated unless someone actually ran the validator: reviewers grade prose and validators grade shape, and neither notices that the other never ran.
|
|
366
|
+
|
|
367
|
+
### lesson-raised-6fa07c6529b9: A correction that declares its reach as "wherever this document spell...
|
|
368
|
+
|
|
369
|
+
- lesson_id: lesson-raised-6fa07c6529b9
|
|
370
|
+
- finding_category: correctness
|
|
371
|
+
- statement: A correction that declares its reach as "wherever this document spells X" and then enumerates the sites has created a count it must prove; enumerate by mechanical occurrence search, or the correction silently exempts the site it forgot.
|
|
372
|
+
|
|
373
|
+
### lesson-raised-c90b1840a097: Telling an agent to write early is not enough: the artifact contract ...
|
|
374
|
+
|
|
375
|
+
- lesson_id: lesson-raised-c90b1840a097
|
|
376
|
+
- finding_category: correctness
|
|
377
|
+
- statement: Telling an agent to write early is not enough: the artifact contract must mandate a minimum object count with explicit clean and not-reached sentinels, one write per question, so that a budget death leaves a readable partial instead of a file that cannot be told apart from a completed clean review.
|
|
378
|
+
|
|
379
|
+
### lesson-raised-1aabef29e2e1: A priority order stated in a resume prompt is as unenforceable as a t...
|
|
380
|
+
|
|
381
|
+
- lesson_id: lesson-raised-1aabef29e2e1
|
|
382
|
+
- finding_category: correctness
|
|
383
|
+
- statement: A priority order stated in a resume prompt is as unenforceable as a turn budget: the agent will spend its whole stint on the first item it finds tractable. If the order matters, dispatch one question per resume, or measure the remaining questions yourself.
|
|
384
|
+
|
|
385
|
+
### lesson-raised-eb10cdf5761b: A claim about how many leaves a revision changed must be measured ove...
|
|
386
|
+
|
|
387
|
+
- lesson_id: lesson-raised-eb10cdf5761b
|
|
388
|
+
- finding_category: correctness
|
|
389
|
+
- statement: A claim about how many leaves a revision changed must be measured over every leaf including scalars: a strings-only walker undercounts by exactly the version-number bumps, which is the one change every revision makes.
|
|
390
|
+
|
|
391
|
+
### lesson-raised-18c6a8c89228: A zero-occurrence sweep is evidence only after the coordinate is conf...
|
|
392
|
+
|
|
393
|
+
- lesson_id: lesson-raised-18c6a8c89228
|
|
394
|
+
- finding_category: correctness
|
|
395
|
+
- statement: A zero-occurrence sweep is evidence only after the coordinate is confirmed against the finding own location field: searching the wrong criterion returns a null that is indistinguishable from a real defect, and it will manufacture a false finding against correct text.
|
|
396
|
+
|
|
274
397
|
### lesson-raised-66bfd37ce01a: Never override the commit author with `git -c user.email=...`; the re...
|
|
275
398
|
|
|
276
399
|
- lesson_id: lesson-raised-66bfd37ce01a
|
|
@@ -356,6 +479,181 @@ _(none yet)_
|
|
|
356
479
|
- lesson_id: lesson-raised-bc8c041f3a8c
|
|
357
480
|
- statement: A hand-maintained list inside a guard is the hole the guard was built to close; derive the list from the source it checks (a `roots` array in `packaging.test.ts` did not name `ROADMAP_PATH`, so the guard passed the very gap it existed to catch).
|
|
358
481
|
|
|
482
|
+
### lesson-raised-04cd391ca791: A 404 from a scoped npm registry on a PUT is an authentication failur...
|
|
483
|
+
|
|
484
|
+
- lesson_id: lesson-raised-04cd391ca791
|
|
485
|
+
- statement: A 404 from a scoped npm registry on a PUT is an authentication failure, not a missing package: the registry hides an existing scope from an unauthorised token instead of returning 401.
|
|
486
|
+
|
|
487
|
+
### lesson-raised-1804a19612db: npm two-factor authentication makes publishing an operator-run step: ...
|
|
488
|
+
|
|
489
|
+
- lesson_id: lesson-raised-1804a19612db
|
|
490
|
+
- statement: npm two-factor authentication makes publishing an operator-run step: the OTP prompt cannot be satisfied by an agent, so a release runbook must hand the publish command to the operator rather than run it.
|
|
491
|
+
|
|
492
|
+
### lesson-raised-f39c1a53b31b: An npm packument carries `gitHead` for every published version, so th...
|
|
493
|
+
|
|
494
|
+
- lesson_id: lesson-raised-f39c1a53b31b
|
|
495
|
+
- statement: An npm packument carries `gitHead` for every published version, so the commit a release was cut from can be read back from the registry without relying on a tag.
|
|
496
|
+
|
|
497
|
+
### lesson-raised-bac9a3bd3b81: The auto-mode classifier denies `smith plan ingest`, an `mv` of a pla...
|
|
498
|
+
|
|
499
|
+
- lesson_id: lesson-raised-bac9a3bd3b81
|
|
500
|
+
- statement: The auto-mode classifier denies `smith plan ingest`, an `mv` of a plan file, and Bash reads of the skill playbooks under `.claude/skills/`; those steps need the operator or a different tool.
|
|
501
|
+
|
|
502
|
+
### lesson-raised-2528cf4e5f25: `smith wave check` requires the full event envelope and prints no eve...
|
|
503
|
+
|
|
504
|
+
- lesson_id: lesson-raised-2528cf4e5f25
|
|
505
|
+
- statement: `smith wave check` requires the full event envelope and prints no event id, so the id of the event it wrote has to be read back from the session log.
|
|
506
|
+
|
|
507
|
+
### lesson-raised-ccacd8f42e4e: Cut a worktree from the current base: a worktree cut before N merges ...
|
|
508
|
+
|
|
509
|
+
- lesson_id: lesson-raised-ccacd8f42e4e
|
|
510
|
+
- statement: Cut a worktree from the current base: a worktree cut before N merges tests a tree nobody will ship, and a green suite on it says nothing about the tree that lands.
|
|
511
|
+
|
|
512
|
+
### lesson-raised-3a856caf80ac: An effort-floor scan is not a security-reviewer dispatch; the two ans...
|
|
513
|
+
|
|
514
|
+
- lesson_id: lesson-raised-3a856caf80ac
|
|
515
|
+
- statement: An effort-floor scan is not a security-reviewer dispatch; the two answer different questions, and passing one does not discharge the other.
|
|
516
|
+
|
|
517
|
+
### lesson-raised-31b13840f6c5: An `error-logged` event requires `task_ref` in its payload; without i...
|
|
518
|
+
|
|
519
|
+
- lesson_id: lesson-raised-31b13840f6c5
|
|
520
|
+
- statement: An `error-logged` event requires `task_ref` in its payload; without it the append is refused.
|
|
521
|
+
|
|
522
|
+
### lesson-raised-612b4017e024: zsh expands an unquoted `--include` glob before grep ever sees it, so...
|
|
523
|
+
|
|
524
|
+
- lesson_id: lesson-raised-612b4017e024
|
|
525
|
+
- statement: zsh expands an unquoted `--include` glob before grep ever sees it, so the pattern must be quoted.
|
|
526
|
+
|
|
527
|
+
### lesson-raised-bf090949f8e9: The live plan is the `plan-v<n>.json` inside the epic worktree, not t...
|
|
528
|
+
|
|
529
|
+
- lesson_id: lesson-raised-bf090949f8e9
|
|
530
|
+
- statement: The live plan is the `plan-v<n>.json` inside the epic worktree, not the copy of it in the clone.
|
|
531
|
+
|
|
532
|
+
### lesson-raised-5b592f5d0052: `smith queue run --project <dir>` checks out the integration branch i...
|
|
533
|
+
|
|
534
|
+
- lesson_id: lesson-raised-5b592f5d0052
|
|
535
|
+
- statement: `smith queue run --project <dir>` checks out the integration branch in that directory, so it must never be pointed at the main clone.
|
|
536
|
+
|
|
537
|
+
### lesson-raised-9101d200fc02: The visible way to correct a false record in the event log is an oper...
|
|
538
|
+
|
|
539
|
+
- lesson_id: lesson-raised-9101d200fc02
|
|
540
|
+
- statement: The visible way to correct a false record in the event log is an operator-note carrying a non-operator actor, never a rewrite of the event that was wrong.
|
|
541
|
+
|
|
542
|
+
### lesson-raised-612b6c33c722: A `subprocess.run` environment must inherit `PATH`; a wholly replaced...
|
|
543
|
+
|
|
544
|
+
- lesson_id: lesson-raised-612b6c33c722
|
|
545
|
+
- statement: A `subprocess.run` environment must inherit `PATH`; a wholly replaced env silently loses every tool the command needs.
|
|
546
|
+
|
|
547
|
+
### lesson-raised-babd51405588: The factory leaked `SMITH_*` environment variables into project comma...
|
|
548
|
+
|
|
549
|
+
- lesson_id: lesson-raised-babd51405588
|
|
550
|
+
- statement: The factory leaked `SMITH_*` environment variables into project commands on two separate call paths, so one fix at one call site did not close the leak.
|
|
551
|
+
|
|
552
|
+
### lesson-raised-2ab8ba0c5201: `smith event append` takes one inline JSON envelope and no envelope f...
|
|
553
|
+
|
|
554
|
+
- lesson_id: lesson-raised-2ab8ba0c5201
|
|
555
|
+
- statement: `smith event append` takes one inline JSON envelope and no envelope flags, while `smith delegation check` takes its argument as a positional.
|
|
556
|
+
|
|
557
|
+
### lesson-raised-2b2a1e81e546: An orchestrator taking over a dead wave-runner's session must open it...
|
|
558
|
+
|
|
559
|
+
- lesson_id: lesson-raised-2b2a1e81e546
|
|
560
|
+
- statement: An orchestrator taking over a dead wave-runner's session must open its own session with `--continues`, rather than writing into the dead one.
|
|
561
|
+
|
|
562
|
+
### lesson-raised-f6787a2c84c7: Every markdown file in the repo is scanned by the doc tests unless it...
|
|
563
|
+
|
|
564
|
+
- lesson_id: lesson-raised-f6787a2c84c7
|
|
565
|
+
- statement: Every markdown file in the repo is scanned by the doc tests unless it matches the record-of-the-past shape.
|
|
566
|
+
|
|
567
|
+
### lesson-raised-b5d795d4b6d3: Verify a research finding against the code before writing it into the...
|
|
568
|
+
|
|
569
|
+
- lesson_id: lesson-raised-b5d795d4b6d3
|
|
570
|
+
- statement: Verify a research finding against the code before writing it into the roadmap.
|
|
571
|
+
|
|
572
|
+
### lesson-raised-27e836565b55: A reviewer finding can be right about the fact and wrong about the fi...
|
|
573
|
+
|
|
574
|
+
- lesson_id: lesson-raised-27e836565b55
|
|
575
|
+
- statement: A reviewer finding can be right about the fact and wrong about the fix, so the remedy has to be verified separately from the observation.
|
|
576
|
+
|
|
577
|
+
### lesson-raised-37f438433dfa: Prove a regression test discriminates by reverting the fix and watchi...
|
|
578
|
+
|
|
579
|
+
- lesson_id: lesson-raised-37f438433dfa
|
|
580
|
+
- statement: Prove a regression test discriminates by reverting the fix and watching the test fail; a green run on the already-fixed tree proves nothing.
|
|
581
|
+
|
|
582
|
+
### lesson-raised-80a2f7a7a5d5: Biome rejects `${VAR+set}` inside a JavaScript string.
|
|
583
|
+
|
|
584
|
+
- lesson_id: lesson-raised-80a2f7a7a5d5
|
|
585
|
+
- statement: Biome rejects `${VAR+set}` inside a JavaScript string.
|
|
586
|
+
|
|
587
|
+
### lesson-raised-378453209c3b: A red check in a stored background output may predate the fix; compar...
|
|
588
|
+
|
|
589
|
+
- lesson_id: lesson-raised-378453209c3b
|
|
590
|
+
- statement: A red check in a stored background output may predate the fix; compare timestamps before believing it.
|
|
591
|
+
|
|
592
|
+
### lesson-raised-46dd036c0dd9: `gh pr merge --delete-branch` fails to delete the local branch while ...
|
|
593
|
+
|
|
594
|
+
- lesson_id: lesson-raised-46dd036c0dd9
|
|
595
|
+
- statement: `gh pr merge --delete-branch` fails to delete the local branch while a worktree holds it, even though the merge and the remote branch deletion both succeeded; that error is not a failed merge.
|
|
596
|
+
|
|
597
|
+
### lesson-raised-e1d2d89d388f: A backticked dotted token in any instruction file is read as an error...
|
|
598
|
+
|
|
599
|
+
- lesson_id: lesson-raised-e1d2d89d388f
|
|
600
|
+
- statement: A backticked dotted token in any instruction file is read as an error code by the doc test.
|
|
601
|
+
|
|
602
|
+
### lesson-raised-3b940e498974: The event log's key is `event_type`, not `type`.
|
|
603
|
+
|
|
604
|
+
- lesson_id: lesson-raised-3b940e498974
|
|
605
|
+
- statement: The event log's key is `event_type`, not `type`.
|
|
606
|
+
|
|
607
|
+
### lesson-raised-02785579f29c: A node script that imports a repo dependency must live inside that re...
|
|
608
|
+
|
|
609
|
+
- lesson_id: lesson-raised-02785579f29c
|
|
610
|
+
- statement: A node script that imports a repo dependency must live inside that repo, unless it uses `createRequire` rooted at the target's own manifest.
|
|
611
|
+
|
|
612
|
+
### lesson-raised-ead91bf35c28: Before proposing that the factory call a library, check whether it is...
|
|
613
|
+
|
|
614
|
+
- lesson_id: lesson-raised-ead91bf35c28
|
|
615
|
+
- statement: Before proposing that the factory call a library, check whether it is a devDependency: the published package ships `dist` plus its runtime dependencies only.
|
|
616
|
+
|
|
617
|
+
### lesson-raised-d54fac4e1d74: The auto-mode classifier denies `gh pr merge` when it is chained with...
|
|
618
|
+
|
|
619
|
+
- lesson_id: lesson-raised-d54fac4e1d74
|
|
620
|
+
- statement: The auto-mode classifier denies `gh pr merge` when it is chained with another command; the bare form passes.
|
|
621
|
+
|
|
622
|
+
### lesson-raised-2c7a4d56b146: `gh pr checks --json state` returns `IN_PROGRESS` or `QUEUED`, never ...
|
|
623
|
+
|
|
624
|
+
- lesson_id: lesson-raised-2c7a4d56b146
|
|
625
|
+
- statement: `gh pr checks --json state` returns `IN_PROGRESS` or `QUEUED`, never `PENDING`.
|
|
626
|
+
|
|
627
|
+
### lesson-raised-d62b53f459bf: About twenty test files read `factory/specs/roadmap.md`, not only the...
|
|
628
|
+
|
|
629
|
+
- lesson_id: lesson-raised-d62b53f459bf
|
|
630
|
+
- statement: About twenty test files read `factory/specs/roadmap.md`, not only the six doc tests, so a wording change there needs the full suite.
|
|
631
|
+
|
|
632
|
+
### lesson-raised-19254ec2a441: Do not publish a gate claim before the gate finishes: state what was ...
|
|
633
|
+
|
|
634
|
+
- lesson_id: lesson-raised-19254ec2a441
|
|
635
|
+
- statement: Do not publish a gate claim before the gate finishes: state what was actually observed and name CI as the authority.
|
|
636
|
+
|
|
637
|
+
### lesson-raised-f2920a320b64: Never edit a file while a suite is running against it: the result the...
|
|
638
|
+
|
|
639
|
+
- lesson_id: lesson-raised-f2920a320b64
|
|
640
|
+
- statement: Never edit a file while a suite is running against it: the result then describes no single tree. Kill the run and restart it on the committed tree.
|
|
641
|
+
|
|
642
|
+
### lesson-raised-7eeb398fef59: Right after a push, `gh pr checks` reports that no checks were report...
|
|
643
|
+
|
|
644
|
+
- lesson_id: lesson-raised-7eeb398fef59
|
|
645
|
+
- statement: Right after a push, `gh pr checks` reports that no checks were reported; a waiter must treat that as still-pending, not as finished.
|
|
646
|
+
|
|
647
|
+
### lesson-raised-5a731cdab38f: A verification command and the commit that depends on it must be one ...
|
|
648
|
+
|
|
649
|
+
- lesson_id: lesson-raised-5a731cdab38f
|
|
650
|
+
- statement: A verification command and the commit that depends on it must be one `&&` chain, and its output must not be piped past the pass/fail line.
|
|
651
|
+
|
|
652
|
+
### lesson-raised-3a400ca69b5e: When two verbs are compared for cost, check when each one runs before...
|
|
653
|
+
|
|
654
|
+
- lesson_id: lesson-raised-3a400ca69b5e
|
|
655
|
+
- statement: When two verbs are compared for cost, check when each one runs before concluding: the cheaper one may run after the very gate it was meant to save.
|
|
656
|
+
|
|
359
657
|
## security
|
|
360
658
|
|
|
361
659
|
_(none yet)_
|
|
@@ -56,14 +56,39 @@ autonomy:
|
|
|
56
56
|
#
|
|
57
57
|
# The operator's standing decision, 2026-09-02: auto-dispatch with a
|
|
58
58
|
# whitelist. Rechecks and maintenance may run themselves; growth review
|
|
59
|
-
# and anything touching a security surface always wait
|
|
60
|
-
#
|
|
59
|
+
# and anything touching a security surface always wait.
|
|
60
|
+
#
|
|
61
|
+
# Amended 2026-09-18: PRs are no longer merged by a person. That sentence
|
|
62
|
+
# used to stand here as the backstop that made auto-dispatch safe to widen,
|
|
63
|
+
# and deleting it without a replacement would leave this block resting on
|
|
64
|
+
# nothing. What replaces it is the six conjunctive conditions in
|
|
65
|
+
# docs/specs/continuous-loop-scope.md 3.5 — green gate with no pending
|
|
66
|
+
# waiver, no open S1/S2, green CI on the merge head, no protected
|
|
67
|
+
# declaration touched, no security keyword matched, and a merge through the
|
|
68
|
+
# PR rather than a push to main. The third of those is the load-bearing
|
|
69
|
+
# one: an epic that would change THIS FILE, autonomy.ts, budgets.yml,
|
|
70
|
+
# delegation.yml, .claude/settings.json, an agent template, a spec schema
|
|
71
|
+
# or the enable marker classifies operator and never reaches the merge at
|
|
72
|
+
# all. The loop may merge what it builds; it may not merge what bounds it.
|
|
73
|
+
#
|
|
74
|
+
# None of those six is enforced by code yet, because `smith loop` does not
|
|
75
|
+
# exist yet. Until it does, this block's `enabled: true` still only governs
|
|
76
|
+
# dispatch, and the merge is performed by whoever is driving the session.
|
|
61
77
|
enabled: true
|
|
62
78
|
|
|
63
79
|
# Nothing outside this list is ever auto-dispatched, and listing
|
|
64
80
|
# `growth-review-due` would not change that: architecture §12 keeps scope
|
|
65
81
|
# with the operator unconditionally, so autonomy.ts denies it whatever this
|
|
66
82
|
# says. The list is a ceiling, never a floor.
|
|
83
|
+
#
|
|
84
|
+
# `error-report` — the daemon proposing that an error the log holds with
|
|
85
|
+
# no `issue-reported` event be filed (`smith issues report`) — is left out
|
|
86
|
+
# on purpose, and listing it would not change that either. Filing writes
|
|
87
|
+
# to an external issue tracker under an authenticated `gh` token whose
|
|
88
|
+
# scope includes `repo`, and this block's standing decision is that
|
|
89
|
+
# anything touching auth or secrets always waits for a person; autonomy.ts
|
|
90
|
+
# refuses the kind ahead of this list (`tracker-write-never-auto`), the
|
|
91
|
+
# same shape `growth-never-auto` uses.
|
|
67
92
|
auto_dispatch_kinds: [recheck, maintenance]
|
|
68
93
|
|
|
69
94
|
# Rechecks are whitelisted BY REASON, and this is the one knob in the file
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
# across months of runs. Changing the taxonomy is a PR that bumps `version` —
|
|
10
10
|
# never a runtime write. Analytics may group only by taxonomy dimensions.
|
|
11
11
|
|
|
12
|
-
version:
|
|
12
|
+
version: 11
|
|
13
13
|
|
|
14
14
|
# ── Work classification ─────────────────────────────────────────────
|
|
15
15
|
case: [feature, bugfix, refactor, research, spec-review, recheck,
|
|
@@ -32,7 +32,7 @@ agent: [planner, spec-reviewer, researcher, coder, tester, grader,
|
|
|
32
32
|
# operator — the human, as a `found_by`: a defect read off the code
|
|
33
33
|
# by a person. Never dispatched — no template, no budget, no
|
|
34
34
|
# delegation grant, no judge turn — so nothing that counts
|
|
35
|
-
# rounds or pairs roles ever sees it (dogfood
|
|
35
|
+
# rounds or pairs roles ever sees it (added after a dogfood run)
|
|
36
36
|
|
|
37
37
|
provider: [claude, codex, deepseek]
|
|
38
38
|
model_tier: [frontier, mid, small] # fable/opus · sonnet · haiku
|
|
@@ -77,7 +77,7 @@ gate_event: [schema-check-result, artifact-check-result,
|
|
|
77
77
|
finding-raised, finding-reverified, finding-suppressed,
|
|
78
78
|
finding-transitioned, finding-reattributed,
|
|
79
79
|
severity-decisions, waiver-granted, waiver-denied,
|
|
80
|
-
gate-outcome]
|
|
80
|
+
gate-outcome, issue-reported]
|
|
81
81
|
# schema-check-result — task Result vs result.schema.json
|
|
82
82
|
# artifact-check-result — every artifacts[].path in that
|
|
83
83
|
# Result, resolved against the task's
|
|
@@ -196,6 +196,13 @@ gate_event: [schema-check-result, artifact-check-result,
|
|
|
196
196
|
# keyed by finding fingerprint
|
|
197
197
|
# gate-outcome — the composed gate pipeline's
|
|
198
198
|
# final structured result
|
|
199
|
+
# issue-reported — issueReporter.ts's record of one
|
|
200
|
+
# attempt to open or comment on an
|
|
201
|
+
# external tracker issue for a
|
|
202
|
+
# gate-outcome, task-failed or
|
|
203
|
+
# error-logged candidate: outcome,
|
|
204
|
+
# reason and the fingerprint group's
|
|
205
|
+
# latest_event_id
|
|
199
206
|
|
|
200
207
|
# ── Errors: grouped two-level classes (always logged as group.class) ─
|
|
201
208
|
error:
|