@wildorder/nightshift 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +21 -21
  2. package/dist/author.d.ts +13 -0
  3. package/dist/author.d.ts.map +1 -1
  4. package/dist/author.js +46 -13
  5. package/dist/author.js.map +1 -1
  6. package/dist/cli.js +1 -1
  7. package/dist/cli.js.map +1 -1
  8. package/dist/decide.d.ts +13 -5
  9. package/dist/decide.d.ts.map +1 -1
  10. package/dist/decide.js +50 -35
  11. package/dist/decide.js.map +1 -1
  12. package/dist/decider-review.d.ts +68 -1
  13. package/dist/decider-review.d.ts.map +1 -1
  14. package/dist/decider-review.js +211 -3
  15. package/dist/decider-review.js.map +1 -1
  16. package/dist/decision-ledger.d.ts +79 -1
  17. package/dist/decision-ledger.d.ts.map +1 -1
  18. package/dist/decision-ledger.js +118 -11
  19. package/dist/decision-ledger.js.map +1 -1
  20. package/dist/decision-view.d.ts +41 -0
  21. package/dist/decision-view.d.ts.map +1 -0
  22. package/dist/decision-view.js +264 -0
  23. package/dist/decision-view.js.map +1 -0
  24. package/dist/findings.d.ts +3 -0
  25. package/dist/findings.d.ts.map +1 -1
  26. package/dist/findings.js.map +1 -1
  27. package/dist/index.d.ts +2 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/manifest.d.ts +2 -2
  32. package/dist/programs-dir.d.ts +27 -0
  33. package/dist/programs-dir.d.ts.map +1 -0
  34. package/dist/programs-dir.js +52 -0
  35. package/dist/programs-dir.js.map +1 -0
  36. package/dist/publish.d.ts.map +1 -1
  37. package/dist/publish.js +21 -32
  38. package/dist/publish.js.map +1 -1
  39. package/dist/review-pass.d.ts +33 -1
  40. package/dist/review-pass.d.ts.map +1 -1
  41. package/dist/review-pass.js +94 -42
  42. package/dist/review-pass.js.map +1 -1
  43. package/dist/run-program.d.ts +25 -3
  44. package/dist/run-program.d.ts.map +1 -1
  45. package/dist/run-program.js +382 -42
  46. package/dist/run-program.js.map +1 -1
  47. package/package.json +3 -3
  48. package/templates/AGENTS.md +29 -29
  49. package/templates/CLAUDE.md +7 -7
  50. package/templates/vision.md +46 -46
@@ -1,6 +1,7 @@
1
1
  import { type AgentRunner } from "./agent-runner.js";
2
2
  import type { AgentConfig } from "./config.js";
3
- import { type DecisionBlock } from "./decision.js";
3
+ import { type DecisionBlock, type DecisionOption } from "./decision.js";
4
+ import { type LedgerEvent } from "./decision-ledger.js";
4
5
  import type { ProgramManifest } from "./manifest.js";
5
6
  import type { GitOps } from "./run-program.js";
