spec-manager 0.1.1 → 0.2.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 (85) hide show
  1. package/README.md +58 -7
  2. package/dist/cli/change.d.ts.map +1 -1
  3. package/dist/cli/change.js +93 -4
  4. package/dist/cli/change.js.map +1 -1
  5. package/dist/cli/project.d.ts.map +1 -1
  6. package/dist/cli/project.js +50 -0
  7. package/dist/cli/project.js.map +1 -1
  8. package/dist/cli/task.d.ts.map +1 -1
  9. package/dist/cli/task.js +146 -41
  10. package/dist/cli/task.js.map +1 -1
  11. package/dist/core/agents.d.ts +17 -0
  12. package/dist/core/agents.d.ts.map +1 -1
  13. package/dist/core/agents.js +43 -1
  14. package/dist/core/agents.js.map +1 -1
  15. package/dist/core/archive.d.ts.map +1 -1
  16. package/dist/core/archive.js +74 -2
  17. package/dist/core/archive.js.map +1 -1
  18. package/dist/core/audit.d.ts +1 -0
  19. package/dist/core/audit.d.ts.map +1 -1
  20. package/dist/core/audit.js +60 -40
  21. package/dist/core/audit.js.map +1 -1
  22. package/dist/core/completion.js +1 -1
  23. package/dist/core/completion.js.map +1 -1
  24. package/dist/core/delta.d.ts +30 -1
  25. package/dist/core/delta.d.ts.map +1 -1
  26. package/dist/core/delta.js +141 -4
  27. package/dist/core/delta.js.map +1 -1
  28. package/dist/core/harness.d.ts +69 -0
  29. package/dist/core/harness.d.ts.map +1 -0
  30. package/dist/core/harness.js +278 -0
  31. package/dist/core/harness.js.map +1 -0
  32. package/dist/core/integrity-exemptions.d.ts +29 -0
  33. package/dist/core/integrity-exemptions.d.ts.map +1 -0
  34. package/dist/core/integrity-exemptions.js +100 -0
  35. package/dist/core/integrity-exemptions.js.map +1 -0
  36. package/dist/core/integrity.d.ts +12 -0
  37. package/dist/core/integrity.d.ts.map +1 -0
  38. package/dist/core/integrity.js +163 -0
  39. package/dist/core/integrity.js.map +1 -0
  40. package/dist/core/invariants.d.ts +5 -0
  41. package/dist/core/invariants.d.ts.map +1 -0
  42. package/dist/core/invariants.js +19 -0
  43. package/dist/core/invariants.js.map +1 -0
  44. package/dist/core/lifecycle.d.ts +37 -0
  45. package/dist/core/lifecycle.d.ts.map +1 -0
  46. package/dist/core/lifecycle.js +70 -0
  47. package/dist/core/lifecycle.js.map +1 -0
  48. package/dist/core/paths.d.ts +3 -0
  49. package/dist/core/paths.d.ts.map +1 -1
  50. package/dist/core/paths.js +19 -1
  51. package/dist/core/paths.js.map +1 -1
  52. package/dist/core/reconciliation.d.ts +25 -0
  53. package/dist/core/reconciliation.d.ts.map +1 -0
  54. package/dist/core/reconciliation.js +122 -0
  55. package/dist/core/reconciliation.js.map +1 -0
  56. package/dist/core/remediation.d.ts +41 -0
  57. package/dist/core/remediation.d.ts.map +1 -0
  58. package/dist/core/remediation.js +169 -0
  59. package/dist/core/remediation.js.map +1 -0
  60. package/dist/core/spec-io.d.ts +2 -0
  61. package/dist/core/spec-io.d.ts.map +1 -1
  62. package/dist/core/spec-io.js +23 -2
  63. package/dist/core/spec-io.js.map +1 -1
  64. package/dist/core/status.d.ts +2 -0
  65. package/dist/core/status.d.ts.map +1 -1
  66. package/dist/core/status.js +7 -0
  67. package/dist/core/status.js.map +1 -1
  68. package/dist/core/task.d.ts +24 -0
  69. package/dist/core/task.d.ts.map +1 -1
  70. package/dist/core/task.js +62 -43
  71. package/dist/core/task.js.map +1 -1
  72. package/dist/core/transaction.d.ts +10 -0
  73. package/dist/core/transaction.d.ts.map +1 -0
  74. package/dist/core/transaction.js +65 -0
  75. package/dist/core/transaction.js.map +1 -0
  76. package/dist/core/usability.d.ts.map +1 -1
  77. package/dist/core/usability.js +50 -13
  78. package/dist/core/usability.js.map +1 -1
  79. package/dist/index.d.ts +7 -0
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +7 -0
  82. package/dist/index.js.map +1 -1
  83. package/dist/schemas/change.d.ts +20 -20
  84. package/dist/schemas/spec.d.ts +12 -12
  85. package/package.json +1 -1
