@am_shork/attest 0.2.1 → 0.3.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +655 -79
  2. package/README.md +132 -18
  3. package/dist/cli/index.js +91 -21
  4. package/dist/cli/index.js.map +1 -1
  5. package/dist/cli/json.d.ts +52 -5
  6. package/dist/cli/json.d.ts.map +1 -1
  7. package/dist/cli/json.js +50 -2
  8. package/dist/cli/json.js.map +1 -1
  9. package/dist/cli/report.d.ts +28 -1
  10. package/dist/cli/report.d.ts.map +1 -1
  11. package/dist/cli/report.js +100 -1
  12. package/dist/cli/report.js.map +1 -1
  13. package/dist/core/apply.d.ts +8 -0
  14. package/dist/core/apply.d.ts.map +1 -1
  15. package/dist/core/apply.js +10 -0
  16. package/dist/core/apply.js.map +1 -1
  17. package/dist/core/gate.d.ts +36 -10
  18. package/dist/core/gate.d.ts.map +1 -1
  19. package/dist/core/gate.js +59 -12
  20. package/dist/core/gate.js.map +1 -1
  21. package/dist/core/loader.d.ts +8 -0
  22. package/dist/core/loader.d.ts.map +1 -1
  23. package/dist/core/loader.js +1 -0
  24. package/dist/core/loader.js.map +1 -1
  25. package/dist/core/locate.d.ts +4 -0
  26. package/dist/core/locate.d.ts.map +1 -1
  27. package/dist/core/locate.js +8 -3
  28. package/dist/core/locate.js.map +1 -1
  29. package/dist/core/paths.d.ts +15 -0
  30. package/dist/core/paths.d.ts.map +1 -0
  31. package/dist/core/paths.js +36 -0
  32. package/dist/core/paths.js.map +1 -0
  33. package/dist/core/pipeline.d.ts +63 -2
  34. package/dist/core/pipeline.d.ts.map +1 -1
  35. package/dist/core/pipeline.js +190 -34
  36. package/dist/core/pipeline.js.map +1 -1
  37. package/dist/core/red-record.d.ts +50 -0
  38. package/dist/core/red-record.d.ts.map +1 -0
  39. package/dist/core/red-record.js +148 -0
  40. package/dist/core/red-record.js.map +1 -0
  41. package/dist/core/render.d.ts +1 -1
  42. package/dist/core/render.d.ts.map +1 -1
  43. package/dist/core/render.js +16 -2
  44. package/dist/core/render.js.map +1 -1
  45. package/dist/core/runner.d.ts.map +1 -1
  46. package/dist/core/runner.js +16 -6
  47. package/dist/core/runner.js.map +1 -1
  48. package/dist/core/skill.d.ts +23 -0
  49. package/dist/core/skill.d.ts.map +1 -0
  50. package/dist/core/skill.js +276 -0
  51. package/dist/core/skill.js.map +1 -0
  52. package/dist/core/static-registry.d.ts +28 -0
  53. package/dist/core/static-registry.d.ts.map +1 -1
  54. package/dist/core/static-registry.js +86 -25
  55. package/dist/core/static-registry.js.map +1 -1
  56. package/dist/core/status.d.ts +39 -0
  57. package/dist/core/status.d.ts.map +1 -0
  58. package/dist/core/status.js +64 -0
  59. package/dist/core/status.js.map +1 -0
  60. package/dist/core/targets.d.ts +52 -0
  61. package/dist/core/targets.d.ts.map +1 -0
  62. package/dist/core/targets.js +141 -0
  63. package/dist/core/targets.js.map +1 -0
  64. package/dist/core/types.d.ts +13 -0
  65. package/dist/core/types.d.ts.map +1 -1
  66. package/dist/core/types.js.map +1 -1
  67. package/dist/core/validator.d.ts +11 -0
  68. package/dist/core/validator.d.ts.map +1 -1
  69. package/dist/core/validator.js +28 -12
  70. package/dist/core/validator.js.map +1 -1
  71. package/dist/core/write.d.ts +2 -0
  72. package/dist/core/write.d.ts.map +1 -0
  73. package/dist/core/write.js +21 -0
  74. package/dist/core/write.js.map +1 -0
  75. package/dist/runtime.d.ts +9 -1
  76. package/dist/runtime.d.ts.map +1 -1
  77. package/dist/runtime.js +10 -2
  78. package/dist/runtime.js.map +1 -1
  79. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import type { ObligationState, StatusRow } from './status.js';