6
7
  export interface ReviewDecisionsOptions {
@@ -14,8 +15,74 @@ export interface ReviewDecisionsOptions {
14
15
  agentRunner: AgentRunner;
15
16
  git: GitOps;
16
17
  isRepository: boolean;
18
+ /**
19
+ * Subject ids already sent to the decider this run, shared across the
20
+ * authoring and build stages and across both the decision and finding
21
+ * paths. Consulted, then added, immediately before each invocation, so a
22
+ * subject that re-surfaces in the same run is never reviewed twice while a
23
+ * later run still reviews it correctly (SC-10). This is a "sent" set, not
24
+ * a "ruled on" set — see `triaged`.
25
+ */
26
+ reviewed: Set<string>;
27
+ /**
28
+ * Subject ids the decider actually ruled on this run — added only after a
29
+ * successful invocation produced a valid verdict that was appended to the
30
+ * ledger. Distinct from `reviewed` (which marks a subject as sent, even
31
+ * when the invocation fails or the decider returns no parseable verdict):
32
+ * this is the run-local basis the report's triage ratio (SC-07) needs, so
33
+ * a failed or protocol-invalid decider run is never counted as having
34
+ * triaged the subject.
35
+ */
36
+ triaged: Set<string>;
17
37
  now: () => Date;
18
38
  log: (line: string) => void;
19
39
  }
20
40
  export declare function reviewDecisions(options: ReviewDecisionsOptions): Promise<void>;
41
+ export type FindingRecordedEvent = Extract<LedgerEvent, {
42
+ kind: "finding-recorded";
43
+ }>;
44
+ export type TriageVerdict = {
45
+ disposition: "fix-now" | "accept";
46
+ rationale: string;
47
+ } | {
48
+ disposition: "escalate";
49
+ rationale: string;
50
+ question: string;
51
+ alternatives: DecisionOption[];
52
+ };
53
+ /**
54
+ * Parses the finding-triage verdict block, last-block-wins, fail-closed to
55
+ * `undefined` — mirroring `extractVerdict`. An `escalate` verdict missing a
56
+ * real, non-blank question or a non-empty array of well-formed alternatives
57
+ * is rejected here rather than written: the invariant that a ledgered
58
+ * `escalate` always carries both holds at this boundary (SC-12).
59
+ */
60
+ export declare function extractTriageVerdict(output: string): TriageVerdict | undefined;
61
+ export interface TriageFindingsOptions {
62
+ root: string;
63
+ programId: string;
64
+ manifest: ProgramManifest;
65
+ workstreamId: string;
66
+ /** The routed `finding-recorded` events for this workstream — already appended to the ledger. */
67
+ findings: FindingRecordedEvent[];
68
+ /** The pre-workstream diff base, same as `reviewDecisions` uses. */
69
+ baseCommit: string | undefined;
70
+ decider: AgentConfig | undefined;
71
+ agentRunner: AgentRunner;
72
+ git: GitOps;
73
+ isRepository: boolean;
74
+ /** Shared with `reviewDecisions` — see that option's doc comment. */
75
+ reviewed: Set<string>;
76
+ /** Shared with `reviewDecisions` — see that option's doc comment. */
77
+ triaged: Set<string>;
78
+ now: () => Date;
79
+ log: (line: string) => void;
80
+ }
81
+ /**
82
+ * Triages each routed finding with the charter's three dispositions. This
83
+ * only records a `fix-now` triage — WS-06 acts on it. Fails open throughout:
84
+ * no decider, a non-zero exit, an unparseable verdict, or a hollow
85
+ * escalation leaves the finding `open` and never blocks the run.
86
+ */
87
+ export declare function triageFindings(options: TriageFindingsOptions): Promise<void>;
21
88
  //# sourceMappingURL=decider-review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decider-review.d.ts","sourceRoot":"","sources":["../src/decider-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAkF/C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA2Cf"}
1
+ {"version":3,"file":"decider-review.d.ts","sourceRoot":"","sources":["../src/decider-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AA4F/C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAgDf;AAMD,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,WAAW,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAAC;AAkHtF,MAAM,MAAM,aAAa,GACrB;IAAE,WAAW,EAAE,SAAS,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACxD;IACE,WAAW,EAAE,UAAU,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC,CAAC;AAEN;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAyC9E;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,eAAe,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,oEAAoE;IACpE,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,qEAAqE;IACrE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,qEAAqE;IACrE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DlF"}
@@ -7,12 +7,22 @@ import { appendLedgerEvents } from "./decision-ledger.js";
7
7
  * decision, one invocation, one verdict — a judgment, not a dialogue. No
8
8
  * decider configured means defaults stand unratified, which the run report
9
9
  * says plainly.
10
+ *
11
+ * A routed finding is a different kind of subject — raised by an
12
+ * independent reviewer, not a judgment call an agent stands behind — and
13
+ * gets its own triage path (`triageFindings`) with its own three-disposition
14
+ * vocabulary. The two paths are kept physically separate on purpose: an
15
+ * agent's own decision must stay on its untouched `ratify`/`escalate`
16
+ * contract.
10
17
  */
11
18
  const DIFF_LIMIT = 20_000;
12
- function deciderBrief(manifest, record, diff) {
13
- const clippedDiff = diff.length > DIFF_LIMIT
19
+ function clipDiff(diff) {
20
+ return diff.length > DIFF_LIMIT
14
21
  ? `${diff.slice(0, DIFF_LIMIT)}\n… (diff clipped at ${DIFF_LIMIT} characters)`
15
22
  : diff;
23
+ }
24
+ function deciderBrief(manifest, record, diff) {
25
+ const clippedDiff = clipDiff(diff);
16
26
  return [
17
27
  "# Review one decision",
18
28
  "",
@@ -66,7 +76,7 @@ function extractVerdict(output) {
66
76
  return undefined;
67
77
  }
68
78
  export async function reviewDecisions(options) {
69
- const { root, programId, manifest, workstreamId, decisions, baseCommit, decider, agentRunner, git, isRepository, now, log, } = options;
79
+ const { root, programId, manifest, workstreamId, decisions, baseCommit, decider, agentRunner, git, isRepository, reviewed, triaged, now, log, } = options;
70
80
  if (!decider || decisions.length === 0)
71
81
  return;
72
82
  const diff = isRepository && baseCommit !== undefined
@@ -74,6 +84,9 @@ export async function reviewDecisions(options) {
74
84
  : "";
75
85
  for (const decision of decisions) {
76
86
  const id = decisionFingerprint(workstreamId, decision);
87
+ if (reviewed.has(id))
88
+ continue;
89
+ reviewed.add(id);
77
90
  const brief = deciderBrief(manifest, { workstream: workstreamId, decision }, diff);
78
91
  const invocation = await invokeAgent(agentRunner, decider, brief, root);
79
92
  const verdict = extractVerdict(invocation.output);
@@ -92,7 +105,202 @@ export async function reviewDecisions(options) {
92
105
  reviewedBy: "decider",
93
106
  };
94
107
  await appendLedgerEvents(root, programId, [event]);
108
+ triaged.add(id);
95
109
  log(`${workstreamId} decision ${id}: ${verdict.verdict}`);
96
110
  }
97
111
  }
112
+ function findingEvidenceLines(evidence) {
113
+ return evidence.map((item) => {
114
+ if (item.kind === "location") {
115
+ const range = item.endLine === undefined ? `${item.startLine}` : `${item.startLine}-${item.endLine}`;
116
+ const location = `${item.file}:${range}${item.unverifiable ? " (unverifiable path)" : ""}`;
117
+ return item.excerpt ? `- ${location} — ${item.excerpt}` : `- ${location}`;
118
+ }
119
+ if (item.kind === "concern") {
120
+ return item.detail ? `- ${item.named} — ${item.detail}` : `- ${item.named}`;
121
+ }
122
+ return `- ${item.metric}: ${item.value}`;
123
+ });
124
+ }
125
+ /**
126
+ * The origin-aware finding brief (SC-11): states plainly that the subject is
127
+ * a finding routed from a review pass, never framed as an agent's own
128
+ * judgment call, renders the finding as the structured data it is, offers
129
+ * the three dispositions with honest definitions, and — for a finding the
130
+ * reviewer itself declined to rate a blocker — states in prose (never a
131
+ * numeric cap) that escalation is reserved for the genuinely unsettleable.
132
+ */
133
+ function findingTriageBrief(manifest, workstreamId, event, diff) {
134
+ const clippedDiff = clipDiff(diff);
135
+ const evidenceLines = findingEvidenceLines(event.evidence);
136
+ const higherBar = event.severity === "major"
137
+ ? [
138
+ "This finding's severity is **major** — the reviewer itself",
139
+ "declined to rate it a blocker. That is itself evidence: reserve",
140
+ "`escalate` for what is genuinely unsettleable here, and lean on",
141
+ "`fix-now` or `accept` — a reviewer that stopped short of blocker",
142
+ "is usually right that the crew can settle this on its own.",
143
+ "",
144
+ ]
145
+ : [];
146
+ return [
147
+ "# Triage a finding",
148
+ "",
149
+ `Program: ${manifest.program.id} — ${manifest.program.name}`,
150
+ `Workstream: ${workstreamId}`,
151
+ "",
152
+ "This is a **finding routed from a review pass** — raised by an",
153
+ "independent reviewer, not a judgment call an implementing agent made",
154
+ "and stands behind. Your job is to triage it: fix it now, accept it as",
155
+ "a known limitation, or escalate it to the human. You never edit",
156
+ "anything.",
157
+ "",
158
+ `- **Severity:** ${event.severity}`,
159
+ `- **Category:** ${event.category}`,
160
+ `- **Subject:** ${event.subject}`,
161
+ `- **Message:** ${event.message}`,
162
+ ...(evidenceLines.length > 0 ? ["- **Evidence:**", ...evidenceLines] : []),
163
+ "",
164
+ ...higherBar,
165
+ "The work this finding concerns:",
166
+ "",
167
+ "```diff",
168
+ clippedDiff.trim() === "" ? "(no diff available)" : clippedDiff,
169
+ "```",
170
+ "",
171
+ "Reply with exactly one verdict block:",
172
+ "",
173
+ "```verdict",
174
+ "{",
175
+ ' "disposition": "fix-now" | "accept" | "escalate",',
176
+ ' "rationale": "One or two sentences, written for the human who reads the run report.",',
177
+ ' "question": "…",',
178
+ ' "alternatives": [',
179
+ ' { "label": "…", "description": "…" }',
180
+ " ]",
181
+ "}",
182
+ "```",
183
+ "",
184
+ "`question` and `alternatives` apply only to `escalate` — omit them for",
185
+ "`fix-now` or `accept`.",
186
+ "",
187
+ "`fix-now`: the finding is worth one bounded fix attempt in this run",
188
+ "before proceeding. `accept`: a real but tolerable limitation, recorded",
189
+ "for the human and not worth stopping for. `escalate`: the crew cannot",
190
+ "settle this and the human should rule — compose the question and the",
191
+ "real alternatives yourself, in your own words. One triage, one",
192
+ "verdict: this is a judgment, not a dialogue.",
193
+ ].join("\n");
194
+ }
195
+ /**
196
+ * A well-formed escalation alternative, per SC-12 and the verdict contract:
197
+ * a *real* `{ label, description }` composed by the decider, not a bare
198
+ * label. Unlike `DecisionOption` (where `description` is optional for an
199
+ * agent's own decision options), an escalation alternative requires a
200
+ * non-blank description — a hollow `{ "label": "fix" }` is not an
201
+ * alternative the human can rule on.
202
+ */
203
+ function isWellFormedAlternative(value) {
204
+ if (typeof value !== "object" || value === null)
205
+ return false;
206
+ const candidate = value;
207
+ if (typeof candidate.label !== "string" || candidate.label.trim() === "")
208
+ return false;
209
+ if (typeof candidate.description !== "string" || candidate.description.trim() === "") {
210
+ return false;
211
+ }
212
+ return true;
213
+ }
214
+ /**
215
+ * Parses the finding-triage verdict block, last-block-wins, fail-closed to
216
+ * `undefined` — mirroring `extractVerdict`. An `escalate` verdict missing a
217
+ * real, non-blank question or a non-empty array of well-formed alternatives
218
+ * is rejected here rather than written: the invariant that a ledgered
219
+ * `escalate` always carries both holds at this boundary (SC-12).
220
+ */
221
+ export function extractTriageVerdict(output) {
222
+ const matches = [...output.matchAll(/```verdict[^\S\r\n]*\r?\n([\s\S]*?)```/gu)];
223
+ for (const match of matches.reverse()) {
224
+ try {
225
+ const parsed = JSON.parse(match[1] ?? "");
226
+ if (typeof parsed.rationale !== "string")
227
+ continue;
228
+ if (parsed.disposition === "fix-now" || parsed.disposition === "accept") {
229
+ return { disposition: parsed.disposition, rationale: parsed.rationale };
230
+ }
231
+ if (parsed.disposition === "escalate") {
232
+ const question = parsed.question;
233
+ const alternatives = parsed.alternatives;
234
+ if (typeof question === "string" &&
235
+ question.trim() !== "" &&
236
+ Array.isArray(alternatives) &&
237
+ alternatives.length > 0 &&
238
+ alternatives.every(isWellFormedAlternative)) {
239
+ return {
240
+ disposition: "escalate",
241
+ rationale: parsed.rationale,
242
+ question,
243
+ alternatives,
244
+ };
245
+ }
246
+ // A hollow escalation (missing question/alternatives) is rejected at
247
+ // this boundary — try an earlier block rather than writing it.
248
+ }
249
+ }
250
+ catch {
251
+ // Try an earlier block.
252
+ }
253
+ }
254
+ return undefined;
255
+ }
256
+ /**
257
+ * Triages each routed finding with the charter's three dispositions. This
258
+ * only records a `fix-now` triage — WS-06 acts on it. Fails open throughout:
259
+ * no decider, a non-zero exit, an unparseable verdict, or a hollow
260
+ * escalation leaves the finding `open` and never blocks the run.
261
+ */
262
+ export async function triageFindings(options) {
263
+ const { root, programId, manifest, workstreamId, findings, baseCommit, decider, agentRunner, git, isRepository, reviewed, triaged, now, log, } = options;
264
+ if (!decider || findings.length === 0)
265
+ return;
266
+ const diff = isRepository && baseCommit !== undefined
267
+ ? await git.diffSince(root, baseCommit)
268
+ : "";
269
+ for (const event of findings) {
270
+ if (reviewed.has(event.id))
271
+ continue;
272
+ reviewed.add(event.id);
273
+ const brief = findingTriageBrief(manifest, workstreamId, event, diff);
274
+ const invocation = await invokeAgent(agentRunner, decider, brief, root);
275
+ const verdict = extractTriageVerdict(invocation.output);
276
+ if (invocation.exitCode !== 0 || verdict === undefined) {
277
+ // Fail open: an untriaged finding stays open and the report says so;
278
+ // it never blocks the run.
279
+ log(`${workstreamId} finding ${event.id}: decider produced no verdict; left untriaged`);
280
+ continue;
281
+ }
282
+ const triageEvent = verdict.disposition === "escalate"
283
+ ? {
284
+ kind: "finding-triaged",
285
+ at: now().toISOString(),
286
+ id: event.id,
287
+ disposition: "escalate",
288
+ rationale: verdict.rationale,
289
+ question: verdict.question,
290
+ alternatives: verdict.alternatives,
291
+ reviewedBy: "decider",
292
+ }
293
+ : {
294
+ kind: "finding-triaged",
295
+ at: now().toISOString(),
296
+ id: event.id,
297
+ disposition: verdict.disposition,
298
+ rationale: verdict.rationale,
299
+ reviewedBy: "decider",
300
+ };
301
+ await appendLedgerEvents(root, programId, [triageEvent]);
302
+ triaged.add(event.id);
303
+ log(`${workstreamId} finding ${event.id}: ${verdict.disposition}`);
304
+ }
305
+ }
98
306
  //# sourceMappingURL=decider-review.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decider-review.js","sourceRoot":"","sources":["../src/decider-review.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decider-review.js","sourceRoot":"","sources":["../src/decider-review.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- import type { DecisionBlock } from "./decision.js";
1
+ import type { DecisionBlock, DecisionOption } from "./decision.js";
2
+ import type { Evidence, FindingCategory, Severity } from "./findings.js";
2
3
  /**
3
4
  * The decision ledger: an append-only JSONL journal per program, the durable
4
5
  * record of every judgment call a run made, who reviewed it, and what a
@@ -34,6 +35,46 @@ export type LedgerEvent = (EventBase & {
34
35
  /** The option label the human settled on. */
35
36
  chosen: string;
36
37
  reason: string;
38
+ }) | (EventBase & {
39
+ kind: "finding-recorded";
40
+ workstream: string;
41
+ severity: Severity;
42
+ category: FindingCategory;
43
+ subject: string;
44
+ message: string;
45
+ evidence: Evidence[];
46
+ /** The finding's optional machine code. */
47
+ code?: string;
48
+ /** The green pre-critique commit — the anchor. */
49
+ baseCommit?: string;
50
+ /** Attribution — never "implementer": a finding is the reviewer's. */
51
+ foundBy: "reviewer";
52
+ }) | (EventBase & ({
53
+ kind: "finding-triaged";
54
+ disposition: "fix-now" | "accept";
55
+ rationale: string;
56
+ reviewedBy: "decider";
57
+ } | {
58
+ kind: "finding-triaged";
59
+ disposition: "escalate";
60
+ rationale: string;
61
+ /** Composed by the decider. */
62
+ question: string;
63
+ /** The real alternatives, in the decider's words. */
64
+ alternatives: DecisionOption[];
65
+ reviewedBy: "decider";
66
+ })) | (EventBase & {
67
+ kind: "finding-fix-attempted";
68
+ /** "kept" only when a fix verified clean AND landed a commit; "failed"
69
+ * for a failed verification or a clean attempt that produced no
70
+ * commit. */
71
+ outcome: "kept" | "failed";
72
+ /** The implementer's verbatim summary, plus (on failure) the
73
+ * verification diagnosis or the no-change fact. */
74
+ note: string;
75
+ /** The fix commit, present only on a kept fix that landed one. */
76
+ commit?: string;
77
+ attemptedBy: "implementer";
37
78
  });
38
79
  export type DecisionStatus = "unratified" | "ratified" | "escalated" | "human-decided";
39
80
  export interface DecisionRecord {
@@ -50,8 +91,45 @@ export interface DecisionRecord {
50
91
  /** True when the agent claimed the choice is costly to undo. */
51
92
  oneWay: boolean;
52
93
  }
94
+ export type FindingStatus = "open" | "fix-now" | "accepted" | "escalated" | "human-decided";
95
+ export interface FindingRecord {
96
+ id: string;
97
+ workstream: string;
98
+ severity: Severity;
99
+ category: FindingCategory;
100
+ subject: string;
101
+ message: string;
102
+ evidence: Evidence[];
103
+ code?: string;
104
+ baseCommit?: string;
105
+ status: FindingStatus;
106
+ /** Present when a decider triaged it. */
107
+ triageRationale?: string;
108
+ /** Present when the decider escalated; the composed question. */
109
+ escalationQuestion?: string;
110
+ escalationAlternatives?: DecisionOption[];
111
+ /** Present when a human decided; overrides the decider's triage. */
112
+ humanChosen?: string;
113
+ humanReason?: string;
114
+ foundBy: "reviewer";
115
+ /** Discriminates from a DecisionRecord where a union of both is handled. */
116
+ origin: "finding";
117
+ /**
118
+ * Present once a `fix-now` triage has driven a bounded fix attempt
119
+ * (WS-06). "kept" leaves `status` at `"fix-now"` — a fix-attempt-and-verify
120
+ * fact, not a per-finding proof of correction; "failed" moves `status` to
121
+ * `"escalated"` while `triageRationale` (the decider's original reason)
122
+ * stays untouched.
123
+ */
124
+ fixAttempt?: {
125
+ outcome: "kept" | "failed";
126
+ note: string;
127
+ commit?: string;
128
+ };
129
+ }
53
130
  export interface DecisionLedgerView {
54
131
  decisions: DecisionRecord[];
132
+ findings: FindingRecord[];
55
133
  /** Journal lines that could not be read; reported, never fatal. */
56
134
  corrupt: number;
57
135
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decision-ledger.d.ts","sourceRoot":"","sources":["../src/decision-ledger.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,WAAW,GACnB,CAAC,SAAS,GAAG;IACX,IAAI,EAAE,mBAAmB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,aAAa,CAAC;CAC1B,CAAC,GACF,CAAC,SAAS,GAAG;IACX,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,CAAC;CACvB,CAAC,GACF,CAAC,SAAS,GAAG;IACX,IAAI,EAAE,gBAAgB,CAAC;IACvB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEP,MAAM,MAAM,cAAc,GACtB,YAAY,GACZ,UAAU,GACV,WAAW,GACX,eAAe,CAAC;AAEpB,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAOlE;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EAAE,GACpB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,kBAAkB,CA8C5E;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CA0B7B"}
1
+ {"version":3,"file":"decision-ledger.d.ts","sourceRoot":"","sources":["../src/decision-ledger.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,11 @@ import { dirname, join, resolve } from "node:path";
13
13
  * blocked run — because the ledger explains work, it does not gate it.
14
14
  */
15
15
  export const LEDGER_SCHEMA_VERSION = 1;
16
+ const FINDING_STATUS_BY_DISPOSITION = {
17
+ "fix-now": "fix-now",
18
+ accept: "accepted",
19
+ escalate: "escalated",
20
+ };
16
21
  export function ledgerPath(root, programId) {
17
22
  return join(resolve(root), "docs", "programs", `${programId}-decisions.jsonl`);
18
23
  }
@@ -27,13 +32,14 @@ export async function appendLedgerEvents(root, programId, events) {
27
32
  await appendFile(path, `${lines}\n`, "utf8");
28
33
  }
29
34
  export function reduceLedgerEvents(events) {
30
- const byId = new Map();
35
+ const decisionsById = new Map();
36
+ const findingsById = new Map();
31
37
  for (const event of events) {
32
38
  if (event.kind === "decision-recorded") {
33
- const existing = byId.get(event.id);
39
+ const existing = decisionsById.get(event.id);
34
40
  // A re-recorded decision (retry, resumed run) refreshes the block but
35
41
  // keeps any higher-authority outcome already on the record.
36
- byId.set(event.id, {
42
+ decisionsById.set(event.id, {
37
43
  id: event.id,
38
44
  workstream: event.workstream,
39
45
  decision: event.decision,
@@ -54,23 +60,124 @@ export function reduceLedgerEvents(events) {
54
60
  });
55
61
  continue;
56
62
  }
57
- const record = byId.get(event.id);
58
- if (!record)
63
+ if (event.kind === "finding-recorded") {
64
+ const existing = findingsById.get(event.id);
65
+ // Mirrors the decision-recorded re-record rule: refresh the finding's
66
+ // own fields, keep any higher-authority outcome already on it.
67
+ findingsById.set(event.id, {
68
+ id: event.id,
69
+ workstream: event.workstream,
70
+ severity: event.severity,
71
+ category: event.category,
72
+ subject: event.subject,
73
+ message: event.message,
74
+ evidence: event.evidence,
75
+ ...(event.code === undefined ? {} : { code: event.code }),
76
+ ...(event.baseCommit === undefined
77
+ ? {}
78
+ : { baseCommit: event.baseCommit }),
79
+ status: existing?.status ?? "open",
80
+ ...(existing?.triageRationale === undefined
81
+ ? {}
82
+ : { triageRationale: existing.triageRationale }),
83
+ ...(existing?.escalationQuestion === undefined
84
+ ? {}
85
+ : { escalationQuestion: existing.escalationQuestion }),
86
+ ...(existing?.escalationAlternatives === undefined
87
+ ? {}
88
+ : { escalationAlternatives: existing.escalationAlternatives }),
89
+ ...(existing?.humanChosen === undefined
90
+ ? {}
91
+ : { humanChosen: existing.humanChosen }),
92
+ ...(existing?.humanReason === undefined
93
+ ? {}
94
+ : { humanReason: existing.humanReason }),
95
+ ...(existing?.fixAttempt === undefined
96
+ ? {}
97
+ : { fixAttempt: existing.fixAttempt }),
98
+ foundBy: "reviewer",
99
+ origin: "finding",
100
+ });
59
101
  continue;
102
+ }
103
+ if (event.kind === "finding-triaged") {
104
+ const record = findingsById.get(event.id);
105
+ if (!record)
106
+ continue;
107
+ // Human authority already on the record outranks a decider triage.
108
+ if (record.status === "human-decided")
109
+ continue;
110
+ record.status = FINDING_STATUS_BY_DISPOSITION[event.disposition];
111
+ record.triageRationale = event.rationale;
112
+ if (event.disposition === "escalate") {
113
+ record.escalationQuestion = event.question;
114
+ record.escalationAlternatives = event.alternatives;
115
+ }
116
+ continue;
117
+ }
118
+ if (event.kind === "finding-fix-attempted") {
119
+ const record = findingsById.get(event.id);
120
+ if (!record)
121
+ continue;
122
+ // Human authority already on the record outranks a fix attempt — the
123
+ // fix-now driver never selects a human-decided finding in the first
124
+ // place (it reads the same projection), but an older run's ledger can
125
+ // still contain the event, so the reducer stays harmless either way.
126
+ if (record.status === "human-decided")
127
+ continue;
128
+ record.fixAttempt = {
129
+ outcome: event.outcome,
130
+ note: event.note,
131
+ ...(event.commit === undefined ? {} : { commit: event.commit }),
132
+ };
133
+ // A kept fix leaves status at "fix-now" — the presence of a "kept"
134
+ // fixAttempt is what distinguishes it from a still-pending fix-now
135
+ // finding. A failed fix — a failed verification or a clean attempt
136
+ // that landed no commit — is promoted to escalation: this is the
137
+ // *only* place that promotion happens, a projection, not a re-triage.
138
+ if (event.outcome === "failed") {
139
+ record.status = "escalated";
140
+ }
141
+ continue;
142
+ }
60
143
  if (event.kind === "decision-reviewed") {
144
+ const record = decisionsById.get(event.id);
145
+ if (!record)
146
+ continue;
61
147
  // Human authority already on the record outranks a decider review.
62
148
  if (record.status === "human-decided")
63
149
  continue;
64
150
  record.status = event.verdict === "ratify" ? "ratified" : "escalated";
65
151
  record.reviewRationale = event.rationale;
152
+ continue;
66
153
  }
67
- else {
68
- record.status = "human-decided";
69
- record.humanChosen = event.chosen;
70
- record.humanReason = event.reason;
154
+ if (event.kind === "decision-human") {
155
+ // A human ruling settles whichever record matches the id — a decision
156
+ // or a finding — never both, since ids never collide across the two.
157
+ const decision = decisionsById.get(event.id);
158
+ if (decision) {
159
+ decision.status = "human-decided";
160
+ decision.humanChosen = event.chosen;
161
+ decision.humanReason = event.reason;
162
+ continue;
163
+ }
164
+ const finding = findingsById.get(event.id);
165
+ if (finding) {
166
+ finding.status = "human-decided";
167
+ finding.humanChosen = event.chosen;
168
+ finding.humanReason = event.reason;
169
+ }
170
+ continue;
71
171
  }
172
+ // A genuinely unknown or future event kind is ignored, never
173
+ // mis-handled — reads stay fail-open regardless of what a hand-edited
174
+ // or newer ledger presents.
72
175
  }
73
- return { decisions: [...byId.values()], corrupt: 0 };
176
+ return {
177
+ decisions: [...decisionsById.values()],
178
+ findings: [...findingsById.values()],
179
+ corrupt: 0,
180
+ };
74
181
  }
75
182
  /**
76
183
  * Read and reduce the journal. Fail-open: a missing file is an empty ledger,
@@ -83,7 +190,7 @@ export async function readDecisionLedger(root, programId) {
83
190
  raw = await readFile(ledgerPath(root, programId), "utf8");
84
191
  }
85
192
  catch {
86
- return { decisions: [], corrupt: 0 };
193
+ return { decisions: [], findings: [], corrupt: 0 };
87
194
  }
88
195
  const events = [];
89
196
  let corrupt = 0;