@@ -0,0 +1,278 @@
1
+ import { listDecisions } from './decision.js';
2
+ import { findSpecByCode, listAllSpecs } from './spec-io.js';
3
+ import { addTaskVerification, reportStep, showTask } from './task.js';
4
+ export function buildHarnessTaskContext(paths, l3Code) {
5
+ const spec = findSpecByCode(paths, l3Code);
6
+ if (!spec)
7
+ throw new Error(`SPEC_NOT_FOUND: ${l3Code}`);
8
+ if (spec.fm.level !== 'L3')
9
+ throw new Error(`SPEC_NOT_L3: ${l3Code}`);
10
+ if (spec.fm.status !== 'frozen' && spec.fm.status !== 'implemented') {
11
+ throw new Error(`L3_NOT_FROZEN: ${l3Code} status=${spec.fm.status}`);
12
+ }
13
+ const warnings = [];
14
+ collectParentWarnings(paths, spec, warnings);
15
+ const acceptanceCriteria = extractListSection(spec.content, '验收标准');
16
+ if (acceptanceCriteria.length === 0) {
17
+ warnings.push('acceptanceCriteria empty: no items extracted from ## 验收标准');
18
+ }
19
+ const suggestedVerification = extractVerificationCommands(spec.content);
20
+ if (suggestedVerification.length === 0) {
21
+ warnings.push('suggestedVerification empty: no commands extracted from ## 验证命令');
22
+ }
23
+ const decisions = listDecisions(paths, { topic: spec.fm.topic }).map(d => ({
24
+ code: d.id,
25
+ title: d.fm.what,
26
+ summary: d.fm.why ?? d.fm.what,
27
+ }));
28
+ return {
29
+ schemaVersion: 'harness-context.experimental.v1',
30
+ specCode: spec.fm.code,
31
+ topic: spec.fm.topic,
32
+ title: spec.fm.title,
33
+ statusGate: {
34
+ level: spec.fm.level,
35
+ status: spec.fm.status,
36
+ allowed: true,
37
+ },
38
+ summary: spec.fm.aiSummary?.trim() || spec.fm.title,
39
+ objectives: extractObjectives(spec.content),
40
+ nonGoals: extractNonGoals(spec.content),
41
+ acceptanceCriteria,
42
+ decisions,
43
+ suggestedVerification,
44
+ nextCommands: [`spec-manager task create ${spec.fm.code} --plan ./plan.json`],
45
+ warnings,
46
+ };
47
+ }
48
+ export function normalizeHarnessTaskReportPayload(raw) {
49
+ if (!isRecord(raw))
50
+ throw new Error('INVALID_REPORT: payload must be an object');
51
+ const summary = raw.summary;
52
+ if (typeof summary !== 'string' || summary.trim().length === 0) {
53
+ throw new Error('INVALID_REPORT: summary must be a non-empty string');
54
+ }
55
+ const stepNo = raw.stepNo;
56
+ if (stepNo !== undefined && !isValidStepNo(stepNo)) {
57
+ throw new Error('INVALID_REPORT: stepNo must be a non-empty string or number');
58
+ }
59
+ return {
60
+ summary: summary.trim(),
61
+ ...(stepNo !== undefined ? { stepNo } : {}),
62
+ files: normalizeStringArray(raw.files, 'files', 'INVALID_REPORT'),
63
+ tests: normalizeStringArray(raw.tests, 'tests', 'INVALID_REPORT'),
64
+ risks: normalizeStringArray(raw.risks, 'risks', 'INVALID_REPORT'),
65
+ };
66
+ }
67
+ export function reportHarnessTaskStep(input) {
68
+ const shown = showTask(input.paths, input.taskId, { full: true, specCode: input.specCode });
69
+ if (!shown)
70
+ throw new Error(`TASK_NOT_FOUND: ${input.taskId}`);
71
+ const stepNo = input.payload.stepNo ?? nextReportableStepNo(input.taskId, shown.steps);
72
+ const outputJson = JSON.stringify({
73
+ summary: input.payload.summary,
74
+ files: input.payload.files ?? [],
75
+ tests: input.payload.tests ?? [],
76
+ risks: input.payload.risks ?? [],
77
+ });
78
+ const result = reportStep({
79
+ paths: input.paths,
80
+ taskId: input.taskId,
81
+ specCode: input.specCode,
82
+ stepNo,
83
+ status: 'succeeded',
84
+ outputJson,
85
+ });
86
+ return { task: result.task, stepNo, warnings: result.warnings };
87
+ }
88
+ export function normalizeHarnessTaskVerificationPayload(raw) {
89
+ if (!isRecord(raw))
90
+ throw new Error('INVALID_VERIFICATION: payload must be an object');
91
+ const command = raw.command;
92
+ if (typeof command !== 'string' || command.trim().length === 0) {
93
+ throw new Error('INVALID_VERIFICATION: command must be a non-empty string');
94
+ }
95
+ const exitCode = raw.exitCode;
96
+ if (typeof exitCode !== 'number' || !Number.isFinite(exitCode)) {
97
+ throw new Error('INVALID_VERIFICATION: exitCode must be a finite number');
98
+ }
99
+ const summary = raw.summary;
100
+ if (typeof summary !== 'string' || summary.trim().length === 0) {
101
+ throw new Error('INVALID_VERIFICATION: summary must be a non-empty string');
102
+ }
103
+ return {
104
+ command: command.trim(),
105
+ exitCode,
106
+ summary: summary.trim(),
107
+ artifacts: normalizeStringArray(raw.artifacts, 'artifacts', 'INVALID_VERIFICATION'),
108
+ coversAc: normalizeStringArray(raw.coversAc, 'coversAc', 'INVALID_VERIFICATION'),
109
+ };
110
+ }
111
+ export function recordHarnessTaskVerification(input) {
112
+ const payload = normalizeHarnessTaskVerificationPayload(input.payload);
113
+ return addTaskVerification({
114
+ paths: input.paths,
115
+ taskId: input.taskId,
116
+ specCode: input.specCode,
117
+ command: payload.command,
118
+ exitCode: payload.exitCode,
119
+ summary: payload.summary,
120
+ artifacts: payload.artifacts ?? [],
121
+ coversAc: payload.coversAc ?? [],
122
+ });
123
+ }
124
+ export function renderHarnessTaskContextText(context) {
125
+ const lines = [];
126
+ lines.push(`Task Context: ${context.specCode}`);
127
+ lines.push(`Title: ${context.title}`);
128
+ lines.push('');
129
+ lines.push(`Status Gate: ${context.statusGate.level} ${context.statusGate.status}, implementation ${context.statusGate.allowed ? 'allowed' : 'blocked'}`);
130
+ if (context.statusGate.reason)
131
+ lines.push(`Reason: ${context.statusGate.reason}`);
132
+ lines.push('');
133
+ lines.push('Summary:');
134
+ lines.push(context.summary || '(none)');
135
+ lines.push('');
136
+ pushList(lines, 'Objectives', context.objectives);
137
+ pushList(lines, 'Non Goals', context.nonGoals);
138
+ pushList(lines, 'Acceptance Criteria', context.acceptanceCriteria);
139
+ pushList(lines, 'Decisions', context.decisions.map(d => `${d.code ? `${d.code}: ` : ''}${d.title}${d.summary && d.summary !== d.title ? ` — ${d.summary}` : ''}`));
140
+ pushList(lines, 'Suggested Verification', context.suggestedVerification);
141
+ pushList(lines, 'Warnings', context.warnings);
142
+ pushList(lines, 'Next', context.nextCommands);
143
+ return `${lines.join('\n')}\n`;
144
+ }
145
+ function nextReportableStepNo(taskId, steps) {
146
+ const step = steps.find(s => s.status === 'pending' || s.status === 'running');
147
+ if (!step)
148
+ throw new Error(`NO_REPORTABLE_STEP: ${taskId}`);
149
+ return step.stepNo;
150
+ }
151
+ function isRecord(value) {
152
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
153
+ }
154
+ function isValidStepNo(value) {
155
+ return (typeof value === 'number' && Number.isFinite(value)) || (typeof value === 'string' && value.trim().length > 0);
156
+ }
157
+ function normalizeStringArray(value, field, errorCode) {
158
+ if (value === undefined)
159
+ return undefined;
160
+ if (!Array.isArray(value) || value.some(item => typeof item !== 'string')) {
161
+ throw new Error(`${errorCode}: ${field} must be a string array`);
162
+ }
163
+ return value.map(item => item.trim()).filter(Boolean);
164
+ }
165
+ function pushList(lines, title, items) {
166
+ lines.push(`${title}:`);
167
+ if (items.length === 0) {
168
+ lines.push('- (none)');
169
+ }
170
+ else {
171
+ for (const item of items)
172
+ lines.push(`- ${item}`);
173
+ }
174
+ lines.push('');
175
+ }
176
+ function collectParentWarnings(paths, spec, warnings) {
177
+ const all = listAllSpecs(paths);
178
+ let parentCode = spec.fm.parentCode;
179
+ while (parentCode) {
180
+ const parent = all.find(s => s.fm.code === parentCode);
181
+ if (!parent) {
182
+ warnings.push(`parent missing: ${parentCode}`);
183
+ return;
184
+ }
185
+ parentCode = parent.fm.parentCode;
186
+ }
187
+ }
188
+ function extractObjectives(content) {
189
+ const section = sectionBody(content, '目标');
190
+ const bullets = extractBullets(section).filter(line => !line.startsWith('前置依赖'));
191
+ if (bullets.length > 0)
192
+ return bullets;
193
+ const paragraph = firstParagraph(section);
194
+ return paragraph ? [paragraph] : [];
195
+ }
196
+ function extractNonGoals(content) {
197
+ const section = sectionBody(content, '范围边界');
198
+ if (!section)
199
+ return [];
200
+ const lines = section.split('\n');
201
+ const out = [];
202
+ let inNonGoals = false;
203
+ for (const raw of lines) {
204
+ const line = raw.trim();
205
+ if (/不做|显式排除/.test(line)) {
206
+ inNonGoals = true;
207
+ continue;
208
+ }
209
+ if (inNonGoals && /^-\s+\*\*/.test(line))
210
+ break;
211
+ if (inNonGoals) {
212
+ const item = normalizeListItem(line);
213
+ if (item)
214
+ out.push(item);
215
+ }
216
+ }
217
+ return out;
218
+ }
219
+ function extractListSection(content, heading) {
220
+ return extractBullets(sectionBody(content, heading));
221
+ }
222
+ function extractVerificationCommands(content) {
223
+ const section = sectionBody(content, '验证命令');
224
+ if (!section)
225
+ return [];
226
+ const commands = [];
227
+ const fenceRe = /```(?:bash|sh|shell)?\n([\s\S]*?)```/g;
228
+ let match;
229
+ while ((match = fenceRe.exec(section)) !== null) {
230
+ for (const raw of match[1].split('\n')) {
231
+ const line = raw.trim();
232
+ if (!line || line.startsWith('#'))
233
+ continue;
234
+ commands.push(line);
235
+ }
236
+ }
237
+ return commands;
238
+ }
239
+ function sectionBody(content, heading) {
240
+ const lines = content.split('\n');
241
+ const start = lines.findIndex(line => new RegExp(`^##\\s+${escapeRegExp(heading)}\\s*$`).test(line.trim()));
242
+ if (start < 0)
243
+ return '';
244
+ let end = lines.length;
245
+ for (let i = start + 1; i < lines.length; i += 1) {
246
+ if (/^##\s+/.test(lines[i])) {
247
+ end = i;
248
+ break;
249
+ }
250
+ }
251
+ return lines.slice(start + 1, end).join('\n').trim();
252
+ }
253
+ function extractBullets(section) {
254
+ const out = [];
255
+ for (const raw of section.split('\n')) {
256
+ const item = normalizeListItem(raw.trim());
257
+ if (item)
258
+ out.push(item);
259
+ }
260
+ return out;
261
+ }
262
+ function normalizeListItem(line) {
263
+ const match = line.match(/^(?:[-*]|\d+\.)\s+(.*)$/);
264
+ if (!match)
265
+ return null;
266
+ return match[1].trim();
267
+ }
268
+ function firstParagraph(section) {
269
+ const lines = section
270
+ .split('\n')
271
+ .map(line => line.trim())
272
+ .filter(line => line && !line.startsWith('#') && !line.startsWith('```') && !line.startsWith('**'));
273
+ return lines[0] ?? null;
274
+ }
275
+ function escapeRegExp(value) {
276
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
277
+ }
278
+ //# sourceMappingURL=harness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness.js","sourceRoot":"","sources":["../../src/core/harness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { ProjectPaths } from './paths.js';
2
+ export type IntegrityExemptionKind = 'legacy-missing-verification';
3
+ export interface IntegrityExemption {
4
+ id: string;
5
+ kind: IntegrityExemptionKind;
6
+ specCode: string;
7
+ taskId: string;
8
+ reason: string;
9
+ createdAt: string;
10
+ migrationId: string;
11
+ }
12
+ export interface IntegrityExemptionRegistry {
13
+ version: 1;
14
+ exemptions: IntegrityExemption[];
15
+ }
16
+ export interface IntegrityExemptionProblem {
17
+ sourceId: string;
18
+ message: string;
19
+ }
20
+ export interface IntegrityExemptionReadResult {
21
+ registry: IntegrityExemptionRegistry;
22
+ problems: IntegrityExemptionProblem[];
23
+ }
24
+ export declare function emptyIntegrityExemptionRegistry(): IntegrityExemptionRegistry;
25
+ export declare function readIntegrityExemptions(paths: ProjectPaths): IntegrityExemptionReadResult;
26
+ export declare function mergeIntegrityExemptions(registry: IntegrityExemptionRegistry, additions: IntegrityExemption[]): IntegrityExemptionRegistry;
27
+ export declare function writeIntegrityExemptions(paths: ProjectPaths, registry: IntegrityExemptionRegistry): void;
28
+ export declare function exemptionTaskKey(exemption: Pick<IntegrityExemption, 'specCode' | 'taskId'>): string;
29
+ //# sourceMappingURL=integrity-exemptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity-exemptions.d.ts","sourceRoot":"","sources":["../../src/core/integrity-exemptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,MAAM,MAAM,sBAAsB,GAAG,6BAA6B,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,sBAAsB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,kBAAkB,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,0BAA0B,CAAC;IACrC,QAAQ,EAAE,yBAAyB,EAAE,CAAC;CACvC;AAED,wBAAgB,+BAA+B,IAAI,0BAA0B,CAE5E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,GAAG,4BAA4B,CAsCzF;AAED,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,0BAA0B,EACpC,SAAS,EAAE,kBAAkB,EAAE,GAC9B,0BAA0B,CAsB5B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,0BAA0B,GAAG,IAAI,CAExG;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,GAAG,MAAM,CAEnG"}
@@ -0,0 +1,100 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { writeAtomic } from './frontmatter.js';
3
+ export function emptyIntegrityExemptionRegistry() {
4
+ return { version: 1, exemptions: [] };
5
+ }
6
+ export function readIntegrityExemptions(paths) {
7
+ if (!existsSync(paths.integrityExemptionsFile)) {
8
+ return { registry: emptyIntegrityExemptionRegistry(), problems: [] };
9
+ }
10
+ let value;
11
+ try {
12
+ value = JSON.parse(readFileSync(paths.integrityExemptionsFile, 'utf8'));
13
+ }
14
+ catch (err) {
15
+ return invalidRegistry(`cannot parse integrity exemption registry: ${errorMessage(err)}`);
16
+ }
17
+ if (!isRecord(value) || value.version !== 1 || !Array.isArray(value.exemptions)) {
18
+ return invalidRegistry('integrity exemption registry must have version 1 and an exemptions array');
19
+ }
20
+ const exemptions = [];
21
+ const problems = [];
22
+ const ids = new Set();
23
+ const taskKeys = new Set();
24
+ for (const [index, item] of value.exemptions.entries()) {
25
+ if (!isIntegrityExemption(item)) {
26
+ problems.push({ sourceId: `exemption[${index}]`, message: `integrity exemption at index ${index} has invalid fields` });
27
+ continue;
28
+ }
29
+ const taskKey = exemptionTaskKey(item);
30
+ if (ids.has(item.id)) {
31
+ problems.push({ sourceId: item.id, message: `duplicate integrity exemption id: ${item.id}` });
32
+ continue;
33
+ }
34
+ if (taskKeys.has(taskKey)) {
35
+ problems.push({ sourceId: taskKey, message: `duplicate integrity exemption task key: ${taskKey}` });
36
+ continue;
37
+ }
38
+ ids.add(item.id);
39
+ taskKeys.add(taskKey);
40
+ exemptions.push(item);
41
+ }
42
+ return { registry: { version: 1, exemptions }, problems };
43
+ }
44
+ export function mergeIntegrityExemptions(registry, additions) {
45
+ const byId = new Map(registry.exemptions.map(exemption => [exemption.id, exemption]));
46
+ const byTask = new Map(registry.exemptions.map(exemption => [exemptionTaskKey(exemption), exemption]));
47
+ const merged = [...registry.exemptions];
48
+ for (const exemption of additions) {
49
+ if (!isIntegrityExemption(exemption)) {
50
+ throw new Error('INVALID_EXEMPTION: invalid fields');
51
+ }
52
+ const sameId = byId.get(exemption.id);
53
+ const sameTask = byTask.get(exemptionTaskKey(exemption));
54
+ if (sameId && JSON.stringify(sameId) !== JSON.stringify(exemption)) {
55
+ throw new Error(`EXEMPTION_CONFLICT: id ${exemption.id}`);
56
+ }
57
+ if (sameTask && sameTask.id !== exemption.id) {
58
+ throw new Error(`EXEMPTION_CONFLICT: task ${exemptionTaskKey(exemption)}`);
59
+ }
60
+ if (sameId || sameTask)
61
+ continue;
62
+ merged.push(exemption);
63
+ byId.set(exemption.id, exemption);
64
+ byTask.set(exemptionTaskKey(exemption), exemption);
65
+ }
66
+ return { version: 1, exemptions: merged };
67
+ }
68
+ export function writeIntegrityExemptions(paths, registry) {
69
+ writeAtomic(paths.integrityExemptionsFile, `${JSON.stringify(registry, null, 2)}\n`);
70
+ }
71
+ export function exemptionTaskKey(exemption) {
72
+ return `${exemption.specCode}:${exemption.taskId}`;
73
+ }
74
+ function invalidRegistry(message) {
75
+ return {
76
+ registry: emptyIntegrityExemptionRegistry(),
77
+ problems: [{ sourceId: 'integrity-exemptions', message }],
78
+ };
79
+ }
80
+ function isIntegrityExemption(value) {
81
+ if (!isRecord(value))
82
+ return false;
83
+ return value.kind === 'legacy-missing-verification'
84
+ && nonEmpty(value.id)
85
+ && nonEmpty(value.specCode)
86
+ && nonEmpty(value.taskId)
87
+ && nonEmpty(value.reason)
88
+ && nonEmpty(value.createdAt)
89
+ && nonEmpty(value.migrationId);
90
+ }
91
+ function isRecord(value) {
92
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
93
+ }
94
+ function nonEmpty(value) {
95
+ return typeof value === 'string' && value.trim().length > 0;
96
+ }
97
+ function errorMessage(err) {
98
+ return err instanceof Error ? err.message : String(err);
99
+ }
100
+ //# sourceMappingURL=integrity-exemptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity-exemptions.js","sourceRoot":"","sources":["../../src/core/integrity-exemptions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ProjectPaths } from './paths.js';
2
+ export type IntegrityIssueKind = 'dangling-reference' | 'conflicting-active-task' | 'missing-verification' | 'missing-decision' | 'immutable-history-violation' | 'invalid-exemption' | 'stale-confirmed-parent';
3
+ export interface IntegrityIssue {
4
+ kind: IntegrityIssueKind;
5
+ sourceFile: string;
6
+ sourceId: string;
7
+ targetId?: string;
8
+ message: string;
9
+ remediation?: string;
10
+ }
11
+ export declare function inspectProjectIntegrity(paths: ProjectPaths): IntegrityIssue[];
12
+ //# sourceMappingURL=integrity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/core/integrity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/C,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,yBAAyB,GACzB,sBAAsB,GACtB,kBAAkB,GAClB,6BAA6B,GAC7B,mBAAmB,GACnB,wBAAwB,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,YAAY,GAAG,cAAc,EAAE,CAqI7E"}
@@ -0,0 +1,163 @@
1
+ import { listAllSpecs } from './spec-io.js';
2
+ import { listTasks } from './task.js';
3
+ import { listDecisions } from './decision.js';
4
+ import { listIncidents } from './incident.js';
5
+ import { listTaskLinkedChangeProposals } from './delta.js';
6
+ import { exemptionTaskKey, readIntegrityExemptions } from './integrity-exemptions.js';
7
+ const ACTIVE_TASK_STATUSES = new Set(['draft', 'running', 'waiting']);
8
+ export function inspectProjectIntegrity(paths) {
9
+ const issues = [];
10
+ const specs = listAllSpecs(paths);
11
+ const tasks = listTasks(paths);
12
+ const decisions = listDecisions(paths, { includeAll: true });
13
+ const incidents = listIncidents(paths);
14
+ const changes = listTaskLinkedChangeProposals(paths);
15
+ const exemptionResult = readIntegrityExemptions(paths);
16
+ const specCodes = new Set(specs.map(spec => spec.fm.code));
17
+ const taskKeys = new Set(tasks.map(task => `${task.specCode}:${task.id}`));
18
+ const decisionIds = new Set(decisions.map(decision => decision.id));
19
+ const taskByKey = new Map(tasks.map(task => [`${task.specCode}:${task.id}`, task]));
20
+ const validExemptionTaskKeys = new Set();
21
+ for (const problem of exemptionResult.problems) {
22
+ issues.push({
23
+ kind: 'invalid-exemption',
24
+ sourceFile: paths.integrityExemptionsFile,
25
+ sourceId: problem.sourceId,
26
+ message: problem.message,
27
+ remediation: 'Repair or remove the invalid integrity exemption entry.',
28
+ });
29
+ }
30
+ for (const exemption of exemptionResult.registry.exemptions) {
31
+ const key = exemptionTaskKey(exemption);
32
+ const task = taskByKey.get(key);
33
+ if (!task) {
34
+ issues.push(invalidExemption(paths, exemption.id, `integrity exemption references missing task ${key}`));
35
+ }
36
+ else if (task.status !== 'completed') {
37
+ issues.push(invalidExemption(paths, exemption.id, `integrity exemption references non-completed task ${key}`));
38
+ }
39
+ else if ((task.verifications ?? []).some(v => v.exitCode === 0)) {
40
+ issues.push(invalidExemption(paths, exemption.id, `integrity exemption references task with successful verification ${key}`));
41
+ }
42
+ else {
43
+ validExemptionTaskKeys.add(key);
44
+ }
45
+ }
46
+ for (const spec of specs) {
47
+ if (spec.fm.parentCode && !specCodes.has(spec.fm.parentCode)) {
48
+ issues.push(dangling(spec.filePath, spec.fm.code, spec.fm.parentCode, 'parentCode'));
49
+ }
50
+ for (const relation of spec.fm.relations ?? []) {
51
+ if (!specCodes.has(relation.target)) {
52
+ issues.push(dangling(spec.filePath, spec.fm.code, relation.target, `relation ${relation.type}`));
53
+ }
54
+ }
55
+ if (spec.fm.level === 'L1' && spec.fm.status === 'implemented' && !decisions.some(d => d.fm.docCode === spec.fm.code)) {
56
+ issues.push({
57
+ kind: 'missing-decision',
58
+ sourceFile: spec.filePath,
59
+ sourceId: spec.fm.code,
60
+ message: `implemented L1 ${spec.fm.code} has no decision card`,
61
+ remediation: `spec-manager decision create ${spec.fm.code} --topic ${spec.fm.topic} --what "..."`,
62
+ });
63
+ }
64
+ if ((spec.fm.level === 'L1' || spec.fm.level === 'L2') && spec.fm.status === 'confirmed') {
65
+ const children = specs.filter(child => child.fm.parentCode === spec.fm.code);
66
+ if (children.length > 0 && children.every(child => child.fm.status === 'implemented')) {
67
+ issues.push({
68
+ kind: 'stale-confirmed-parent',
69
+ sourceFile: spec.filePath,
70
+ sourceId: spec.fm.code,
71
+ message: `confirmed ${spec.fm.level} ${spec.fm.code} has only implemented direct children`,
72
+ remediation: 'spec-manager project reconcile --dry-run',
73
+ });
74
+ }
75
+ }
76
+ }
77
+ for (const task of tasks) {
78
+ if (!specCodes.has(task.specCode)) {
79
+ issues.push(dangling(taskFileHint(paths, task), task.id, task.specCode, 'task specCode'));
80
+ }
81
+ const taskKey = `${task.specCode}:${task.id}`;
82
+ if (task.status === 'completed' && !(task.verifications ?? []).some(v => v.exitCode === 0) && !validExemptionTaskKeys.has(taskKey)) {
83
+ issues.push({
84
+ kind: 'missing-verification',
85
+ sourceFile: taskFileHint(paths, task),
86
+ sourceId: `${task.specCode}:${task.id}`,
87
+ message: `completed task ${task.id} (${task.specCode}) has no successful verification`,
88
+ remediation: 'Create a follow-up task; completed task history is immutable.',
89
+ });
90
+ }
91
+ if ((task.status === 'completed' || task.status === 'failed') && (task.steps ?? []).some(step => step.status !== 'succeeded')) {
92
+ issues.push({
93
+ kind: 'immutable-history-violation',
94
+ sourceFile: taskFileHint(paths, task),
95
+ sourceId: `${task.specCode}:${task.id}`,
96
+ message: `terminal task ${task.id} contains non-succeeded steps`,
97
+ });
98
+ }
99
+ }
100
+ const activeBySpec = new Map();
101
+ for (const task of tasks.filter(task => ACTIVE_TASK_STATUSES.has(task.status))) {
102
+ activeBySpec.set(task.specCode, [...(activeBySpec.get(task.specCode) ?? []), task]);
103
+ }
104
+ for (const [specCode, active] of activeBySpec) {
105
+ if (active.length > 1) {
106
+ issues.push({
107
+ kind: 'conflicting-active-task',
108
+ sourceFile: taskFileHint(paths, active[0]),
109
+ sourceId: specCode,
110
+ message: `${specCode} has ${active.length} active tasks: ${active.map(task => task.id).join(', ')}`,
111
+ });
112
+ }
113
+ }
114
+ for (const decision of decisions) {
115
+ if (!specCodes.has(decision.fm.docCode)) {
116
+ issues.push(dangling(decision.filePath, decision.id, decision.fm.docCode, 'decision docCode'));
117
+ }
118
+ }
119
+ for (const incident of incidents) {
120
+ if (incident.fm.specCode && !specCodes.has(incident.fm.specCode)) {
121
+ issues.push(dangling(incident.filePath, incident.id, incident.fm.specCode, 'incident specCode'));
122
+ }
123
+ if (incident.fm.taskCode && incident.fm.specCode && !taskKeys.has(`${incident.fm.specCode}:${incident.fm.taskCode}`)) {
124
+ issues.push(dangling(incident.filePath, incident.id, incident.fm.taskCode, 'incident taskCode'));
125
+ }
126
+ for (const id of incident.fm.relatedDecisions ?? []) {
127
+ if (!decisionIds.has(id))
128
+ issues.push(dangling(incident.filePath, incident.id, id, 'incident relatedDecision'));
129
+ }
130
+ }
131
+ for (const change of changes) {
132
+ if (!specCodes.has(change.specCode)) {
133
+ issues.push(dangling(change.proposalFile, change.name, change.specCode, 'change specCode'));
134
+ }
135
+ if (!taskKeys.has(`${change.specCode}:${change.taskCode}`)) {
136
+ issues.push(dangling(change.proposalFile, change.name, change.taskCode, 'change taskCode'));
137
+ }
138
+ }
139
+ return issues;
140
+ }
141
+ function invalidExemption(paths, sourceId, message) {
142
+ return {
143
+ kind: 'invalid-exemption',
144
+ sourceFile: paths.integrityExemptionsFile,
145
+ sourceId,
146
+ message,
147
+ remediation: 'Repair or remove the invalid integrity exemption entry.',
148
+ };
149
+ }
150
+ function dangling(sourceFile, sourceId, targetId, field) {
151
+ return {
152
+ kind: 'dangling-reference',
153
+ sourceFile,
154
+ sourceId,
155
+ targetId,
156
+ message: `${sourceId} has dangling ${field}: ${targetId}`,
157
+ };
158
+ }
159
+ function taskFileHint(paths, task) {
160
+ const topic = listAllSpecs(paths).find(spec => spec.fm.code === task.specCode)?.fm.topic ?? '?';
161
+ return `${paths.specsDir}/${topic}/tasks/${task.specCode}-${task.id}.json`;
162
+ }
163
+ //# sourceMappingURL=integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/core/integrity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { TaskRecord } from './task.js';
2
+ export declare function assertTaskMutable(task: TaskRecord, operation: string): void;
3
+ export declare function assertNoActiveTaskForSpec(tasks: TaskRecord[], specCode: string): void;
4
+ export declare function assertTaskHasSuccessfulVerification(task: TaskRecord): void;
5
+ //# sourceMappingURL=invariants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariants.d.ts","sourceRoot":"","sources":["../../src/core/invariants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAK5C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAI3E;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAKrF;AAED,wBAAgB,mCAAmC,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAI1E"}