@rasensio/aidlc 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/commands/gate.d.ts.map +1 -1
  2. package/dist/commands/gate.js +17 -0
  3. package/dist/commands/gate.js.map +1 -1
  4. package/dist/commands/status.d.ts.map +1 -1
  5. package/dist/commands/status.js +30 -2
  6. package/dist/commands/status.js.map +1 -1
  7. package/dist/commands/transition.d.ts.map +1 -1
  8. package/dist/commands/transition.js +21 -0
  9. package/dist/commands/transition.js.map +1 -1
  10. package/dist/core/gate.d.ts +7 -0
  11. package/dist/core/gate.d.ts.map +1 -1
  12. package/dist/core/gate.js.map +1 -1
  13. package/dist/core/types.d.ts +10 -1
  14. package/dist/core/types.d.ts.map +1 -1
  15. package/dist/traceability/cache.d.ts +21 -0
  16. package/dist/traceability/cache.d.ts.map +1 -0
  17. package/dist/traceability/cache.js +106 -0
  18. package/dist/traceability/cache.js.map +1 -0
  19. package/dist/traceability/coverage-block.d.ts +21 -0
  20. package/dist/traceability/coverage-block.d.ts.map +1 -0
  21. package/dist/traceability/coverage-block.js +41 -0
  22. package/dist/traceability/coverage-block.js.map +1 -0
  23. package/dist/traceability/gate-criterion.d.ts +34 -0
  24. package/dist/traceability/gate-criterion.d.ts.map +1 -0
  25. package/dist/traceability/gate-criterion.js +128 -0
  26. package/dist/traceability/gate-criterion.js.map +1 -0
  27. package/dist/traceability/matrix.d.ts +35 -0
  28. package/dist/traceability/matrix.d.ts.map +1 -0
  29. package/dist/traceability/matrix.js +93 -0
  30. package/dist/traceability/matrix.js.map +1 -0
  31. package/dist/traceability/parser.d.ts +27 -0
  32. package/dist/traceability/parser.d.ts.map +1 -0
  33. package/dist/traceability/parser.js +101 -0
  34. package/dist/traceability/parser.js.map +1 -0
  35. package/dist/traceability/scanner.d.ts +62 -0
  36. package/dist/traceability/scanner.d.ts.map +1 -0
  37. package/dist/traceability/scanner.js +198 -0
  38. package/dist/traceability/scanner.js.map +1 -0
  39. package/dist/traceability/types.d.ts +77 -0
  40. package/dist/traceability/types.d.ts.map +1 -0
  41. package/dist/traceability/types.js +8 -0
  42. package/dist/traceability/types.js.map +1 -0
  43. package/package.json +2 -2
  44. package/dist/commands/setup.d.ts +0 -24
  45. package/dist/commands/setup.d.ts.map +0 -1
  46. package/dist/commands/setup.js +0 -262
  47. package/dist/commands/setup.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Traceability gate criterion (FR4): computed live at the command layer
