@rasensio/aidlc 1.19.0 → 1.20.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 (44) hide show
  1. package/dist/change/cross-check.d.ts +28 -0
  2. package/dist/change/cross-check.d.ts.map +1 -0
  3. package/dist/change/cross-check.js +53 -0
  4. package/dist/change/cross-check.js.map +1 -0
  5. package/dist/change/impact.d.ts +57 -0
  6. package/dist/change/impact.d.ts.map +1 -0
  7. package/dist/change/impact.js +288 -0
  8. package/dist/change/impact.js.map +1 -0
  9. package/dist/change/index.d.ts +12 -0
  10. package/dist/change/index.d.ts.map +1 -0
  11. package/dist/change/index.js +11 -0
  12. package/dist/change/index.js.map +1 -0
  13. package/dist/change/parser.d.ts +52 -0
  14. package/dist/change/parser.d.ts.map +1 -0
  15. package/dist/change/parser.js +339 -0
  16. package/dist/change/parser.js.map +1 -0
  17. package/dist/change/reopen.d.ts +80 -0
  18. package/dist/change/reopen.d.ts.map +1 -0
  19. package/dist/change/reopen.js +227 -0
  20. package/dist/change/reopen.js.map +1 -0
  21. package/dist/change/types.d.ts +144 -0
  22. package/dist/change/types.d.ts.map +1 -0
  23. package/dist/change/types.js +8 -0
  24. package/dist/change/types.js.map +1 -0
  25. package/dist/cli.d.ts.map +1 -1
  26. package/dist/cli.js +2 -0
  27. package/dist/cli.js.map +1 -1
  28. package/dist/commands/amend.d.ts +22 -0
  29. package/dist/commands/amend.d.ts.map +1 -0
  30. package/dist/commands/amend.js +355 -0
  31. package/dist/commands/amend.js.map +1 -0
  32. package/dist/commands/docs.d.ts.map +1 -1
  33. package/dist/commands/docs.js +6 -0
  34. package/dist/commands/docs.js.map +1 -1
  35. package/dist/core/lifecycle.d.ts +3 -0
  36. package/dist/core/lifecycle.d.ts.map +1 -1
  37. package/dist/core/lifecycle.js +13 -2
  38. package/dist/core/lifecycle.js.map +1 -1
  39. package/dist/core/types.d.ts +37 -2
  40. package/dist/core/types.d.ts.map +1 -1
  41. package/dist/menu/roster.d.ts.map +1 -1
  42. package/dist/menu/roster.js +4 -0
  43. package/dist/menu/roster.js.map +1 -1
  44. package/package.json +2 -2
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Amendment cross-check (FR2): do the ids an amendment claims match what the
3
+ * requirements file actually defines?
4
+ *
5
+ * Two checks only, and both are data (AC-13) — they never fail a gate and never
6
+ * change an exit code. The obvious third check, "a retired criterion no
7
+ * amendment claims", was specified and then dropped: measured on this repo it
8
+ * fires 44 times across 12 instances that have never been amended, which is
9
+ * noise arriving before any signal (retired AC-12).
10
+ *
11
+ * Warnings from here surface in `aidlc amend` output alone (AC-74). Putting
12
+ * them where the traceability warnings surface — `aidlc gate --json` and the
13
+ * `criterionWarnings` block at `commands/transition.ts:408-419` — would have
14
+ * changed output for every never-amended instance on the first run.
15
+ *
16
+ * Requirements: change-management/AC-10, AC-11, AC-13
17
+ */
18
+ import type { ParsedRequirements } from '../traceability/types.js';
19
+ import type { Amendment } from './types.js';
20
+ /**
21
+ * Cross-check one amendment's claimed ids against the AC definitions.
22
+ *
23
+ * @param amendment - The amendment under consideration.
24
+ * @param parsed - Parsed requirements for the same file.
25
+ * @returns Warnings, ordered `Retires:` then `Issues:`, ascending by id.
26
+ */
27
+ export declare function crossCheck(amendment: Amendment, parsed: ParsedRequirements): string[];
28
+ //# sourceMappingURL=cross-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-check.d.ts","sourceRoot":"","sources":["../../src/change/cross-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAsCrF"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Amendment cross-check (FR2): do the ids an amendment claims match what the
3
+ * requirements file actually defines?
4
+ *
5
+ * Two checks only, and both are data (AC-13) — they never fail a gate and never
6
+ * change an exit code. The obvious third check, "a retired criterion no
7
+ * amendment claims", was specified and then dropped: measured on this repo it
8
+ * fires 44 times across 12 instances that have never been amended, which is
9
+ * noise arriving before any signal (retired AC-12).
10
+ *
11
+ * Warnings from here surface in `aidlc amend` output alone (AC-74). Putting
12
+ * them where the traceability warnings surface — `aidlc gate --json` and the
13
+ * `criterionWarnings` block at `commands/transition.ts:408-419` — would have
14
+ * changed output for every never-amended instance on the first run.
15
+ *
16
+ * Requirements: change-management/AC-10, AC-11, AC-13
17
+ */
18
+ /**
19
+ * Cross-check one amendment's claimed ids against the AC definitions.
20
+ *
21
+ * @param amendment - The amendment under consideration.
22
+ * @param parsed - Parsed requirements for the same file.
23
+ * @returns Warnings, ordered `Retires:` then `Issues:`, ascending by id.
24
+ */
25
+ export function crossCheck(amendment, parsed) {
26
+ const byId = new Map(parsed.defs.map((def) => [def.id, def]));
27
+ const warnings = [];
28
+ // AC-10: an id claimed as retired that is not defined as retired.
29
+ for (const id of [...amendment.retires].sort((a, b) => a - b)) {
30
+ const def = byId.get(id);
31
+ if (!def) {
32
+ warnings.push(`Amendment ${amendment.n} retires AC-${id}, which this file does not define`);
33
+ continue;
34
+ }
35
+ if (def.status !== 'retired') {
36
+ warnings.push(`Amendment ${amendment.n} retires AC-${id}, but line ${def.line} defines it as ` +
37
+ `${def.status} — mark the definition bullet retired, or drop it from Retires:`);
38
+ }
39
+ }
40
+ // AC-11: an id claimed as issued that is undefined, or defined as retired.
41
+ for (const id of [...amendment.issues].sort((a, b) => a - b)) {
42
+ const def = byId.get(id);
43
+ if (!def) {
44
+ warnings.push(`Amendment ${amendment.n} issues AC-${id}, which this file does not define`);
45
+ continue;
46
+ }
47
+ if (def.status === 'retired') {
48
+ warnings.push(`Amendment ${amendment.n} issues AC-${id}, but line ${def.line} defines it as retired`);
49
+ }
50
+ }
51
+ return warnings;
52
+ }
53
+ //# sourceMappingURL=cross-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-check.js","sourceRoot":"","sources":["../../src/change/cross-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,SAAoB,EAAE,MAA0B;IACzE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,kEAAkE;IAClE,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,QAAQ,CAAC,IAAI,CACX,aAAa,SAAS,CAAC,CAAC,eAAe,EAAE,mCAAmC,CAC7E,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CACX,aAAa,SAAS,CAAC,CAAC,eAAe,EAAE,cAAc,GAAG,CAAC,IAAI,iBAAiB;gBAC9E,GAAG,GAAG,CAAC,MAAM,iEAAiE,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,QAAQ,CAAC,IAAI,CACX,aAAa,SAAS,CAAC,CAAC,cAAc,EAAE,mCAAmC,CAC5E,CAAC;YACF,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CACX,aAAa,SAAS,CAAC,CAAC,cAAc,EAAE,cAAc,GAAG,CAAC,IAAI,wBAAwB,CACvF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Impact walk (FR3): which citations of a retired criterion are still out there?
3
+ *
4
+ * Read-only and advisory. It performs no writes (AC-22) and its `suggestedReopens`
5
+ * is a suggestion the author may paste into `Reopens:` — `aidlc amend` never reads
6
+ * it (AC-58). The first draft derived the reopen set from this walk, which was
7
+ * degenerate: `requirements.md` is the requirements phase's declared artifact and
8
+ * always cites every retired id (the retirement bullet, the `superseded by AC-m`
9
+ * clause, and the amendment's own `Retires:` field), so every amendment would have
10
+ * reopened requirements. A destructive state write must not depend on a
11
+ * prose-scanning heuristic.
12
+ *
13
+ * Three halves, each with a stated resolution rule, because the two shipped rules
14
+ * genuinely differ and picking one for both would be wrong:
15
+ *
16
+ * - **Test files** use the uniqueness rule at `traceability/matrix.ts:77-87` — a
17
+ * bare `AC-n` counts only when exactly one AC-bearing instance defines the id.
18
+ * - **Tasks** use the owning-instance rule (`tasks/types.ts:15-19`), which that file
19
+ * documents as "never traceability's uniqueness rule".
20
+ * - **Artifacts** use the same tokens as the scanner, resolved by the test rule.
21
+ *
22
+ * `requirements.md` is the one artifact never read: it is the authority being
23
+ * amended, not a consumer of it (AC-81). AC-definition-shaped bullets *elsewhere*
24
+ * are reported rather than excluded — measured, 20 such bullets live in
25
+ * `tasks.md`, `code-complete.md` and `reproduction.md` files and every one is
26
+ * verification evidence citing a criterion, which is signal.
27
+ *
28
+ * Requirements: change-management/AC-15, AC-17, AC-21, AC-22, AC-48, AC-49,
29
+ * AC-58, AC-71, AC-80, AC-81, AC-88
30
+ */
31
+ import type { WorkflowTemplate } from '../core/types.js';
32
+ import type { ParsedRequirements } from '../traceability/types.js';
33
+ import type { Amendment, ImpactReport } from './types.js';
34
+ export interface WalkInput {
35
+ projectRoot: string;
36
+ instance: string;
37
+ /** The amendment whose retirements drive the walk. */
38
+ amendment: Amendment;
39
+ /** All instances' parsed requirements — the uniqueness-rule registry. */
40
+ registry: Map<string, ParsedRequirements>;
41
+ resolvedTemplate: WorkflowTemplate;
42
+ scope: string;
43
+ }
44
+ /**
45
+ * Walk every citation of the amendment's retired ids.
46
+ *
47
+ * @returns A report whose `outcome` distinguishes four states (AC-88): a
48
+ * truncated `Retires:` and a genuinely empty one must never render alike.
49
+ */
50
+ export declare function walkImpact(input: WalkInput): ImpactReport;
51
+ /**
52
+ * One-line human summary. Every outcome says something — an empty result is
53
+ * never rendered as silence (AC-21), because a silent no-op is
54
+ * indistinguishable from success.
55
+ */
56
+ export declare function describeOutcome(report: ImpactReport): string;
57
+ //# sourceMappingURL=impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.d.ts","sourceRoot":"","sources":["../../src/change/impact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AASnE,OAAO,KAAK,EAAE,SAAS,EAAa,YAAY,EAAiB,MAAM,YAAY,CAAC;AA2BpF,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,EAAE,SAAS,CAAC;IACrB,yEAAyE;IACzE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC1C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,YAAY,CAuNzD;AAMD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAa5D"}
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Impact walk (FR3): which citations of a retired criterion are still out there?
3
+ *
4
+ * Read-only and advisory. It performs no writes (AC-22) and its `suggestedReopens`
5
+ * is a suggestion the author may paste into `Reopens:` — `aidlc amend` never reads
6
+ * it (AC-58). The first draft derived the reopen set from this walk, which was
7
+ * degenerate: `requirements.md` is the requirements phase's declared artifact and
8
+ * always cites every retired id (the retirement bullet, the `superseded by AC-m`
9
+ * clause, and the amendment's own `Retires:` field), so every amendment would have
10
+ * reopened requirements. A destructive state write must not depend on a
11
+ * prose-scanning heuristic.
12
+ *
13
+ * Three halves, each with a stated resolution rule, because the two shipped rules
14
+ * genuinely differ and picking one for both would be wrong:
15
+ *
16
+ * - **Test files** use the uniqueness rule at `traceability/matrix.ts:77-87` — a
17
+ * bare `AC-n` counts only when exactly one AC-bearing instance defines the id.
18
+ * - **Tasks** use the owning-instance rule (`tasks/types.ts:15-19`), which that file
19
+ * documents as "never traceability's uniqueness rule".
20
+ * - **Artifacts** use the same tokens as the scanner, resolved by the test rule.
21
+ *
22
+ * `requirements.md` is the one artifact never read: it is the authority being
23
+ * amended, not a consumer of it (AC-81). AC-definition-shaped bullets *elsewhere*
24
+ * are reported rather than excluded — measured, 20 such bullets live in
25
+ * `tasks.md`, `code-complete.md` and `reproduction.md` files and every one is
26
+ * verification evidence citing a criterion, which is signal.
27
+ *
28
+ * Requirements: change-management/AC-15, AC-17, AC-21, AC-22, AC-48, AC-49,
29
+ * AC-58, AC-71, AC-80, AC-81, AC-88
30
+ */
31
+ import { existsSync, readFileSync, statSync } from 'node:fs';
32
+ import { join } from 'node:path';
33
+ import { phasesForScope } from '../core/template-resolver.js';
34
+ import { DEFAULT_TEST_GLOBS, discoverTestFiles, scanContent, scanFiles, } from '../traceability/scanner.js';
35
+ import { loadTraceabilityConfig } from '../traceability/gate-criterion.js';
36
+ import { parseTasks } from '../tasks/parser.js';
37
+ /** The one artifact the walk never reads (AC-81). */
38
+ const AUTHORITY_ARTIFACT = 'requirements.md';
39
+ /** Same bounds the scanner applies (`scanner.ts:31-33`), copied onto the artifact half. */
40
+ const MAX_FILE_BYTES = 1024 * 1024;
41
+ const BINARY_SNIFF_BYTES = 8 * 1024;
42
+ /**
43
+ * A template artifact name that could escape the instance directory is skipped
44
+ * (AC-17), mirroring `traceability/gate-criterion.ts:64-71`. Template files come
45
+ * from `.aidlc/templates/`, which is tracked and therefore untrusted.
46
+ */
47
+ function isSafeArtifactName(name) {
48
+ return !name.includes('/') && !name.includes('\\') && !name.includes('..');
49
+ }
50
+ /** Instances defining a given AC id, for the uniqueness rule. */
51
+ function definersOf(registry, acId) {
52
+ const definers = [];
53
+ for (const [name, parsed] of registry) {
54
+ if (parsed.defs.some((def) => def.id === acId))
55
+ definers.push(name);
56
+ }
57
+ return definers.sort();
58
+ }
59
+ /**
60
+ * Walk every citation of the amendment's retired ids.
61
+ *
62
+ * @returns A report whose `outcome` distinguishes four states (AC-88): a
63
+ * truncated `Retires:` and a genuinely empty one must never render alike.
64
+ */
65
+ export function walkImpact(input) {
66
+ const { projectRoot, instance, amendment, registry, resolvedTemplate, scope } = input;
67
+ if (!amendment.retiresPresent) {
68
+ return emptyReport('retires-absent', []);
69
+ }
70
+ const retiredIds = [...new Set(amendment.retires)].sort((a, b) => a - b);
71
+ if (retiredIds.length === 0) {
72
+ return emptyReport('no-retirements', []);
73
+ }
74
+ const wanted = new Set(retiredIds);
75
+ const refs = [];
76
+ const warnings = [];
77
+ // Ambiguity is counted per id and reported once (AC-80), never per occurrence.
78
+ // Measured on this instance: 289 of 289 bare occurrences were ambiguous and
79
+ // none resolved here, so per-occurrence reporting is 289 lines of noise before
80
+ // any signal — the shape that retired AC-12 at 44.
81
+ const ambiguous = new Map();
82
+ const noteAmbiguous = (acId, path) => {
83
+ let paths = ambiguous.get(acId);
84
+ if (!paths)
85
+ ambiguous.set(acId, (paths = new Set()));
86
+ paths.add(path);
87
+ };
88
+ /**
89
+ * Resolve one scanned reference to this instance, or explain why not.
90
+ * Returns true when the reference belongs to this instance.
91
+ */
92
+ const resolvesHere = (acId, refInstance, path) => {
93
+ if (refInstance !== null) {
94
+ // Qualified: counts only for the named instance, and an unknown
95
+ // instance/id warns and drops (`matrix.ts:66-75`).
96
+ const target = registry.get(refInstance);
97
+ if (!target || !target.defs.some((def) => def.id === acId))
98
+ return false;
99
+ return refInstance === instance;
100
+ }
101
+ const definers = definersOf(registry, acId);
102
+ if (definers.length === 0)
103
+ return false;
104
+ if (definers.length > 1) {
105
+ // Only worth mentioning when this instance is among the definers. When it
106
+ // is not, the reference is provably not ours and saying so is pure noise.
107
+ if (definers.includes(instance))
108
+ noteAmbiguous(acId, path);
109
+ return false;
110
+ }
111
+ return definers[0] === instance;
112
+ };
113
+ // ---- Test files (AC-80) -------------------------------------------------
114
+ const config = loadTraceabilityConfig(projectRoot);
115
+ const globs = config?.test_globs ?? DEFAULT_TEST_GLOBS;
116
+ const discovery = discoverTestFiles(projectRoot, globs);
117
+ warnings.push(...discovery.warnings);
118
+ const scan = scanFiles(projectRoot, discovery.files);
119
+ warnings.push(...scan.warnings);
120
+ for (const ref of scan.refs) {
121
+ if (!wanted.has(ref.acId))
122
+ continue;
123
+ if (!resolvesHere(ref.acId, ref.instance, ref.path))
124
+ continue;
125
+ refs.push({ path: ref.path, line: ref.line, acId: ref.acId, source: 'test' });
126
+ }
127
+ // ---- tasks.md (AC-15) ---------------------------------------------------
128
+ // The owning-instance rule, deliberately different from the rule above.
129
+ const instanceDir = join(projectRoot, '.aidlc', 'state', instance);
130
+ const tasksPath = join(instanceDir, 'tasks.md');
131
+ if (existsSync(tasksPath)) {
132
+ let tasksContent = null;
133
+ try {
134
+ tasksContent = readFileSync(tasksPath, 'utf8');
135
+ }
136
+ catch {
137
+ warnings.push(`skipped tasks.md: unreadable`);
138
+ }
139
+ if (tasksContent !== null) {
140
+ const relTasks = `.aidlc/state/${instance}/tasks.md`;
141
+ for (const task of parseTasks(tasksContent).tasks) {
142
+ for (const acRef of task.acRefs) {
143
+ if (!wanted.has(acRef.id))
144
+ continue;
145
+ // Bare refs resolve to the owning instance; a qualified ref naming
146
+ // someone else is that instance's business.
147
+ if (acRef.instance !== null && acRef.instance !== instance)
148
+ continue;
149
+ refs.push({
150
+ path: relTasks,
151
+ line: task.line,
152
+ acId: acRef.id,
153
+ source: 'task',
154
+ taskId: task.id,
155
+ taskState: task.state,
156
+ });
157
+ }
158
+ }
159
+ }
160
+ }
161
+ // ---- Phase artifacts (AC-81) -------------------------------------------
162
+ // Every artifact the template declares, required and optional, except the
163
+ // authority. Phase ownership is what turns a hit into a suggested reopen.
164
+ const applicable = phasesForScope(resolvedTemplate, scope);
165
+ const phaseByArtifact = new Map();
166
+ const impactedPhases = new Set();
167
+ for (const phase of applicable) {
168
+ const declared = [
169
+ ...(phase.required_artifacts ?? []),
170
+ ...(phase.optional_artifacts ?? []),
171
+ ];
172
+ for (const decl of declared) {
173
+ if (decl.name === AUTHORITY_ARTIFACT)
174
+ continue;
175
+ if (!isSafeArtifactName(decl.name)) {
176
+ warnings.push(`skipped artifact "${decl.name}" declared by phase "${phase.name}": ` +
177
+ `name could escape the instance directory`);
178
+ continue;
179
+ }
180
+ // First declaring phase wins, so an artifact named by two phases is
181
+ // attributed deterministically rather than by iteration accident.
182
+ if (!phaseByArtifact.has(decl.name))
183
+ phaseByArtifact.set(decl.name, String(phase.name));
184
+ }
185
+ }
186
+ for (const [artifact, phaseName] of phaseByArtifact) {
187
+ const abs = join(instanceDir, artifact);
188
+ if (!existsSync(abs))
189
+ continue;
190
+ let size;
191
+ try {
192
+ size = statSync(abs).size;
193
+ }
194
+ catch {
195
+ warnings.push(`skipped ${artifact}: unreadable`);
196
+ continue;
197
+ }
198
+ if (size > MAX_FILE_BYTES) {
199
+ warnings.push(`skipped ${artifact}: too large`);
200
+ continue;
201
+ }
202
+ let buf;
203
+ try {
204
+ buf = readFileSync(abs);
205
+ }
206
+ catch {
207
+ warnings.push(`skipped ${artifact}: unreadable`);
208
+ continue;
209
+ }
210
+ if (buf.subarray(0, BINARY_SNIFF_BYTES).includes(0)) {
211
+ warnings.push(`skipped ${artifact}: binary`);
212
+ continue;
213
+ }
214
+ const rel = `.aidlc/state/${instance}/${artifact}`;
215
+ for (const ref of scanContent(buf.toString('utf8'), rel)) {
216
+ if (!wanted.has(ref.acId))
217
+ continue;
218
+ if (!resolvesHere(ref.acId, ref.instance, ref.path))
219
+ continue;
220
+ refs.push({ path: rel, line: ref.line, acId: ref.acId, source: 'artifact' });
221
+ impactedPhases.add(phaseName);
222
+ }
223
+ }
224
+ // ---- Assembly (AC-71, AC-48) -------------------------------------------
225
+ // Dedup on path:line:acId with `task` winning, because a task record carries
226
+ // strictly more information and tasks.md is walked twice by construction —
227
+ // once as tasks, once as the design phase's declared artifact.
228
+ const byKey = new Map();
229
+ for (const ref of refs) {
230
+ const key = `${ref.path}:${ref.line}:${ref.acId}`;
231
+ const existing = byKey.get(key);
232
+ if (!existing || (existing.source === 'artifact' && ref.source === 'task')) {
233
+ byKey.set(key, ref);
234
+ }
235
+ }
236
+ const deduped = [...byKey.values()].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0) ||
237
+ a.line - b.line ||
238
+ a.acId - b.acId);
239
+ // A task citing a retired id means the design phase's tasks.md is stale;
240
+ // a test citing one means the testing phase is.
241
+ for (const ref of deduped) {
242
+ if (ref.source === 'task') {
243
+ const design = applicable.find((p) => (p.required_artifacts ?? []).some((a) => a.name === 'tasks.md'));
244
+ if (design)
245
+ impactedPhases.add(String(design.name));
246
+ }
247
+ else if (ref.source === 'test') {
248
+ if (applicable.some((p) => p.name === 'testing'))
249
+ impactedPhases.add('testing');
250
+ }
251
+ }
252
+ for (const [acId, paths] of [...ambiguous.entries()].sort((a, b) => a[0] - b[0])) {
253
+ warnings.push(`bare AC-${acId} is ambiguous in ${paths.size} file(s) and was not counted; ` +
254
+ `qualify as ${instance}/AC-${acId}`);
255
+ }
256
+ const order = new Map(applicable.map((p, i) => [String(p.name), i]));
257
+ const suggestedReopens = [...impactedPhases].sort((a, b) => (order.get(a) ?? 0) - (order.get(b) ?? 0));
258
+ return {
259
+ outcome: deduped.length > 0 ? 'impacts' : 'none',
260
+ retiredIds,
261
+ refs: deduped,
262
+ suggestedReopens,
263
+ warnings,
264
+ };
265
+ }
266
+ function emptyReport(outcome, retiredIds) {
267
+ return { outcome, retiredIds, refs: [], suggestedReopens: [], warnings: [] };
268
+ }
269
+ /**
270
+ * One-line human summary. Every outcome says something — an empty result is
271
+ * never rendered as silence (AC-21), because a silent no-op is
272
+ * indistinguishable from success.
273
+ */
274
+ export function describeOutcome(report) {
275
+ switch (report.outcome) {
276
+ case 'retires-absent':
277
+ return 'this amendment declares no Retires: field, so there is nothing to walk';
278
+ case 'no-retirements':
279
+ return 'this amendment retires no criteria, so there is nothing to walk';
280
+ case 'none':
281
+ return `no citations of AC-${report.retiredIds.join(', AC-')} found outside requirements.md`;
282
+ case 'impacts': {
283
+ const files = new Set(report.refs.map((r) => r.path)).size;
284
+ return `${report.refs.length} citation(s) across ${files} file(s) still name a retired criterion`;
285
+ }
286
+ }
287
+ }
288
+ //# sourceMappingURL=impact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.js","sourceRoot":"","sources":["../../src/change/impact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Mid-instance change management: amendments, the read-only impact walk, and
3
+ * the `reopen` transition.
4
+ *
5
+ * @module
6
+ */
7
+ export type { Amendment, AmendEnvelope, AmendErrorCode, BlockedCode, ImpactOutcome, ImpactRef, ImpactReport, ParsedAmendments, ReopenPlan, } from './types.js';
8
+ export { parseAmendments, scanOutsideFences } from './parser.js';
9
+ export { crossCheck } from './cross-check.js';
10
+ export { describeOutcome, walkImpact } from './impact.js';
11
+ export { applyReopen, mergeApplied, planReopen, recordApplied } from './reopen.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/change/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Mid-instance change management: amendments, the read-only impact walk, and
3
+ * the `reopen` transition.
4
+ *
5
+ * @module
6
+ */
7
+ export { parseAmendments, scanOutsideFences } from './parser.js';
8
+ export { crossCheck } from './cross-check.js';
9
+ export { describeOutcome, walkImpact } from './impact.js';
10
+ export { applyReopen, mergeApplied, planReopen, recordApplied } from './reopen.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/change/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Amendment parser: closed grammar over the `## Amendment <n>` sections of
3
+ * requirements.md (FR1).
4
+ *
5
+ * The grammar was derived from the corpus, not invented. Measured over 39
6
+ * `requirements.md` and 29 `tasks.md` on 2026-09-07, two conventions exist:
7
+ *
8
+ * ## Amendment 1 — 2026-09-05, after the design review (5 real, accepted)
9
+ * ### Amendments from the design review (2026-09-05) (4 real, warned)
10
+ *
11
+ * The second is unnumbered and undated and cannot be applied, so it warns
12
+ * rather than vanishing — a near-miss that reads as absence is this project's
13
+ * single most repeated defect class (AC-53).
14
+ *
15
+ * Two rules exist because a prototype got them wrong on real input:
16
+ *
17
+ * - **Three emphasis variants, copied from `ACTIVE_RE`** (`traceability/parser.ts:23-24`).
18
+ * The first draft accepted `Retires:` and `**Retires**:` but not
19
+ * `**Retires:**` — which is the form this instance's own Amendment 1 was
20
+ * written with, so its 23 retirements parsed as zero (AC-78).
21
+ * - **A wrapped bullet is one bullet.** Ending the field block at "the first
22
+ * non-bullet non-blank line" truncates any field that wraps: measured, a
23
+ * wrapped `Retires:` yielded 12 of 23 ids and dropped `Issues`, `Reason`
24
+ * and `Reopens` outright, and the impact report would then have said "no
25
+ * retired ids" for an amendment that retired 23 criteria (AC-78, AC-94).
26
+ *
27
+ * Requirements: change-management/AC-3, AC-5, AC-7, AC-8, AC-51, AC-53,
28
+ * AC-54, AC-78, AC-79
29
+ */
30
+ import type { ParsedAmendments } from './types.js';
31
+ /**
32
+ * Walk lines outside fenced code blocks (AC-79).
33
+ *
34
+ * CommonMark rules: a fence opens with 3+ backticks or tildes and closes only
35
+ * on the same character at the same length or longer. Written correctly rather
36
+ * than as a naive toggle because it is cheap to do so — the corpus currently
37
+ * cannot tell the two apart (1047 AC-shaped lines, zero inside fences), which
38
+ * is a reason to write the correct one, not evidence that it does not matter.
39
+ *
40
+ * Indentation is deliberately permissive (`\s*`, not ` {0,3}`): AIDLC markdown
41
+ * nests fenced examples inside list items routinely — see the `ac-coverage`
42
+ * example at `packages/content/skills/50-testing.md:43-45`, indented five
43
+ * spaces — and an absolute three-space rule is blind to every one of them.
44
+ */
45
+ export declare function scanOutsideFences(lines: string[], visit: (line: string, index: number) => void): void;
46
+ /**
47
+ * Parse every amendment section in one requirements.md.
48
+ *
49
+ * @param content - File content (UTF-8). Never throws.
50
+ */
51
+ export declare function parseAmendments(content: string): ParsedAmendments;
52
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/change/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAa,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+D9D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAC3C,IAAI,CAgBN;AA4FD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAwJjE"}