1
2
  import type { RenderTarget } from './render.js';
2
3
  import type { Issue } from './types.js';
3
4
  /**
@@ -44,8 +45,28 @@ export interface CoverageRow {
44
45
  covered: boolean;
45
46
  scenarioCount: number;
46
47
  }
47
- /** Coverage-only report (design §9: `attest cover`). */
48
- export declare function runCover(root: string, options?: ReadOptions): Promise<CoverageRow[]>;
48
+ export interface CoverResult {
49
+ /** One row per requirement, in id order. */
50
+ rows: CoverageRow[];
51
+ /**
52
+ * The same uncovered requirements as `uncovered: true` rows, in issue form —
53
+ * so `ok` derives from `hasError` like every other command, and a consumer
54
+ * told to read `issues[].code` is not handed an empty array by this one.
55
+ */
56
+ issues: Issue[];
57
+ }
58
+ /**
59
+ * Coverage-only report (design §9: `attest cover`).
60
+ *
61
+ * A registry that failed to load is reported, never coveraged. Discarding the
62
+ * load issues turned an unreadable registry into an empty one, and an empty
63
+ * registry is fully covered — so the command answered `ok: true` on exactly the
64
+ * repo whose intent layer had stopped being readable. Refusing here is the same
65
+ * call `runRender` makes for the same reason: a report computed from a
66
+ * half-loaded registry is a lie, and a lie that reads as a pass is the worst
67
+ * shape it can take.
68
+ */
69
+ export declare function runCover(root: string, options?: ReadOptions): Promise<CoverResult>;
49
70
  export interface RenderResult {
50
71
  /** The rendered document; empty string when `issues` contains an ERROR. */
51
72
  markdown: string;
@@ -69,6 +90,27 @@ export declare function runRender(root: string, options?: ReadOptions): Promise<
69
90
  * alongside a gate that fails when the file no longer matches its source.
70
91
  */
71
92
  export declare function runRenderCheck(root: string, outFile: string, target: RenderTarget, options?: ReadOptions): Promise<Issue[]>;
93
+ export { SKILL_FILE, skillContent, TARGETS, TARGET_NAMES, DEFAULT_TARGET } from './targets.js';
94
+ export type { AgentTarget } from './targets.js';
95
+ /**
96
+ * `attest init`: write the workflow document for each agent target asked for.
97
+ *
98
+ * Naming none means the default one, decided here rather than in the CLI: it is
99
+ * what `init` does, not how a flag parses, and the CLI is a shell over these.
100
+ *
101
+ * Nothing is written while any name is unresolvable. A partial write would
102
+ * leave the repo carrying instructions for some agents and a failing command
103
+ * with no way to tell which — and the whole reason this is safe to put in a
104
+ * script is that its effect is the same on every run.
105
+ *
106
+ * Each file is a pure function of nothing, so re-running after an upgrade is the
107
+ * entire update mechanism (design §9); the write is atomic because every file
108
+ * Attest writes is one the user commits.
109
+ */
110
+ export declare function runInit(root: string, names: readonly string[]): Promise<{
111
+ files: string[];
112
+ issues: Issue[];
113
+ }>;
72
114
  /**
73
115
  * The globs that keep *other* proposals out of a change's gate run.
74
116
  *
@@ -78,6 +120,25 @@ export declare function runRenderCheck(root: string, outFile: string, target: Re
78
120
  * widening the scope of the one check that decides "done".
79
121
  */
80
122
  export declare function changeExcludeGlobs(others: string[]): string[];
123
+ export interface StatusResult {
124
+ change: string;
125
+ /** One row per added id, in id order. */
126
+ rows: StatusRow[];
127
+ /** Roll-up of the rows by state. */
128
+ counts: Record<ObligationState, number>;
129
+ /**
130
+ * Only the reasons the report could not be computed — never progress.
131
+ *
132
+ * A change mid-flight has unmet obligations by definition; reporting those as
133
+ * issues would put them in `summary.error`, and the verdict every command
134
+ * derives from `hasError` would then make `status` exit 1 on the normal state
135
+ * of every change in progress. That is a second gate disagreeing with the
136
+ * first, which is what this command exists *not* to be.
137
+ */
138
+ issues: Issue[];
139
+ }
140
+ /** Per-change progress (design §9: `attest status <change>`). */
141
+ export declare function runStatus(root: string, changeName: string, options?: ReadOptions): Promise<StatusResult>;
81
142
  /** Archive gate for a change (design §8, §9: `attest archive <change>`). */
82
143
  export declare function runArchive(root: string, changeName: string, options?: RunOptions): Promise<Issue[]>;
83
144
  //# sourceMappingURL=pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,OAAO,KAAK,EAAc,KAAK,EAAY,MAAM,YAAY,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAoBD,2DAA2D;AAC3D,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CASxF;AAED,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;CACtB;AAeD,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CA6D7F;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAe9F;AAED,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAM9F;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,KAAK,EAAE,CAAC,CAOlB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE7D;AAMD,4EAA4E;AAC5E,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,KAAK,EAAE,CAAC,CAoElB"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
@@ -2,14 +2,20 @@
2
2
  // tool-agnostic; the CLI is a thin shell that calls them and renders the result.
3
3
  import { createLoader } from './loader.js';
4
4
  import { evalReader, loadRegistry, parseSpecs, parseChangeSpecs, listChangeNames, scanProject, staticReader, } from './locate.js';
5
- import { validateStructure, detectPotentialDrift } from './validator.js';
5
+ import { validateStructure, detectPotentialDrift, uncoveredIssues } from './validator.js';
6
6
  import { byCodeUnit } from './order.js';
7
7
  import { runAndCollect } from './runner.js';
8
- import { applyDelta } from './apply.js';
8
+ import { applyDelta, addedIds } from './apply.js';
9
+ import { readDeltaSource } from './static-registry.js';
10
+ import { statusRows, statusCounts } from './status.js';
9
11
  import { evaluateGate, declaredNotRunIssues } from './gate.js';
10
12
  import { renderMarkdown, staleIssue } from './render.js';
11
- import { readFile } from 'node:fs/promises';
12
- import { join, relative } from 'node:path';
13
+ import { mergeRedRecord, readRedRecord, redRecordPath, serialiseRedRecord, } from './red-record.js';
14
+ import { DEFAULT_TARGET, resolveTargets } from './targets.js';
15
+ import { writeAtomic } from './write.js';
16
+ import { mkdir, readFile } from 'node:fs/promises';
17
+ import { basename, dirname, join } from 'node:path';
18
+ import { relativePath } from './paths.js';
13
19
  import { configDefaults } from 'vitest/config';
14
20
  import { hasError } from './types.js';
15
21
  /**
@@ -94,7 +100,11 @@ export async function runVerify(root, options = {}) {
94
100
  // the child run keeps an incumbent suite untouched; the verdict comes from
95
101
  // empty-spec or uncovered-requirement, both already ERRORs above.
96
102
  const run = attesting.length === 0
97
- ? { passed: true, runtimeCoverage: new Map() }
103
+ ? {
104
+ passed: true,
105
+ runtimeCoverage: new Map(),
106
+ outcomes: new Map(),
107
+ }
98
108
  : await runAndCollect({
99
109
  root,
100
110
  quiet: true,
@@ -107,22 +117,35 @@ export async function runVerify(root, options = {}) {
107
117
  issues.push(...declaredNotRunIssues(plan, run));
108
118
  return { issues, passed: run.passed, ok: run.passed && !hasError(issues), counts };
109
119
  }
110
- /** Coverage-only report (design §9: `attest cover`). */
120
+ /**
121
+ * Coverage-only report (design §9: `attest cover`).
122
+ *
123
+ * A registry that failed to load is reported, never coveraged. Discarding the
124
+ * load issues turned an unreadable registry into an empty one, and an empty
125
+ * registry is fully covered — so the command answered `ok: true` on exactly the
126
+ * repo whose intent layer had stopped being readable. Refusing here is the same
127
+ * call `runRender` makes for the same reason: a report computed from a
128
+ * half-loaded registry is a lie, and a lie that reads as a pass is the worst
129
+ * shape it can take.
130
+ */
111
131
  export async function runCover(root, options = {}) {
112
132
  const scan = await scanProject(root);
113
- const { registry } = await readRegistry(root, options, scan.reqsFiles);
133
+ const { registry, issues: loadIssues } = await readRegistry(root, options, scan.reqsFiles);
134
+ if (hasError(loadIssues))
135
+ return { rows: [], issues: loadIssues };
114
136
  const plan = await parseSpecs(scan.specFiles, root);
115
137
  const counts = new Map();
116
138
  for (const s of plan.scenarios) {
117
139
  counts.set(s.reqId, (counts.get(s.reqId) ?? 0) + 1);
118
140
  }
119
- return Object.keys(registry)
141
+ const rows = Object.keys(registry)
120
142
  .sort()
121
143
  .map((reqId) => ({
122
144
  reqId,
123
145
  covered: (counts.get(reqId) ?? 0) > 0,
124
146
  scenarioCount: counts.get(reqId) ?? 0,
125
147
  }));
148
+ return { rows, issues: [...loadIssues, ...uncoveredIssues(registry, plan)] };
126
149
  }
127
150
  /**
128
151
  * Markdown projection of the intent layer (design §9: `attest render`).
@@ -155,6 +178,35 @@ export async function runRenderCheck(root, outFile, target, options = {}) {
155
178
  const stale = staleIssue(target, current, markdown);
156
179
  return stale ? [...issues, stale] : issues;
157
180
  }
181
+ export { SKILL_FILE, skillContent, TARGETS, TARGET_NAMES, DEFAULT_TARGET } from './targets.js';
182
+ /**
183
+ * `attest init`: write the workflow document for each agent target asked for.
184
+ *
185
+ * Naming none means the default one, decided here rather than in the CLI: it is
186
+ * what `init` does, not how a flag parses, and the CLI is a shell over these.
187
+ *
188
+ * Nothing is written while any name is unresolvable. A partial write would
189
+ * leave the repo carrying instructions for some agents and a failing command
190
+ * with no way to tell which — and the whole reason this is safe to put in a
191
+ * script is that its effect is the same on every run.
192
+ *
193
+ * Each file is a pure function of nothing, so re-running after an upgrade is the
194
+ * entire update mechanism (design §9); the write is atomic because every file
195
+ * Attest writes is one the user commits.
196
+ */
197
+ export async function runInit(root, names) {
198
+ const { targets, issues } = resolveTargets(names.length > 0 ? names : [DEFAULT_TARGET]);
199
+ if (issues.length > 0)
200
+ return { files: [], issues };
201
+ const files = [];
202
+ for (const target of targets) {
203
+ const dest = join(root, target.file);
204
+ await mkdir(dirname(dest), { recursive: true });
205
+ await writeAtomic(dest, target.content());
206
+ files.push(target.file);
207
+ }
208
+ return { files, issues };
209
+ }
158
210
  /**
159
211
  * A change name must name one directory inside `changes/`, and nothing else.
160
212
  *
@@ -191,51 +243,139 @@ export function changeExcludeGlobs(others) {
191
243
  function escapeGlob(name) {
192
244
  return name.replace(/[*?[\]{}()!+@|^$]/g, '\\$&');
193
245
  }
246
+ /** The delta a change is declared in (design §7). */
247
+ const CHANGE_DELTA_FILE = 'requirements.delta.ts';
248
+ function changeDeltaPath(root, changeName) {
249
+ return join(root, 'changes', changeName, CHANGE_DELTA_FILE);
250
+ }
251
+ /** The guard's refusal, as the issue every change-scoped command reports. */
252
+ function invalidChangeNameIssue(changeName) {
253
+ return {
254
+ level: 'ERROR',
255
+ code: 'invalid-change-name',
256
+ message: `Invalid change name ${JSON.stringify(changeName)}. A change name must be one directory inside changes/: it cannot be empty, "." or "..", or contain a path separator.`,
257
+ };
258
+ }
259
+ function changeNotFoundIssue(root, deltaPath, changeName, err) {
260
+ return {
261
+ level: 'ERROR',
262
+ code: 'change-not-found',
263
+ file: relativePath(root, deltaPath),
264
+ message: `Could not find or load the delta for change "${changeName}": ${err instanceof Error ? err.message : String(err)}`,
265
+ };
266
+ }
267
+ /**
268
+ * Read a change's delta the way `options` asks for, or the one issue that
269
+ * stopped it.
270
+ *
271
+ * The static path is the default for the same reason it is for `check`, `cover`
272
+ * and `render` (design §5.1): a command that only reports has no business
273
+ * executing a file out of `changes/`, where the content is by definition still
274
+ * under review. `archive` evaluates unconditionally because it runs the suite
275
+ * anyway, so declining to evaluate one more module would buy it nothing.
276
+ */
277
+ async function readDelta(root, changeName, options) {
278
+ const deltaPath = changeDeltaPath(root, changeName);
279
+ if (options.evaluate) {
280
+ const loader = await createLoader();
281
+ try {
282
+ const mod = await loader.load(deltaPath);
283
+ if (!mod.default || typeof mod.default !== 'object') {
284
+ return {
285
+ issue: changeNotFoundIssue(root, deltaPath, changeName, new Error(`${CHANGE_DELTA_FILE} must default-export the result of delta(...).`)),
286
+ };
287
+ }
288
+ return { delta: mod.default };
289
+ }
290
+ catch (err) {
291
+ return { issue: changeNotFoundIssue(root, deltaPath, changeName, err) };
292
+ }
293
+ finally {
294
+ await loader.close();
295
+ }
296
+ }
297
+ let source;
298
+ try {
299
+ source = await readFile(deltaPath, 'utf8');
300
+ }
301
+ catch (err) {
302
+ return { issue: changeNotFoundIssue(root, deltaPath, changeName, err) };
303
+ }
304
+ const read = readDeltaSource(basename(deltaPath), source);
305
+ if (read.ok)
306
+ return { delta: read.delta };
307
+ return {
308
+ issue: {
309
+ level: 'ERROR',
310
+ code: read.code,
311
+ file: relativePath(root, deltaPath),
312
+ message: read.message,
313
+ ...(read.line === undefined ? {} : { line: read.line }),
314
+ },
315
+ };
316
+ }
317
+ /**
318
+ * The static plan a change is gated and reported against: the base suite plus
319
+ * the change's own specs (design §8). Takes the spec files rather than finding
320
+ * them, so a caller that already scanned the tree does not walk it twice.
321
+ */
322
+ async function changeMergedPlan(root, changeName, specFiles) {
323
+ const basePlan = await parseSpecs(specFiles, root);
324
+ const changePlan = await parseChangeSpecs(root, changeName);
325
+ return {
326
+ scenarios: [...basePlan.scenarios, ...changePlan.scenarios],
327
+ paramRefs: [...basePlan.paramRefs, ...changePlan.paramRefs],
328
+ };
329
+ }
330
+ /** Per-change progress (design §9: `attest status <change>`). */
331
+ export async function runStatus(root, changeName, options = {}) {
332
+ const nothing = (issues) => ({
333
+ change: changeName,
334
+ rows: [],
335
+ counts: statusCounts([]),
336
+ issues,
337
+ });
338
+ // Checked before anything is read on the name's behalf, for the reason the
339
+ // gate checks it: under `--eval` the name reaches a module that is executed.
340
+ if (!isSafeChangeName(changeName))
341
+ return nothing([invalidChangeNameIssue(changeName)]);
342
+ const read = await readDelta(root, changeName, options);
343
+ if ('issue' in read)
344
+ return nothing([read.issue]);
345
+ const scan = await scanProject(root);
346
+ const plan = await changeMergedPlan(root, changeName, scan.specFiles);
347
+ const firstRun = await readRedRecord(root, changeName);
348
+ const rows = statusRows(addedIds(read.delta), plan, firstRun);
349
+ return { change: changeName, rows, counts: statusCounts(rows), issues: [] };
350
+ }
194
351
  /** Archive gate for a change (design §8, §9: `attest archive <change>`). */
195
352
  export async function runArchive(root, changeName, options = {}) {
196
353
  // Checked before any loader starts: nothing should be resolved, let alone
197
354
  // evaluated, on behalf of a name we have already rejected.
198
- if (!isSafeChangeName(changeName)) {
199
- return [
200
- {
201
- level: 'ERROR',
202
- code: 'invalid-change-name',
203
- message: `Invalid change name ${JSON.stringify(changeName)}. A change name must be one directory inside changes/: it cannot be empty, "." or "..", or contain a path separator.`,
204
- },
205
- ];
206
- }
355
+ if (!isSafeChangeName(changeName))
356
+ return [invalidChangeNameIssue(changeName)];
207
357
  const scan = await scanProject(root);
208
358
  const loader = await createLoader();
209
359
  try {
210
360
  const { registry: base, issues } = await loadRegistry(root, evalReader(loader), scan.reqsFiles);
211
361
  if (issues.some((i) => i.level === 'ERROR'))
212
362
  return issues;
213
- const deltaPath = join(root, 'changes', changeName, 'requirements.delta.ts');
363
+ const deltaPath = changeDeltaPath(root, changeName);
214
364
  let delta;
215
365
  try {
216
366
  const mod = await loader.load(deltaPath);
217
367
  delta = mod.default;
218
368
  }
219
369
  catch (err) {
220
- return [
221
- {
222
- level: 'ERROR',
223
- code: 'change-not-found',
224
- file: relative(root, deltaPath),
225
- message: `Could not find or load the delta for change "${changeName}": ${err instanceof Error ? err.message : String(err)}`,
226
- },
227
- ];
370
+ return [changeNotFoundIssue(root, deltaPath, changeName, err)];
228
371
  }
229
372
  const applied = applyDelta(base, delta);
230
373
  if (applied.issues.length > 0)
231
374
  return applied.issues;
232
- // Static plan = merged base suite + this change's specs (design §8).
233
- const basePlan = await parseSpecs(scan.specFiles, root);
234
- const changePlan = await parseChangeSpecs(root, changeName);
235
- const plan = {
236
- scenarios: [...basePlan.scenarios, ...changePlan.scenarios],
237
- paramRefs: [...basePlan.paramRefs, ...changePlan.paramRefs],
238
- };
375
+ // Static plan = merged base suite + this change's specs (design §8), by the
376
+ // same function `status` reports against — a progress report computed over a
377
+ // different spec set than the gate uses would be a report about nothing.
378
+ const plan = await changeMergedPlan(root, changeName, scan.specFiles);
239
379
  // Run base specs + this change's specs; exclude other proposals and archive.
240
380
  const others = (await listChangeNames(root)).filter((n) => n !== changeName);
241
381
  const exclude = [
@@ -253,7 +393,23 @@ export async function runArchive(root, changeName, options = {}) {
253
393
  exclude,
254
394
  vitestConfig: options.vitestConfig,
255
395
  });
256
- return evaluateGate({ registry: applied.registry, plan, run });
396
+ // Mechanism 2 (design §6). The stage-1 run of this same command is where a
397
+ // scenario is *supposed* to be red, so recording happens on every archive
398
+ // run, before the verdict — a run whose gate fails is exactly the run whose
399
+ // observation matters most. First write wins, so the green run at the end
400
+ // cannot overwrite the red that came before it.
401
+ const added = addedIds(delta);
402
+ let firstRun = await readRedRecord(root, changeName);
403
+ if (added.length > 0) {
404
+ const merged = mergeRedRecord(firstRun, plan, run, added);
405
+ firstRun = merged.record;
406
+ // Only when something was actually learned: re-running the gate on an
407
+ // unchanged change must not dirty the working tree.
408
+ if (merged.changed) {
409
+ await writeAtomic(redRecordPath(root, changeName), serialiseRedRecord(changeName, merged.record));
410
+ }
411
+ }
412
+ return evaluateGate({ registry: applied.registry, plan, run, addedIds: added, firstRun });
257
413
  }
258
414
  finally {
259
415
  await loader.close();
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/core/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { AttestPlan, Outcome, RunResult } from './types.js';
2
+ /** Where the record lives, relative to the project root. */
3
+ export declare function redRecordPath(root: string, changeName: string): string;
4
+ /** The file name, exported so a diagnostic can name it without rebuilding it. */
5
+ export declare const RED_RECORD_FILE = "first-run.json";
6
+ /**
7
+ * reqId -> scenario name -> the outcome of its first observed run.
8
+ *
9
+ * Deliberately not a list of "red scenarios": a scenario whose first run passed
10
+ * is the case mechanism 2 exists to catch, so it has to be recorded as a fact
11
+ * rather than as an absence. An absence then means only one thing — never
12
+ * observed at all — and the gate can report the two separately.
13
+ */
14
+ export type RedRecord = Record<string, Record<string, Outcome>>;
15
+ /**
16
+ * Read the record for a change. A missing or unreadable file is an empty
17
+ * record, never an error: the first stage-1 run legitimately finds nothing, and
18
+ * a corrupt file must not be more permissive than a missing one — with an empty
19
+ * record every obligation is "never observed", which the gate blocks on.
20
+ */
21
+ export declare function readRedRecord(root: string, changeName: string): Promise<RedRecord>;
22
+ /** What the record says about one scenario, or undefined if it never saw it. */
23
+ export declare function recordedOutcome(record: RedRecord, reqId: string, scenario: string): Outcome | undefined;
24
+ /**
25
+ * Whether this scenario has satisfied the first-red obligation (design §6).
26
+ *
27
+ * One definition, because two readers now decide on it: the gate blocks when it
28
+ * is false, and `status` reports what the gate will do before it is run. A
29
+ * second spelling of `=== 'fail'` would let the report and the verdict drift
30
+ * apart — the same argument that extracted `declaredNotRunIssues` and
31
+ * `uncoveredIssues` from the commands that had a copy each.
32
+ */
33
+ export declare function hasRecordedRed(record: RedRecord, reqId: string, scenario: string): boolean;
34
+ /**
35
+ * Fold this run's outcomes into the record, for the scenarios that carry an
36
+ * obligation — those covering a requirement this change ADDs.
37
+ *
38
+ * Scoped that way rather than to every scenario in the run, because the base
39
+ * suite's scenarios have no obligation here and recording them would grow a file
40
+ * nobody reads with facts nothing checks. Returns the merged record and whether
41
+ * anything changed, so an unchanged record is not rewritten (an archive run that
42
+ * only re-reads must not dirty the working tree).
43
+ */
44
+ export declare function mergeRedRecord(existing: RedRecord, plan: AttestPlan, run: RunResult, addedIds: readonly string[]): {
45
+ record: RedRecord;
46
+ changed: boolean;
47
+ };
48
+ /** Serialise the record. A trailing newline, so the file is a well-formed text file. */
49
+ export declare function serialiseRedRecord(changeName: string, record: RedRecord): string;
50
+ //# sourceMappingURL=red-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"red-record.d.ts","sourceRoot":"","sources":["../../src/core/red-record.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGjE,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,iFAAiF;AACjF,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAUhE;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAaxF;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,GAAG,SAAS,CAErB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE1F;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,SAAS,EACnB,IAAI,EAAE,UAAU,EAChB,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAmCzC;AAED,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAGhF"}
@@ -0,0 +1,148 @@
1
+ // Mechanism 2's record: what each of a change's scenarios did the *first* time
2
+ // it ran (design §6).
3
+ //
4
+ // §8's gate requires green at archive time. That certifies "these tests pass",
5
+ // not "these tests ever discriminated" — a scenario that asserted nothing has
6
+ // been green since the commit that added it and clears the gate exactly like one
7
+ // that drove an implementation. Closing that needs a fact about history, and
8
+ // history needs a record: nothing observable at archive time can distinguish the
9
+ // two, because by then both are green.
10
+ //
11
+ // **The observation point already existed.** The workflow (§9, and the skill
12
+ // `attest init` writes) has stage 1 run `attest archive <name>` and *expect*
13
+ // `tests-red`. The engine saw every one of those reds and threw them away. This
14
+ // file keeps them.
15
+ //
16
+ // **Why a generated file, committed, is acceptable here and nowhere else.** This
17
+ // project treats a committed generated artifact as a liability — the argument
18
+ // against `init --check`, and the reason `render` takes no formatting options.
19
+ // The difference is lifetime. `changes/<name>/` is temporary by construction: it
20
+ // exists while a change is in flight and goes away when the change is archived,
21
+ // so this file has exactly the change's lifetime and never becomes a permanent
22
+ // asset that can drift. It is also *evidence*, and evidence belongs in the diff
23
+ // a reviewer reads.
24
+ //
25
+ // It has to be committed rather than kept in a scratch directory, because the
26
+ // gate must reach the same verdict on a CI runner's fresh checkout as it does on
27
+ // the author's machine — a witness that only exists locally would block every
28
+ // change that CI archives.
29
+ //
30
+ // **A fail is sticky; a pass is provisional.** The record moves one way only,
31
+ // toward `fail`, and the asymmetry is load-bearing in both directions.
32
+ //
33
+ // Sticky fail: recording the latest outcome would erase the very fact being
34
+ // recorded, because by the time a change is archivable everything is green — a
35
+ // last-write-wins record says "green" about a scenario that spent the whole
36
+ // change red. Once a scenario has been seen to fail, nothing can take it back.
37
+ //
38
+ // Provisional pass: plain first-write-wins was the first design here, and it
39
+ // makes the defect this mechanism exists to catch *unrecoverable*. A scenario
40
+ // that passed on its first run is one that asserts nothing; the fix is to give
41
+ // it a real assertion and watch it fail — but under first-write-wins that
42
+ // observation could never be recorded, so the only way out was deleting the
43
+ // record by hand, a manual step that would equally let someone delete a genuine
44
+ // red. Allowing a later `fail` to replace an earlier `pass` cannot be abused,
45
+ // because the only way to produce one is for the scenario to actually fail.
46
+ import { readFile } from 'node:fs/promises';
47
+ import { join } from 'node:path';
48
+ import { byCodeUnit } from './order.js';
49
+ /** Where the record lives, relative to the project root. */
50
+ export function redRecordPath(root, changeName) {
51
+ return join(root, 'changes', changeName, RED_RECORD_FILE);
52
+ }
53
+ /** The file name, exported so a diagnostic can name it without rebuilding it. */
54
+ export const RED_RECORD_FILE = 'first-run.json';
55
+ /**
56
+ * Read the record for a change. A missing or unreadable file is an empty
57
+ * record, never an error: the first stage-1 run legitimately finds nothing, and
58
+ * a corrupt file must not be more permissive than a missing one — with an empty
59
+ * record every obligation is "never observed", which the gate blocks on.
60
+ */
61
+ export async function readRedRecord(root, changeName) {
62
+ let raw;
63
+ try {
64
+ raw = await readFile(redRecordPath(root, changeName), 'utf8');
65
+ }
66
+ catch {
67
+ return {};
68
+ }
69
+ try {
70
+ const parsed = JSON.parse(raw);
71
+ return isRecord(parsed?.firstRun) ? parsed.firstRun : {};
72
+ }
73
+ catch {
74
+ return {};
75
+ }
76
+ }
77
+ /** What the record says about one scenario, or undefined if it never saw it. */
78
+ export function recordedOutcome(record, reqId, scenario) {
79
+ return record[reqId]?.[scenario];
80
+ }
81
+ /**
82
+ * Whether this scenario has satisfied the first-red obligation (design §6).
83
+ *
84
+ * One definition, because two readers now decide on it: the gate blocks when it
85
+ * is false, and `status` reports what the gate will do before it is run. A
86
+ * second spelling of `=== 'fail'` would let the report and the verdict drift
87
+ * apart — the same argument that extracted `declaredNotRunIssues` and
88
+ * `uncoveredIssues` from the commands that had a copy each.
89
+ */
90
+ export function hasRecordedRed(record, reqId, scenario) {
91
+ return recordedOutcome(record, reqId, scenario) === 'fail';
92
+ }
93
+ /**
94
+ * Fold this run's outcomes into the record, for the scenarios that carry an
95
+ * obligation — those covering a requirement this change ADDs.
96
+ *
97
+ * Scoped that way rather than to every scenario in the run, because the base
98
+ * suite's scenarios have no obligation here and recording them would grow a file
99
+ * nobody reads with facts nothing checks. Returns the merged record and whether
100
+ * anything changed, so an unchanged record is not rewritten (an archive run that
101
+ * only re-reads must not dirty the working tree).
102
+ */
103
+ export function mergeRedRecord(existing, plan, run, addedIds) {
104
+ const added = new Set(addedIds);
105
+ const record = {};
106
+ // Rebuild rather than mutate, so key order is a function of the data and two
107
+ // machines write byte-identical files (the same reason `render` orders ids
108
+ // through one code-unit comparator).
109
+ for (const id of Object.keys(existing).sort(byCodeUnit)) {
110
+ record[id] = { ...existing[id] };
111
+ }
112
+ let changed = false;
113
+ for (const s of plan.scenarios) {
114
+ if (!added.has(s.reqId))
115
+ continue;
116
+ const outcome = run.outcomes.get(s.reqId)?.get(s.name);
117
+ // No outcome means the scenario did not execute. That is `declared-not-run`,
118
+ // reported by the gate on its own terms; writing nothing here leaves the
119
+ // obligation unobserved rather than inventing a state for it.
120
+ if (!outcome)
121
+ continue;
122
+ const forId = (record[s.reqId] ??= {});
123
+ // Monotonic toward `fail`: a recorded fail is final, a recorded pass can
124
+ // still be corrected by a real one. See the note at the top of this file.
125
+ if (forId[s.name] === 'fail' || forId[s.name] === outcome)
126
+ continue;
127
+ forId[s.name] = outcome;
128
+ changed = true;
129
+ }
130
+ // Sort within each requirement for the same byte-stability reason.
131
+ for (const id of Object.keys(record)) {
132
+ const sorted = {};
133
+ for (const name of Object.keys(record[id]).sort(byCodeUnit)) {
134
+ sorted[name] = record[id][name];
135
+ }
136
+ record[id] = sorted;
137
+ }
138
+ return { record, changed };
139
+ }
140
+ /** Serialise the record. A trailing newline, so the file is a well-formed text file. */
141
+ export function serialiseRedRecord(changeName, record) {
142
+ const file = { version: 1, change: changeName, firstRun: record };
143
+ return `${JSON.stringify(file, null, 2)}\n`;
144
+ }
145
+ function isRecord(value) {
146
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
147
+ }
148
+ //# sourceMappingURL=red-record.js.map