3
+ * after `evaluateGate`, following the knowledge-criterion precedent — it
4
+ * therefore evaluates even when phase state is `complete` (AC-11) and never
5
+ * touches `evaluateGate`'s contract (DD1).
6
+ *
7
+ * Applicability tri-state (DD7):
8
+ * null phase ≠ testing, phase-testing.yaml absent, or
9
+ * zero AC-shaped lines (AC-3, AC-13)
10
+ * result, empty entries only near-misses — warnings surface (AC-22)
11
+ * result with entries ≥1 valid definition — full evaluation
12
+ *
13
+ * Requirements: traceability-ids/AC-3, AC-11..AC-15
14
+ */
15
+ import type { ParsedRequirements, TraceabilityConfig, TraceabilityResult } from './types.js';
16
+ /** Message template callers use for unsatisfied criteria / violations. */
17
+ export declare function uncoveredMessage(acId: number): string;
18
+ /** Tolerant reader for the optional `traceability:` config section (AC-7). */
19
+ export declare function loadTraceabilityConfig(projectRoot: string): TraceabilityConfig | null;
20
+ /**
21
+ * Parse every instance's requirements.md — the registry backing the bare-
22
+ * reference uniqueness rule (AC-24, D5). Reads by explicit path; the
23
+ * scanner's `.aidlc` exclusion governs test discovery only.
24
+ */
25
+ export declare function loadRegistry(projectRoot: string): Map<string, ParsedRequirements>;
26
+ /**
27
+ * Evaluate the traceability criterion for one instance.
28
+ *
29
+ * @returns null when the criterion does not evaluate (AC-3, AC-13); otherwise
30
+ * a result whose `uncoveredActive` entries the caller turns into
31
+ * unsatisfied criteria / gate violations via {@link uncoveredMessage}.
32
+ */
33
+ export declare function evaluateTraceabilityCriterion(projectRoot: string, instanceName: string, phaseName: string): TraceabilityResult | null;
34
+ //# sourceMappingURL=gate-criterion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-criterion.d.ts","sourceRoot":"","sources":["../../src/traceability/gate-criterion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAM7F,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,8EAA8E;AAC9E,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAarF;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAkBjF;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,kBAAkB,GAAG,IAAI,CAuD3B"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Traceability gate criterion (FR4): computed live at the command layer
3
+ * after `evaluateGate`, following the knowledge-criterion precedent — it
4
+ * therefore evaluates even when phase state is `complete` (AC-11) and never
5
+ * touches `evaluateGate`'s contract (DD1).
6
+ *
7
+ * Applicability tri-state (DD7):
8
+ * null phase ≠ testing, phase-testing.yaml absent, or
9
+ * zero AC-shaped lines (AC-3, AC-13)
10
+ * result, empty entries only near-misses — warnings surface (AC-22)
11
+ * result with entries ≥1 valid definition — full evaluation
12
+ *
13
+ * Requirements: traceability-ids/AC-3, AC-11..AC-15
14
+ */
15
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
16
+ import { join } from 'node:path';
17
+ import { parse as parseYaml } from 'yaml';
18
+ import { parseRequirements } from './parser.js';
19
+ import { DEFAULT_TEST_GLOBS, discoverTestFiles, scanFiles } from './scanner.js';
20
+ import { parseCoverageBlock } from './coverage-block.js';
21
+ import { buildMatrix } from './matrix.js';
22
+ /** Message template callers use for unsatisfied criteria / violations. */
23
+ export function uncoveredMessage(acId) {
24
+ return `acceptance criterion AC-${acId} has no referencing test (traceability)`;
25
+ }
26
+ /** Tolerant reader for the optional `traceability:` config section (AC-7). */
27
+ export function loadTraceabilityConfig(projectRoot) {
28
+ const configPath = join(projectRoot, '.aidlc', 'config.yaml');
29
+ try {
30
+ if (!existsSync(configPath))
31
+ return null;
32
+ const config = parseYaml(readFileSync(configPath, 'utf8'));
33
+ const section = config?.traceability;
34
+ if (typeof section !== 'object' || section === null)
35
+ return null;
36
+ const globs = section.test_globs;
37
+ if (!Array.isArray(globs) || !globs.every((g) => typeof g === 'string'))
38
+ return {};
39
+ return { test_globs: globs };
40
+ }
41
+ catch {
42
+ return null;
43
+ }
44
+ }
45
+ /**
46
+ * Parse every instance's requirements.md — the registry backing the bare-
47
+ * reference uniqueness rule (AC-24, D5). Reads by explicit path; the
48
+ * scanner's `.aidlc` exclusion governs test discovery only.
49
+ */
50
+ export function loadRegistry(projectRoot) {
51
+ const registry = new Map();
52
+ const stateDir = join(projectRoot, '.aidlc', 'state');
53
+ let instances;
54
+ try {
55
+ instances = readdirSync(stateDir);
56
+ }
57
+ catch {
58
+ return registry;
59
+ }
60
+ for (const name of instances.sort()) {
61
+ const reqPath = join(stateDir, name, 'requirements.md');
62
+ try {
63
+ registry.set(name, parseRequirements(readFileSync(reqPath, 'utf8'), name));
64
+ }
65
+ catch {
66
+ // No requirements.md — not an AC-bearing instance.
67
+ }
68
+ }
69
+ return registry;
70
+ }
71
+ /**
72
+ * Evaluate the traceability criterion for one instance.
73
+ *
74
+ * @returns null when the criterion does not evaluate (AC-3, AC-13); otherwise
75
+ * a result whose `uncoveredActive` entries the caller turns into
76
+ * unsatisfied criteria / gate violations via {@link uncoveredMessage}.
77
+ */
78
+ export function evaluateTraceabilityCriterion(projectRoot, instanceName, phaseName) {
79
+ if (phaseName !== 'testing')
80
+ return null;
81
+ const instanceDir = join(projectRoot, '.aidlc', 'state', instanceName);
82
+ if (!existsSync(join(instanceDir, 'phase-testing.yaml')))
83
+ return null;
84
+ const registry = loadRegistry(projectRoot);
85
+ const parsed = registry.get(instanceName);
86
+ if (!parsed || parsed.acShapedLines === 0)
87
+ return null;
88
+ const requirementsPath = `.aidlc/state/${instanceName}/requirements.md`;
89
+ const testingPath = `.aidlc/state/${instanceName}/testing.md`;
90
+ // Warnings ordered by phase: parse → glob/discovery → scan → block → matrix
91
+ // (NFR4). Registry parse warnings are scoped to the target instance only.
92
+ const warnings = [...parsed.warnings];
93
+ if (parsed.defs.length === 0) {
94
+ // Tri-state case 2: every criterion is a near-miss — visible, not silent.
95
+ return { requirementsPath, entries: [], warnings, uncoveredActive: [] };
96
+ }
97
+ const config = loadTraceabilityConfig(projectRoot);
98
+ const globs = config?.test_globs ?? DEFAULT_TEST_GLOBS;
99
+ const discovery = discoverTestFiles(projectRoot, globs);
100
+ warnings.push(...discovery.warnings);
101
+ const scan = scanFiles(projectRoot, discovery.files);
102
+ warnings.push(...scan.warnings);
103
+ let blockEntries = [];
104
+ try {
105
+ const block = parseCoverageBlock(readFileSync(join(instanceDir, 'testing.md'), 'utf8'));
106
+ blockEntries = block.entries;
107
+ warnings.push(...block.warnings);
108
+ }
109
+ catch {
110
+ // No testing.md yet — scan-only coverage.
111
+ }
112
+ const matrix = buildMatrix({
113
+ instance: instanceName,
114
+ parsed,
115
+ registry,
116
+ refs: scan.refs,
117
+ blockEntries,
118
+ testingPath,
119
+ });
120
+ warnings.push(...matrix.warnings);
121
+ return {
122
+ requirementsPath,
123
+ entries: matrix.entries,
124
+ warnings,
125
+ uncoveredActive: matrix.uncoveredActive,
126
+ };
127
+ }
128
+ //# sourceMappingURL=gate-criterion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-criterion.js","sourceRoot":"","sources":["../../src/traceability/gate-criterion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Coverage matrix builder: resolves references against the cross-instance
3
+ * registry (uniqueness rule, D5) and unions scan ∪ block coverage per AC.
4
+ *
5
+ * Bare `AC-n` counts only when exactly one AC-bearing instance defines id n
6
+ * (AC-24); qualified `<instance>/AC-n` always resolves to that instance
7
+ * (AC-25). Retired ACs never require coverage; references to them warn
8
+ * (AC-14). Only `uncoveredActive` fails gates — warnings are data (DD6).
9
+ *
10
+ * Requirements: traceability-ids/AC-9..AC-15, AC-24, AC-25
11
+ */
12
+ import type { AcCoverageEntry, AcReference, ParsedRequirements } from './types.js';
13
+ import type { CoverageBlockEntry } from './coverage-block.js';
14
+ export interface MatrixInput {
15
+ /** Target instance name. */
16
+ instance: string;
17
+ /** Target instance's parsed requirements. */
18
+ parsed: ParsedRequirements;
19
+ /** All instances' parsed requirements (registry, keyed by instance). */
20
+ registry: Map<string, ParsedRequirements>;
21
+ /** Scanned references from test files. */
22
+ refs: AcReference[];
23
+ /** Entries from the target instance's ac-coverage block. */
24
+ blockEntries: CoverageBlockEntry[];
25
+ /** Posix-relative path of the target instance's testing.md. */
26
+ testingPath: string;
27
+ }
28
+ export interface MatrixOutput {
29
+ entries: AcCoverageEntry[];
30
+ warnings: string[];
31
+ uncoveredActive: number[];
32
+ }
33
+ /** Build the coverage matrix for one instance. */
34
+ export declare function buildMatrix(input: MatrixInput): MatrixOutput;
35
+ //# sourceMappingURL=matrix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix.d.ts","sourceRoot":"","sources":["../../src/traceability/matrix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,eAAe,EAEf,WAAW,EACX,kBAAkB,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC1C,0CAA0C;IAC1C,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,4DAA4D;IAC5D,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAWD,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,CA+E5D"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Coverage matrix builder: resolves references against the cross-instance
3
+ * registry (uniqueness rule, D5) and unions scan ∪ block coverage per AC.
4
+ *
5
+ * Bare `AC-n` counts only when exactly one AC-bearing instance defines id n
6
+ * (AC-24); qualified `<instance>/AC-n` always resolves to that instance
7
+ * (AC-25). Retired ACs never require coverage; references to them warn
8
+ * (AC-14). Only `uncoveredActive` fails gates — warnings are data (DD6).
9
+ *
10
+ * Requirements: traceability-ids/AC-9..AC-15, AC-24, AC-25
11
+ */
12
+ /** Instances (other than possibly the target) defining a given AC id. */
13
+ function definersOf(registry, acId) {
14
+ const definers = [];
15
+ for (const [name, parsed] of registry) {
16
+ if (parsed.defs.some((d) => d.id === acId))
17
+ definers.push(name);
18
+ }
19
+ return definers.sort();
20
+ }
21
+ /** Build the coverage matrix for one instance. */
22
+ export function buildMatrix(input) {
23
+ const { instance, parsed, registry, refs, blockEntries, testingPath } = input;
24
+ const warnings = [];
25
+ const byId = new Map(parsed.defs.map((d) => [d.id, d]));
26
+ const coverage = new Map();
27
+ const addRef = (acId, path, source) => {
28
+ let paths = coverage.get(acId);
29
+ if (!paths)
30
+ coverage.set(acId, (paths = new Map()));
31
+ if (!paths.has(path))
32
+ paths.set(path, source);
33
+ };
34
+ // Resolve scanned references.
35
+ for (const ref of refs) {
36
+ if (ref.instance !== null) {
37
+ // Qualified (AC-25): counts only for the named instance.
38
+ const target = registry.get(ref.instance);
39
+ if (!target || !target.defs.some((d) => d.id === ref.acId)) {
40
+ warnings.push(`${ref.path}:${ref.line}: ${ref.instance}/AC-${ref.acId} references unknown instance/id`);
41
+ continue;
42
+ }
43
+ if (ref.instance !== instance)
44
+ continue; // another instance's coverage
45
+ }
46
+ else {
47
+ // Bare (AC-24): counts only when exactly one instance defines the id.
48
+ const definers = definersOf(registry, ref.acId);
49
+ if (definers.length === 0)
50
+ continue; // unknown id — not ours to warn about
51
+ if (definers.length > 1) {
52
+ warnings.push(`${ref.path}:${ref.line}: bare AC-${ref.acId} is ambiguous (defined by ${definers.join(', ')}); qualify as <instance>/AC-${ref.acId}`);
53
+ continue;
54
+ }
55
+ if (definers[0] !== instance)
56
+ continue;
57
+ }
58
+ const def = byId.get(ref.acId);
59
+ if (def?.status === 'retired') {
60
+ warnings.push(`${ref.path}:${ref.line}: AC-${ref.acId} is retired (stale reference)`);
61
+ }
62
+ addRef(ref.acId, ref.path, 'scan');
63
+ }
64
+ // Union in block entries (AC-9); unknown/retired ids warn, never fail (AC-10).
65
+ for (const entry of blockEntries) {
66
+ const def = byId.get(entry.acId);
67
+ if (!def) {
68
+ warnings.push(`${testingPath}:${entry.line}: ac-coverage entry AC-${entry.acId} references unknown id`);
69
+ continue;
70
+ }
71
+ if (def.status === 'retired') {
72
+ warnings.push(`${testingPath}:${entry.line}: ac-coverage entry AC-${entry.acId} is retired (stale reference)`);
73
+ continue;
74
+ }
75
+ addRef(entry.acId, testingPath, 'block');
76
+ }
77
+ // Assemble entries sorted by id; refs sorted by path (NFR4).
78
+ const entries = [...parsed.defs]
79
+ .sort((a, b) => a.id - b.id)
80
+ .map((def) => {
81
+ const paths = coverage.get(def.id);
82
+ const refList = paths
83
+ ? [...paths.entries()]
84
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
85
+ .map(([path, source]) => ({ path, source }))
86
+ : [];
87
+ const status = def.status === 'retired' ? 'retired' : refList.length > 0 ? 'covered' : 'uncovered';
88
+ return { id: def.id, status, refs: refList };
89
+ });
90
+ const uncoveredActive = entries.filter((e) => e.status === 'uncovered').map((e) => e.id);
91
+ return { entries, warnings, uncoveredActive };
92
+ }
93
+ //# sourceMappingURL=matrix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matrix.js","sourceRoot":"","sources":["../../src/traceability/matrix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * AC definition parser: closed grammar over requirements.md (FR1).
3
+ *
4
+ * Accepted forms (dash bullets only; emphasis coupled — unbalanced bold is a
5
+ * near-miss, AC-22/design F13):
6
+ * - AC-n: text
7
+ * - **AC-n**: text
8
+ * - **AC-n:** text
9
+ * - AC-n (retired YYYY-MM-DD[, superseded by AC-m]): text
10
+ * - **AC-n** (retired ...): text
11
+ * - **AC-n (retired ...):** text
12
+ * - **AC-n (retired ...)**: text
13
+ *
14
+ * Anything AC-shaped that fails the strict grammar warns rather than silently
15
+ * dropping out of required coverage (AC-22).
16
+ *
17
+ * Requirements: traceability-ids/AC-1, AC-2, AC-4, AC-22, AC-23
18
+ */
19
+ import type { ParsedRequirements } from './types.js';
20
+ /**
21
+ * Parse one requirements.md for AC definitions.
22
+ *
23
+ * @param content - File content (UTF-8).
24
+ * @param instance - Owning instance name, recorded on each definition.
25
+ */
26
+ export declare function parseRequirements(content: string, instance: string): ParsedRequirements;
27
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/traceability/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAgB,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA0BnE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAiEvF"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * AC definition parser: closed grammar over requirements.md (FR1).
3
+ *
4
+ * Accepted forms (dash bullets only; emphasis coupled — unbalanced bold is a
5
+ * near-miss, AC-22/design F13):
6
+ * - AC-n: text
7
+ * - **AC-n**: text
8
+ * - **AC-n:** text
9
+ * - AC-n (retired YYYY-MM-DD[, superseded by AC-m]): text
10
+ * - **AC-n** (retired ...): text
11
+ * - **AC-n (retired ...):** text
12
+ * - **AC-n (retired ...)**: text
13
+ *
14
+ * Anything AC-shaped that fails the strict grammar warns rather than silently
15
+ * dropping out of required coverage (AC-22).
16
+ *
17
+ * Requirements: traceability-ids/AC-1, AC-2, AC-4, AC-22, AC-23
18
+ */
19
+ // Active: the three bold/colon variants, coupled emphasis, non-empty text.
20
+ const ACTIVE_RE = /^\s*-\s+(?:AC-([1-9][0-9]*):|\*\*AC-([1-9][0-9]*)\*\*:|\*\*AC-([1-9][0-9]*):\*\*)\s+\S/;
21
+ // Retired: `R` = retired marker with optional supersession.
22
+ const R = String.raw `\(retired\s+(\d{4}-\d{2}-\d{2})(?:,\s*superseded by AC-([1-9][0-9]*))?\)`;
23
+ const RETIRED_RE = new RegExp(String.raw `^\s*-\s+(?:` +
24
+ String.raw `AC-([1-9][0-9]*)\s+${R}:|` +
25
+ String.raw `\*\*AC-([1-9][0-9]*)\*\*\s+${R}:|` +
26
+ String.raw `\*\*AC-([1-9][0-9]*)\s+${R}:\*\*|` +
27
+ String.raw `\*\*AC-([1-9][0-9]*)\s+${R}\*\*:` +
28
+ String.raw `)`);
29
+ // Loose pattern for the near-miss lint (AC-22): any bullet style, so `*`/`+`
30
+ // bullets and numbered items warn instead of vanishing (design F13).
31
+ const AC_SHAPED_RE = /^\s*(?:[-*+]|\d+\.)\s+\**AC-\d+/;
32
+ function excerpt(line) {
33
+ const trimmed = line.trim();
34
+ return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed;
35
+ }
36
+ /**
37
+ * Parse one requirements.md for AC definitions.
38
+ *
39
+ * @param content - File content (UTF-8).
40
+ * @param instance - Owning instance name, recorded on each definition.
41
+ */
42
+ export function parseRequirements(content, instance) {
43
+ const defs = [];
44
+ const warnings = [];
45
+ const byId = new Map();
46
+ let acShapedLines = 0;
47
+ const lines = content.split('\n');
48
+ for (let i = 0; i < lines.length; i++) {
49
+ const line = lines[i];
50
+ const lineNo = i + 1;
51
+ if (!AC_SHAPED_RE.test(line))
52
+ continue;
53
+ acShapedLines++;
54
+ let def = null;
55
+ const active = ACTIVE_RE.exec(line);
56
+ if (active) {
57
+ const id = Number(active[1] ?? active[2] ?? active[3]);
58
+ def = { id, instance, line: lineNo, status: 'active' };
59
+ }
60
+ else {
61
+ const retired = RETIRED_RE.exec(line);
62
+ if (retired) {
63
+ // Four alternatives × (id, date, supersededBy) capture triplets.
64
+ for (let g = 1; g <= 10; g += 3) {
65
+ if (retired[g] !== undefined) {
66
+ def = {
67
+ id: Number(retired[g]),
68
+ instance,
69
+ line: lineNo,
70
+ status: 'retired',
71
+ retiredDate: retired[g + 1],
72
+ ...(retired[g + 2] !== undefined && { supersededBy: Number(retired[g + 2]) }),
73
+ };
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ }
79
+ if (!def) {
80
+ warnings.push(`line ${lineNo}: "${excerpt(line)}" resembles an AC definition but does not match the grammar`);
81
+ continue;
82
+ }
83
+ const existing = byId.get(def.id);
84
+ if (existing) {
85
+ warnings.push(`duplicate AC-${def.id}: lines ${existing.line} and ${lineNo} (first occurrence wins)`);
86
+ continue;
87
+ }
88
+ byId.set(def.id, def);
89
+ defs.push(def);
90
+ }
91
+ // Sequence gaps (AC-23), computed over active ∪ retired ids.
92
+ if (byId.size > 0) {
93
+ const maxId = Math.max(...byId.keys());
94
+ for (let n = 1; n <= maxId; n++) {
95
+ if (!byId.has(n))
96
+ warnings.push(`AC-${n} is never defined (sequence gap)`);
97
+ }
98
+ }
99
+ return { defs, warnings, acShapedLines };
100
+ }
101
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/traceability/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Test-file discovery and AC-reference scanning (FR2).
3
+ *
4
+ * Own walker + glob translator instead of `fs.globSync`: stdlib glob
5
+ * semantics are release-dependent while the Node floor is 22.13; the pinned
6
+ * semantics here are enforced by this module's tests (NFR1, design DD2).
7
+ *
8
+ * Pinned semantics (design Data Flow 4):
9
+ * - `**` matches zero or more path segments
10
+ * - `*` / `?` match within a segment, never a leading dot
11
+ * - dot-files and dot-directories are never traversed
12
+ * - exclusions (node_modules, .git, dist, build, .aidlc) prune before
13
+ * descent at any depth, regardless of glob source (AC-6/AC-7, DD4)
14
+ * - symlinks are never followed (AC-8, NFR3)
15
+ * - emitted paths are posix-separated and project-root-relative (design F7)
16
+ *
17
+ * Requirements: traceability-ids/AC-5..AC-8, AC-24, AC-25
18
+ */
19
+ import type { AcReference } from './types.js';
20
+ /** D1 default test globs. */
21
+ export declare const DEFAULT_TEST_GLOBS: string[];
22
+ /** Scan caps (NFR2, AC-8). */
23
+ export declare const MAX_SCANNED_FILES = 10000;
24
+ /**
25
+ * Translate one glob into a RegExp over posix relative paths, or null when
26
+ * the pattern uses unsupported syntax (braces, extglobs, character classes).
27
+ */
28
+ export declare function translateGlob(pattern: string): RegExp | null;
29
+ /**
30
+ * Validate configured globs (AC-7): absolute or `..`-containing patterns and
31
+ * unsupported syntax are rejected with a warning naming the glob.
32
+ */
33
+ export declare function validateGlobs(patterns: string[]): {
34
+ matchers: RegExp[];
35
+ warnings: string[];
36
+ };
37
+ export interface DiscoveryResult {
38
+ /** Posix-separated project-root-relative paths, sorted. */
39
+ files: string[];
40
+ warnings: string[];
41
+ }
42
+ /**
43
+ * Discover test files by glob against the project root.
44
+ *
45
+ * @param projectRoot - Directory containing `.aidlc/`.
46
+ * @param globs - Effective glob list (defaults or config).
47
+ */
48
+ export declare function discoverTestFiles(projectRoot: string, globs: string[]): DiscoveryResult;
49
+ export interface ScanResult {
50
+ refs: AcReference[];
51
+ warnings: string[];
52
+ }
53
+ /** Scan one file's content for AC reference tokens (qualified, then bare). */
54
+ export declare function scanContent(content: string, path: string): AcReference[];
55
+ /**
56
+ * Scan discovered files, skipping unreadable/oversize/binary files with a
57
+ * warning (AC-8). Never throws.
58
+ */
59
+ export declare function scanFiles(projectRoot: string, files: string[]): ScanResult;
60
+ /** Convert a native relative path to the canonical posix form (design F7). */
61
+ export declare function toPosix(relPath: string): string;
62
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/traceability/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,6BAA6B;AAC7B,eAAO,MAAM,kBAAkB,UAA8D,CAAC;AAK9F,8BAA8B;AAC9B,eAAO,MAAM,iBAAiB,QAAS,CAAC;AAgBxC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyB5D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAoB5F;AAMD,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAsBD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,eAAe,CAYvF;AAMD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAexE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CA8B1E;AAED,8EAA8E;AAC9E,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/C"}