@wildorder/nightshift 0.8.0 → 0.9.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/dist/as-built.d.ts +125 -0
- package/dist/as-built.d.ts.map +1 -0
- package/dist/as-built.js +322 -0
- package/dist/as-built.js.map +1 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +2 -2
- package/dist/run-program.d.ts +66 -2
- package/dist/run-program.d.ts.map +1 -1
- package/dist/run-program.js +322 -35
- package/dist/run-program.js.map +1 -1
- package/dist/whole-program-review.d.ts +165 -0
- package/dist/whole-program-review.d.ts.map +1 -0
- package/dist/whole-program-review.js +580 -0
- package/dist/whole-program-review.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { invokeAgent, resolveReviewerAgent, tail, } from "./agent-runner.js";
|
|
4
|
+
import { resolveSummary, summaryContract } from "./agent-summary.js";
|
|
5
|
+
import { because, countBySeverity, measured, } from "./findings.js";
|
|
6
|
+
import { extractFindings, findingsContract, locateInRepo, verifyEvidence, } from "./review-pass.js";
|
|
7
|
+
/**
|
|
8
|
+
* The production `AsBuiltFs`, backed by `node:fs/promises`. Exported so its
|
|
9
|
+
* error-discrimination contract — `undefined` only for a confirmed
|
|
10
|
+
* not-found, every other errno rethrown — can be tested directly against a
|
|
11
|
+
* real filesystem rather than only through the in-memory fake the rest of
|
|
12
|
+
* this suite injects.
|
|
13
|
+
*/
|
|
14
|
+
export const realAsBuiltFs = {
|
|
15
|
+
async readFile(path) {
|
|
16
|
+
try {
|
|
17
|
+
return await readFile(path, "utf8");
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
const code = error.code;
|
|
21
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
22
|
+
return undefined;
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
async writeFile(path, content) {
|
|
27
|
+
await writeFile(path, content, "utf8");
|
|
28
|
+
},
|
|
29
|
+
async mkdir(path) {
|
|
30
|
+
await mkdir(path, { recursive: true });
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export const AS_BUILT_PATH = "docs/as-built.md";
|
|
34
|
+
/**
|
|
35
|
+
* A constant, never a config key — the charter keeps tuning knobs off the
|
|
36
|
+
* config surface. Aim is 200-300 lines; a curated index, not a code dump.
|
|
37
|
+
*/
|
|
38
|
+
export const AS_BUILT_LINE_BOUND = 300;
|
|
39
|
+
/**
|
|
40
|
+
* The program id reaches this module from a manifest file on disk, and a
|
|
41
|
+
* value containing `/`, `\`, or `..` would place the archive outside
|
|
42
|
+
* `docs/snapshots/`. Ids are lowercase kebab-case by convention, so this is
|
|
43
|
+
* a no-op in practice and a guard in principle.
|
|
44
|
+
*/
|
|
45
|
+
export function asBuiltArchivePath(programId) {
|
|
46
|
+
const sanitized = programId
|
|
47
|
+
.replace(/[^A-Za-z0-9._-]/gu, "-")
|
|
48
|
+
.replace(/^\.+/u, "-");
|
|
49
|
+
return `docs/snapshots/as-built-${sanitized}.md`;
|
|
50
|
+
}
|
|
51
|
+
function emptySeverityCounts() {
|
|
52
|
+
return countBySeverity([]);
|
|
53
|
+
}
|
|
54
|
+
/** The pass a caller records when no reviewerAgent is configured. */
|
|
55
|
+
export function reviewerAbsentReview() {
|
|
56
|
+
return {
|
|
57
|
+
ran: false,
|
|
58
|
+
status: "no-reviewer",
|
|
59
|
+
refreshed: false,
|
|
60
|
+
writtenPaths: [],
|
|
61
|
+
findings: [],
|
|
62
|
+
errors: [],
|
|
63
|
+
severityCounts: emptySeverityCounts(),
|
|
64
|
+
lengthOverrun: false,
|
|
65
|
+
missingLimitations: [],
|
|
66
|
+
inputClipped: false,
|
|
67
|
+
reason: "whole-program review is disabled — no reviewerAgent is configured, " +
|
|
68
|
+
"and the pass was not substituted with the implementer or skipped silently.",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function reviewerErrorOutcome(reason, inputClipped, note) {
|
|
72
|
+
return {
|
|
73
|
+
ran: false,
|
|
74
|
+
status: "reviewer-error",
|
|
75
|
+
refreshed: false,
|
|
76
|
+
writtenPaths: [],
|
|
77
|
+
findings: [],
|
|
78
|
+
errors: [],
|
|
79
|
+
severityCounts: emptySeverityCounts(),
|
|
80
|
+
lengthOverrun: false,
|
|
81
|
+
missingLimitations: [],
|
|
82
|
+
inputClipped,
|
|
83
|
+
reason,
|
|
84
|
+
...(note !== undefined ? { note } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Reproduces run-program.ts's TEST_CRITIQUE_DIFF_LIMIT / clipForReview
|
|
88
|
+
// locally: this pass clips its diff and prior-snapshot inputs "by the same
|
|
89
|
+
// rule test critique uses", but cannot import run-program.ts (which will
|
|
90
|
+
// import this module) and the constant is not exported there.
|
|
91
|
+
const WHOLE_PROGRAM_REVIEW_CLIP_LIMIT = 60_000;
|
|
92
|
+
function clipForReview(text, label) {
|
|
93
|
+
if (text.length <= WHOLE_PROGRAM_REVIEW_CLIP_LIMIT)
|
|
94
|
+
return { text, clipped: false };
|
|
95
|
+
return {
|
|
96
|
+
text: `${text.slice(0, WHOLE_PROGRAM_REVIEW_CLIP_LIMIT)}\n… (${label} clipped at ` +
|
|
97
|
+
`${WHOLE_PROGRAM_REVIEW_CLIP_LIMIT} characters — the reviewer saw a partial ${label})`,
|
|
98
|
+
clipped: true,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/** Presence of at least one fenced findings block — a private duplicate of
|
|
102
|
+
* the same-named helper in author.ts/run-program.ts; hoisting it would mean
|
|
103
|
+
* editing files this workstream does not own. */
|
|
104
|
+
function hasFindingsBlock(output) {
|
|
105
|
+
return /```findings/u.test(output);
|
|
106
|
+
}
|
|
107
|
+
const SNAPSHOT_BEGIN_MARKER = "<!-- as-built:begin -->";
|
|
108
|
+
const SNAPSHOT_END_MARKER = "<!-- as-built:end -->";
|
|
109
|
+
const SNAPSHOT_PATTERN = /<!-- as-built:begin -->\r?\n?([\s\S]*?)<!-- as-built:end -->/gu;
|
|
110
|
+
const SNAPSHOT_PLACEHOLDER_BODY = "# As-Built Snapshot — <project name>\n…the whole document…";
|
|
111
|
+
function isUsableSnapshotBody(body) {
|
|
112
|
+
const trimmed = body.trim();
|
|
113
|
+
if (trimmed === "")
|
|
114
|
+
return false;
|
|
115
|
+
if (!/^#{1,6}\s/mu.test(trimmed))
|
|
116
|
+
return false;
|
|
117
|
+
if (trimmed === SNAPSHOT_PLACEHOLDER_BODY)
|
|
118
|
+
return false;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Three-state parse: `absent` (no complete marker pair at all), the "read
|
|
123
|
+
* the contract, answered it badly" case `present-unusable` (a pair exists
|
|
124
|
+
* but its body fails the usability bar), and `usable`. The last usable pair
|
|
125
|
+
* wins — a reviewer that echoes the contract back before answering would
|
|
126
|
+
* otherwise have its echo parsed as the answer.
|
|
127
|
+
*/
|
|
128
|
+
function parseSnapshotHalf(output) {
|
|
129
|
+
const pairs = [...output.matchAll(SNAPSHOT_PATTERN)].map((match) => match[1] ?? "");
|
|
130
|
+
if (pairs.length === 0)
|
|
131
|
+
return { kind: "absent" };
|
|
132
|
+
const usablePairs = pairs.filter(isUsableSnapshotBody);
|
|
133
|
+
if (usablePairs.length > 0) {
|
|
134
|
+
const last = usablePairs[usablePairs.length - 1] ?? "";
|
|
135
|
+
return { kind: "usable", document: last.trim() };
|
|
136
|
+
}
|
|
137
|
+
const lastPair = pairs[pairs.length - 1] ?? "";
|
|
138
|
+
return { kind: "present-unusable", body: lastPair.trim() };
|
|
139
|
+
}
|
|
140
|
+
function countLines(text) {
|
|
141
|
+
const withoutTrailingNewline = text.replace(/\n$/u, "");
|
|
142
|
+
if (withoutTrailingNewline === "")
|
|
143
|
+
return 0;
|
|
144
|
+
return withoutTrailingNewline.split(/\r?\n/u).length;
|
|
145
|
+
}
|
|
146
|
+
function normalizeForMention(text) {
|
|
147
|
+
return text.replace(/\s+/gu, " ").trim().toLowerCase();
|
|
148
|
+
}
|
|
149
|
+
function auditNotBuilt(document, notBuilt) {
|
|
150
|
+
const normalizedDoc = normalizeForMention(document);
|
|
151
|
+
const missing = [];
|
|
152
|
+
const mentioned = [];
|
|
153
|
+
for (const workstream of notBuilt) {
|
|
154
|
+
const mentionsId = normalizedDoc.includes(normalizeForMention(workstream.id));
|
|
155
|
+
const mentionsName = normalizedDoc.includes(normalizeForMention(workstream.name));
|
|
156
|
+
if (mentionsId || mentionsName)
|
|
157
|
+
mentioned.push(workstream.id);
|
|
158
|
+
else
|
|
159
|
+
missing.push(workstream.id);
|
|
160
|
+
}
|
|
161
|
+
return { missing, mentioned };
|
|
162
|
+
}
|
|
163
|
+
function rosterLines(manifest) {
|
|
164
|
+
return manifest.workstreams
|
|
165
|
+
.map((entry) => `- ${entry.id} ${entry.name}: ${entry.scope?.summary ?? entry.name}`)
|
|
166
|
+
.join("\n");
|
|
167
|
+
}
|
|
168
|
+
function successCriteriaLines(manifest) {
|
|
169
|
+
if (manifest.successCriteria.length === 0) {
|
|
170
|
+
return "None recorded in the manifest.";
|
|
171
|
+
}
|
|
172
|
+
return manifest.successCriteria
|
|
173
|
+
.map((criterion) => `- **${criterion.id}**: ${criterion.description}`)
|
|
174
|
+
.join("\n");
|
|
175
|
+
}
|
|
176
|
+
function notBuiltBriefSection(notBuilt) {
|
|
177
|
+
if (notBuilt.length === 0) {
|
|
178
|
+
return ["## What was not built", "", "Every workstream in this program completed.", ""];
|
|
179
|
+
}
|
|
180
|
+
return [
|
|
181
|
+
"## What was not built",
|
|
182
|
+
"",
|
|
183
|
+
"The following workstreams did not complete this run. Record each one",
|
|
184
|
+
"under known limitations in the regenerated snapshot; do not describe",
|
|
185
|
+
"any of them as built:",
|
|
186
|
+
"",
|
|
187
|
+
...notBuilt.map((workstream) => `- **${workstream.id}** ${workstream.name} — ${workstream.status}: ${workstream.reason}`),
|
|
188
|
+
"",
|
|
189
|
+
"The runner checks the document you return for each id above and",
|
|
190
|
+
"reports any it cannot find. This is not a threat — nothing here can",
|
|
191
|
+
"fail this pass or gate anything — but it is why writing the ids down",
|
|
192
|
+
"matters more than paraphrasing around them.",
|
|
193
|
+
"",
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The reviewer's brief: what this program set out to do, what was not
|
|
198
|
+
* built, the prior snapshot, the program diff, grounding instructions, and
|
|
199
|
+
* the two-part output contract. Exported so tests assert on its content and
|
|
200
|
+
* a caller may log its byte size.
|
|
201
|
+
*/
|
|
202
|
+
export function wholeProgramReviewBrief(input) {
|
|
203
|
+
const { manifest, programId, diff, baseCommit, previous, notBuilt } = input;
|
|
204
|
+
return [
|
|
205
|
+
`# Whole-program review: ${manifest.program.name} (${programId})`,
|
|
206
|
+
"",
|
|
207
|
+
"The run for this program is finished. You are the independent read of",
|
|
208
|
+
"the whole program as it stands now — not a diff, not one workstream,",
|
|
209
|
+
"the repository. Your job is to regenerate `docs/as-built.md`: a",
|
|
210
|
+
"current, curated index of what this repository actually is.",
|
|
211
|
+
"",
|
|
212
|
+
"## Why this document matters",
|
|
213
|
+
"",
|
|
214
|
+
"`docs/as-built.md` is a `contextDoc`: every agent this project spawns",
|
|
215
|
+
"— author, implementer, reviewer, decider — is briefed with it. An",
|
|
216
|
+
"error here misleads every future agent. Prefer omitting a subsystem",
|
|
217
|
+
"entirely to describing one wrongly.",
|
|
218
|
+
"",
|
|
219
|
+
"## Success criteria",
|
|
220
|
+
"",
|
|
221
|
+
successCriteriaLines(manifest),
|
|
222
|
+
"",
|
|
223
|
+
"## Workstream roster",
|
|
224
|
+
"",
|
|
225
|
+
rosterLines(manifest),
|
|
226
|
+
"",
|
|
227
|
+
...notBuiltBriefSection(notBuilt),
|
|
228
|
+
"## The prior snapshot",
|
|
229
|
+
"",
|
|
230
|
+
"This is what the document said before this run. It may be stale.",
|
|
231
|
+
"This is orientation only — do not patch it, replace it: regenerate",
|
|
232
|
+
"wholesale from the repository as it stands now.",
|
|
233
|
+
"",
|
|
234
|
+
previous === undefined ? "(no prior snapshot)" : previous,
|
|
235
|
+
"",
|
|
236
|
+
"## The program diff",
|
|
237
|
+
"",
|
|
238
|
+
baseCommit ? `Base commit: ${baseCommit}` : "(no base commit)",
|
|
239
|
+
"",
|
|
240
|
+
"```diff",
|
|
241
|
+
diff.trim() === "" ? "(no diff available)" : diff,
|
|
242
|
+
"```",
|
|
243
|
+
"",
|
|
244
|
+
"## How to ground the catalogue",
|
|
245
|
+
"",
|
|
246
|
+
"- Start at the entry points: `src/cli.ts` (the command surface),",
|
|
247
|
+
" `src/index.ts` (the barrel — what this package exports), and the",
|
|
248
|
+
" modules those reach.",
|
|
249
|
+
"- Read schema-shaped files for the data model: the Zod schemas in",
|
|
250
|
+
" `src/config.ts`, `src/manifest.ts`, `src/decision-ledger.ts`.",
|
|
251
|
+
"- Trust the repository over the plan. The diff tells you what",
|
|
252
|
+
" changed; the files tell you what exists. Where a program document",
|
|
253
|
+
" and the code disagree, the code is what is as-built.",
|
|
254
|
+
"- Do not attempt the whole tree, and do not paste code. This is a",
|
|
255
|
+
" curated index a human reads to orient, not a generated API dump.",
|
|
256
|
+
"- Regenerate wholesale. Do not diff against the prior version and do",
|
|
257
|
+
" not patch it — a document maintained by successive patches from",
|
|
258
|
+
" different agents converges on nobody's structure.",
|
|
259
|
+
`- Aim for 200-300 lines; over ${AS_BUILT_LINE_BOUND} lines is reported`,
|
|
260
|
+
" as an overrun, but the document is written and kept either way.",
|
|
261
|
+
"",
|
|
262
|
+
"## What to raise as findings",
|
|
263
|
+
"",
|
|
264
|
+
"A whole-program read notices things: drift between documentation and",
|
|
265
|
+
"code, a module nothing imports, a pattern applied inconsistently",
|
|
266
|
+
"across modules, a public surface with no test. Those are findings.",
|
|
267
|
+
"This review has no teeth: the run is already over, and nothing here",
|
|
268
|
+
"can fail a workstream, stop anything, or block a publish. Severity is",
|
|
269
|
+
"a routing hint for where a finding goes, never a verdict.",
|
|
270
|
+
"",
|
|
271
|
+
"An empty findings array is a fine answer. Always end your reply with",
|
|
272
|
+
"a findings block, using an empty array `[]` when you have no",
|
|
273
|
+
"objection, so a clean read and a skipped read stay distinguishable.",
|
|
274
|
+
"",
|
|
275
|
+
"## Rules",
|
|
276
|
+
"",
|
|
277
|
+
"- Never commit — the runner owns commits.",
|
|
278
|
+
"- Never write or edit any file, including `docs/as-built.md` itself:",
|
|
279
|
+
" return the document in your reply and the runner writes it.",
|
|
280
|
+
"- Read freely; the repository is the source.",
|
|
281
|
+
"",
|
|
282
|
+
"## The snapshot contract",
|
|
283
|
+
"",
|
|
284
|
+
"Return the regenerated document between these exact markers, each on",
|
|
285
|
+
"its own line:",
|
|
286
|
+
"",
|
|
287
|
+
SNAPSHOT_BEGIN_MARKER,
|
|
288
|
+
SNAPSHOT_PLACEHOLDER_BODY,
|
|
289
|
+
SNAPSHOT_END_MARKER,
|
|
290
|
+
"",
|
|
291
|
+
"The block above is a placeholder, not a real snapshot — every line is",
|
|
292
|
+
"an example, and echoing it back verbatim produces no snapshot at all.",
|
|
293
|
+
"",
|
|
294
|
+
findingsContract(),
|
|
295
|
+
"",
|
|
296
|
+
summaryContract(),
|
|
297
|
+
].join("\n");
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A human-facing render of one completed (or absent) whole-program review,
|
|
301
|
+
* for the run report. Markdown lines, no heading — the caller splices them
|
|
302
|
+
* under its own section heading.
|
|
303
|
+
*/
|
|
304
|
+
export function renderWholeProgramReview(outcome) {
|
|
305
|
+
const lines = [];
|
|
306
|
+
if (outcome.status === "no-reviewer") {
|
|
307
|
+
return [
|
|
308
|
+
"**Whole-program review:** disabled — no reviewer is configured, and",
|
|
309
|
+
"the pass was not substituted with the implementer or skipped silently.",
|
|
310
|
+
outcome.reason ?? "",
|
|
311
|
+
];
|
|
312
|
+
}
|
|
313
|
+
if (outcome.status === "snapshot-unreadable") {
|
|
314
|
+
return [
|
|
315
|
+
`**Whole-program review:** ${AS_BUILT_PATH} could not be read, so the`,
|
|
316
|
+
"pass invoked no reviewer and wrote nothing rather than risk",
|
|
317
|
+
"overwriting it unarchived.",
|
|
318
|
+
outcome.reason ?? "",
|
|
319
|
+
];
|
|
320
|
+
}
|
|
321
|
+
if (outcome.status === "reviewer-error" ||
|
|
322
|
+
outcome.status === "no-snapshot" ||
|
|
323
|
+
outcome.status === "write-failed") {
|
|
324
|
+
lines.push("**Whole-program review:** the snapshot was **not** refreshed.");
|
|
325
|
+
lines.push(outcome.reason ?? "");
|
|
326
|
+
}
|
|
327
|
+
else if (outcome.status === "unchanged") {
|
|
328
|
+
lines.push("**Whole-program review:** the reviewer read the program and produced", "a snapshot identical to the one on disk, so nothing was written.");
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
lines.push(outcome.archivedTo
|
|
332
|
+
? `**Whole-program review:** refreshed. The prior snapshot was archived to \`${outcome.archivedTo}\`.`
|
|
333
|
+
: "**Whole-program review:** refreshed. There was no prior snapshot to archive.");
|
|
334
|
+
if (outcome.snapshotLines !== undefined) {
|
|
335
|
+
lines.push(`The regenerated snapshot is ${outcome.snapshotLines} lines` +
|
|
336
|
+
(outcome.lengthOverrun
|
|
337
|
+
? `, over the ${AS_BUILT_LINE_BOUND}-line curated-index bound.`
|
|
338
|
+
: "."));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if ((outcome.status === "refreshed" || outcome.status === "unchanged") &&
|
|
342
|
+
outcome.missingLimitations.length > 0) {
|
|
343
|
+
lines.push(`The snapshot never mentions these known limitations: ${outcome.missingLimitations.join(", ")}.`);
|
|
344
|
+
}
|
|
345
|
+
const counts = outcome.severityCounts;
|
|
346
|
+
const totalFindings = counts.blocker + counts.major + counts.minor + counts.advisory;
|
|
347
|
+
if (totalFindings > 0) {
|
|
348
|
+
lines.push(`Findings raised: ${counts.blocker} blocker, ${counts.major} major, ${counts.minor} minor, ${counts.advisory} advisory.`);
|
|
349
|
+
lines.push(`Subjects: ${outcome.findings.map((finding) => finding.subject).join(", ")}.`);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
lines.push("No findings raised.");
|
|
353
|
+
}
|
|
354
|
+
if (outcome.errors.length > 0) {
|
|
355
|
+
lines.push(`Parse errors: ${outcome.errors.join("; ")}`);
|
|
356
|
+
}
|
|
357
|
+
if (outcome.inputClipped) {
|
|
358
|
+
lines.push("Input was clipped for length before the reviewer saw it.");
|
|
359
|
+
}
|
|
360
|
+
if (outcome.note !== undefined) {
|
|
361
|
+
lines.push(`Reviewer's note: ${outcome.note}`);
|
|
362
|
+
}
|
|
363
|
+
return lines;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Runs the pass once. Never throws — every failure becomes a status and a
|
|
367
|
+
* `reason` sentence on the returned outcome.
|
|
368
|
+
*/
|
|
369
|
+
export async function runWholeProgramReview(options) {
|
|
370
|
+
const reviewerAgent = resolveReviewerAgent(options.config);
|
|
371
|
+
if (!reviewerAgent)
|
|
372
|
+
return reviewerAbsentReview();
|
|
373
|
+
const fs = options.fs ?? realAsBuiltFs;
|
|
374
|
+
const root = options.root;
|
|
375
|
+
const notBuilt = options.notBuilt ?? [];
|
|
376
|
+
const log = options.log ?? ((_line) => { });
|
|
377
|
+
let previous;
|
|
378
|
+
try {
|
|
379
|
+
previous = await fs.readFile(join(root, AS_BUILT_PATH));
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
return {
|
|
383
|
+
ran: false,
|
|
384
|
+
status: "snapshot-unreadable",
|
|
385
|
+
refreshed: false,
|
|
386
|
+
writtenPaths: [],
|
|
387
|
+
findings: [],
|
|
388
|
+
errors: [],
|
|
389
|
+
severityCounts: emptySeverityCounts(),
|
|
390
|
+
lengthOverrun: false,
|
|
391
|
+
missingLimitations: [],
|
|
392
|
+
inputClipped: false,
|
|
393
|
+
reason: `${AS_BUILT_PATH} exists but could not be read (${error.message}); ` +
|
|
394
|
+
"the pass therefore invoked no reviewer and wrote nothing, because it could " +
|
|
395
|
+
"not guarantee the archive this pass requires before overwriting it.",
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const diffClip = clipForReview(options.diff, "diff");
|
|
399
|
+
const previousClip = previous === undefined ? undefined : clipForReview(previous, "prior snapshot");
|
|
400
|
+
const inputClipped = diffClip.clipped || (previousClip?.clipped ?? false);
|
|
401
|
+
const brief = wholeProgramReviewBrief({
|
|
402
|
+
manifest: options.manifest,
|
|
403
|
+
programId: options.programId,
|
|
404
|
+
diff: diffClip.text,
|
|
405
|
+
...(options.baseCommit === undefined ? {} : { baseCommit: options.baseCommit }),
|
|
406
|
+
...(previousClip === undefined ? {} : { previous: previousClip.text }),
|
|
407
|
+
notBuilt,
|
|
408
|
+
});
|
|
409
|
+
log(`whole-program review: briefing reviewer (${brief.length} bytes)`);
|
|
410
|
+
let invocation;
|
|
411
|
+
try {
|
|
412
|
+
invocation = await invokeAgent(options.agentRunner, reviewerAgent, brief, root);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
return reviewerErrorOutcome(`the reviewer invocation threw: ${error.message}`, inputClipped);
|
|
416
|
+
}
|
|
417
|
+
const summary = resolveSummary(invocation.output);
|
|
418
|
+
if (invocation.exitCode !== 0) {
|
|
419
|
+
return reviewerErrorOutcome(`the reviewer exited with code ${invocation.exitCode}: ${tail(invocation.output)}`, inputClipped, summary.text);
|
|
420
|
+
}
|
|
421
|
+
const snapshotHalf = parseSnapshotHalf(invocation.output);
|
|
422
|
+
const findingsPresent = hasFindingsBlock(invocation.output);
|
|
423
|
+
if (snapshotHalf.kind === "absent" && !findingsPresent) {
|
|
424
|
+
return reviewerErrorOutcome(`the reviewer's reply carried neither a snapshot document nor a findings ` +
|
|
425
|
+
`block: ${tail(invocation.output)}`, inputClipped, summary.text);
|
|
426
|
+
}
|
|
427
|
+
const parsedFindings = extractFindings(invocation.output);
|
|
428
|
+
const verifiedFindings = verifyEvidence(parsedFindings.findings, (file) => locateInRepo(root, file));
|
|
429
|
+
if (snapshotHalf.kind === "absent") {
|
|
430
|
+
return {
|
|
431
|
+
ran: true,
|
|
432
|
+
status: "no-snapshot",
|
|
433
|
+
refreshed: false,
|
|
434
|
+
writtenPaths: [],
|
|
435
|
+
findings: verifiedFindings,
|
|
436
|
+
errors: parsedFindings.errors,
|
|
437
|
+
severityCounts: countBySeverity(verifiedFindings),
|
|
438
|
+
lengthOverrun: false,
|
|
439
|
+
missingLimitations: [],
|
|
440
|
+
inputClipped,
|
|
441
|
+
reason: "the reply carried findings but no snapshot document",
|
|
442
|
+
note: summary.text,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (snapshotHalf.kind === "present-unusable") {
|
|
446
|
+
return {
|
|
447
|
+
ran: true,
|
|
448
|
+
status: "no-snapshot",
|
|
449
|
+
refreshed: false,
|
|
450
|
+
writtenPaths: [],
|
|
451
|
+
findings: verifiedFindings,
|
|
452
|
+
errors: parsedFindings.errors,
|
|
453
|
+
severityCounts: countBySeverity(verifiedFindings),
|
|
454
|
+
lengthOverrun: false,
|
|
455
|
+
missingLimitations: [],
|
|
456
|
+
inputClipped,
|
|
457
|
+
reason: "the snapshot markers came back holding no usable document: " +
|
|
458
|
+
tail(snapshotHalf.body),
|
|
459
|
+
note: summary.text,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
const normalized = snapshotHalf.document.trimEnd() + "\n";
|
|
463
|
+
const snapshotLines = countLines(normalized);
|
|
464
|
+
let lengthOverrun = false;
|
|
465
|
+
const outputFindings = [...verifiedFindings];
|
|
466
|
+
if (snapshotLines > AS_BUILT_LINE_BOUND) {
|
|
467
|
+
lengthOverrun = true;
|
|
468
|
+
outputFindings.push({
|
|
469
|
+
severity: "advisory",
|
|
470
|
+
category: "scope-structure",
|
|
471
|
+
code: "as-built-length",
|
|
472
|
+
subject: "As-built snapshot length",
|
|
473
|
+
message: `The regenerated snapshot is ${snapshotLines} lines, over the ` +
|
|
474
|
+
`${AS_BUILT_LINE_BOUND}-line curated-index bound. It was written anyway; ` +
|
|
475
|
+
"consider tightening it on the next pass.",
|
|
476
|
+
evidence: [measured("lineCount", snapshotLines)],
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
const audit = auditNotBuilt(normalized, notBuilt);
|
|
480
|
+
if (audit.missing.length > 0) {
|
|
481
|
+
outputFindings.push({
|
|
482
|
+
severity: "advisory",
|
|
483
|
+
category: "acceptance-criteria",
|
|
484
|
+
code: "as-built-missing-limitation",
|
|
485
|
+
subject: "As-built known limitations",
|
|
486
|
+
message: `The regenerated snapshot never mentions ${audit.missing.length} workstream(s) ` +
|
|
487
|
+
`reported as not built: ${audit.missing.join(", ")}. The reviewer was given each ` +
|
|
488
|
+
"id, status, and reason and asked to record them as known limitations. Nothing " +
|
|
489
|
+
"was withheld over it; a reader should treat the snapshot's coverage of what is " +
|
|
490
|
+
"missing as incomplete.",
|
|
491
|
+
evidence: [
|
|
492
|
+
because("not-built workstreams absent from the snapshot", audit.missing.join(", ")),
|
|
493
|
+
],
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
if (previous !== undefined && normalized === previous) {
|
|
497
|
+
return {
|
|
498
|
+
ran: true,
|
|
499
|
+
status: "unchanged",
|
|
500
|
+
refreshed: false,
|
|
501
|
+
writtenPaths: [],
|
|
502
|
+
findings: outputFindings,
|
|
503
|
+
errors: parsedFindings.errors,
|
|
504
|
+
severityCounts: countBySeverity(outputFindings),
|
|
505
|
+
snapshotLines,
|
|
506
|
+
lengthOverrun,
|
|
507
|
+
missingLimitations: audit.missing,
|
|
508
|
+
inputClipped,
|
|
509
|
+
reason: "the regenerated snapshot was identical to the one on disk, so nothing was written",
|
|
510
|
+
note: summary.text,
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
const writtenPaths = [];
|
|
514
|
+
let archivedTo;
|
|
515
|
+
if (previous !== undefined) {
|
|
516
|
+
const archivePath = asBuiltArchivePath(options.programId);
|
|
517
|
+
try {
|
|
518
|
+
await fs.mkdir(dirname(join(root, archivePath)));
|
|
519
|
+
await fs.writeFile(join(root, archivePath), previous);
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
return {
|
|
523
|
+
ran: true,
|
|
524
|
+
status: "write-failed",
|
|
525
|
+
refreshed: false,
|
|
526
|
+
writtenPaths,
|
|
527
|
+
findings: outputFindings,
|
|
528
|
+
errors: parsedFindings.errors,
|
|
529
|
+
severityCounts: countBySeverity(outputFindings),
|
|
530
|
+
snapshotLines,
|
|
531
|
+
lengthOverrun,
|
|
532
|
+
missingLimitations: audit.missing,
|
|
533
|
+
inputClipped,
|
|
534
|
+
reason: `archiving the prior as-built snapshot failed: ${error.message}`,
|
|
535
|
+
note: summary.text,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
writtenPaths.push(archivePath);
|
|
539
|
+
archivedTo = archivePath;
|
|
540
|
+
}
|
|
541
|
+
try {
|
|
542
|
+
await fs.mkdir(dirname(join(root, AS_BUILT_PATH)));
|
|
543
|
+
await fs.writeFile(join(root, AS_BUILT_PATH), normalized);
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
return {
|
|
547
|
+
ran: true,
|
|
548
|
+
status: "write-failed",
|
|
549
|
+
refreshed: false,
|
|
550
|
+
writtenPaths,
|
|
551
|
+
findings: outputFindings,
|
|
552
|
+
errors: parsedFindings.errors,
|
|
553
|
+
severityCounts: countBySeverity(outputFindings),
|
|
554
|
+
snapshotLines,
|
|
555
|
+
lengthOverrun,
|
|
556
|
+
missingLimitations: audit.missing,
|
|
557
|
+
inputClipped,
|
|
558
|
+
reason: `writing the as-built snapshot failed: ${error.message}`,
|
|
559
|
+
...(archivedTo === undefined ? {} : { archivedTo }),
|
|
560
|
+
note: summary.text,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
writtenPaths.push(AS_BUILT_PATH);
|
|
564
|
+
return {
|
|
565
|
+
ran: true,
|
|
566
|
+
status: "refreshed",
|
|
567
|
+
refreshed: true,
|
|
568
|
+
writtenPaths,
|
|
569
|
+
...(archivedTo === undefined ? {} : { archivedTo }),
|
|
570
|
+
findings: outputFindings,
|
|
571
|
+
errors: parsedFindings.errors,
|
|
572
|
+
severityCounts: countBySeverity(outputFindings),
|
|
573
|
+
snapshotLines,
|
|
574
|
+
lengthOverrun,
|
|
575
|
+
missingLimitations: audit.missing,
|
|
576
|
+
inputClipped,
|
|
577
|
+
note: summary.text,
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
//# sourceMappingURL=whole-program-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whole-program-review.js","sourceRoot":"","sources":["../src/whole-program-review.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wildorder/nightshift",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "The crew that builds while you're gone: walk-away, CI-dispatched engineering programs with a decision ledger instead of gates",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@eslint/js": "^10.0.1",
|
|
59
59
|
"@types/node": "^26.1.2",
|
|
60
|
-
"@wildorder/nightshift": "^0.
|
|
60
|
+
"@wildorder/nightshift": "^0.8.0",
|
|
61
61
|
"eslint": "^10.8.0",
|
|
62
62
|
"typescript": "^6.0.3",
|
|
63
63
|
"typescript-eslint": "^8.66.0",
|