project-tiny-context-harness 0.2.80 → 0.2.82

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 (34) hide show
  1. package/README.md +10 -8
  2. package/assets/README.md +9 -7
  3. package/assets/README.zh-CN.md +10 -0
  4. package/assets/github/harness.yml +1 -1
  5. package/assets/skills/composite-long-task-workflow/SKILL.md +10 -2
  6. package/assets/skills/composite-long-task-workflow/assets/execution-binding.template.md +2 -0
  7. package/assets/skills/composite-long-task-workflow/assets/goal-objective.template.md +7 -3
  8. package/assets/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md +27 -11
  9. package/dist/lib/composite-long-task-renderer.js +18 -62
  10. package/dist/lib/superpowers-task-assertion-normalizers.d.ts +3 -0
  11. package/dist/lib/superpowers-task-assertion-normalizers.js +70 -0
  12. package/dist/lib/superpowers-task-assertions.d.ts +20 -0
  13. package/dist/lib/superpowers-task-assertions.js +243 -0
  14. package/dist/lib/superpowers-task-compile-diagnostics.d.ts +5 -0
  15. package/dist/lib/superpowers-task-compile-diagnostics.js +20 -0
  16. package/dist/lib/superpowers-task-compile-guards.d.ts +2 -0
  17. package/dist/lib/superpowers-task-compile-guards.js +66 -0
  18. package/dist/lib/superpowers-task-compile.js +25 -5
  19. package/dist/lib/superpowers-task-conformance.d.ts +2 -0
  20. package/dist/lib/superpowers-task-conformance.js +24 -0
  21. package/dist/lib/superpowers-task-delivery.js +30 -18
  22. package/dist/lib/superpowers-task-derive.d.ts +1 -0
  23. package/dist/lib/superpowers-task-derive.js +121 -4
  24. package/dist/lib/superpowers-task-fields.d.ts +22 -0
  25. package/dist/lib/superpowers-task-fields.js +276 -0
  26. package/dist/lib/superpowers-task-gates.js +57 -3
  27. package/dist/lib/superpowers-task-source-compile.js +128 -92
  28. package/dist/lib/superpowers-task-source-parser.js +12 -18
  29. package/dist/lib/superpowers-task-state-schema.d.ts +120 -1
  30. package/dist/lib/superpowers-task-state.js +33 -8
  31. package/dist/lib/superpowers-task-status.d.ts +2 -0
  32. package/dist/lib/superpowers-task-status.js +14 -0
  33. package/dist/lib/superpowers-task-validator.js +18 -9
  34. package/package.json +69 -69
@@ -1,87 +1,38 @@
1
+ import { MACHINE_VERIFIABLE_PROOF_LAYERS, proofLayerName } from "./superpowers-task-assertions.js";
2
+ import { compileReportSuffix, missingCategory, throwCompileErrors } from "./superpowers-task-compile-diagnostics.js";
3
+ import { ACCEPTANCE_FIELDS, ACCEPTANCE_SCOPES, fieldSet, isSelectedScopeFitSlice, normalizeProofLayerName, PLAN_DELIVERY_SCOPES, PLAN_FIELDS, PRODUCT_DELIVERY_SCOPES, PRODUCT_FIELDS, SCOPE_FIT_DECISIONS } from "./superpowers-task-fields.js";
1
4
  import { fieldArray, fieldBoolean, fieldLine, fieldText, parseDocumentFields, parseHeadingDefinitions } from "./superpowers-task-source-parser.js";
2
5
  export const DEFAULT_LAYERS = ["code", "test"];
3
- const PRODUCT_DELIVERY_SCOPES = new Set(["system_capability_build", "representative_sample_validation", "full_population_operation", "mixed_scope_requires_boundary"]);
4
- const PLAN_DELIVERY_SCOPES = new Set(["system_capability_build", "representative_sample_validation", "full_population_operation", "out_of_scope_backlog"]);
5
- const ACCEPTANCE_SCOPES = new Set(["system_capability_build", "representative_sample_validation", "full_population_operation", "full_population_not_required"]);
6
- const PRODUCT_FIELDS = new Set([
7
- "delivery_scope",
8
- "full_population_required",
9
- "representative_samples_validate",
10
- "representative_samples_do_not_validate",
11
- "out_of_scope_backlog",
12
- "source_authority",
13
- "product_goal",
14
- "surface_ia_lock",
15
- "decision_lock",
16
- "context_delta",
17
- "source_to_context_coverage",
18
- "acceptance_semantics",
19
- "impact"
20
- ]);
21
- const PLAN_FIELDS = new Set([
22
- "delivery_scope",
23
- "capability_target",
24
- "representative_samples",
25
- "full_population_boundary",
26
- "non_required_population",
27
- "owner_surfaces",
28
- "forbidden_surfaces",
29
- "implementation_paths",
30
- "required_tests",
31
- "related_acs",
32
- "requirement_ref",
33
- "decision_id",
34
- "proof_layer_ids",
35
- "api_schema_changes",
36
- "state_machine",
37
- "data_flow",
38
- "worker_runtime_behavior",
39
- "ui_ia_changes",
40
- "migration_plan",
41
- "evidence_artifacts",
42
- "explicit_no_test_scope",
43
- "non_completing_shortcuts",
44
- "substitution_policy",
45
- "drift_severity",
46
- "partial_conditions",
47
- "blockers",
48
- "context_fact_refs"
49
- ]);
50
- const ACCEPTANCE_FIELDS = new Set([
51
- "checklist_source",
52
- "acceptance_scope",
53
- "ac_validates",
54
- "ac_does_not_validate",
55
- "sample_boundary",
56
- "full_population_required",
57
- "related_plan_items",
58
- "required_proof_layers",
59
- "ac_type",
60
- "proof_chain",
61
- "verification_method",
62
- "fail_conditions",
63
- "invalid_evidence",
64
- "substitution_policy",
65
- "missing_layer_downgrade",
66
- "auditor_expectation",
67
- "out_of_scope_na_approval_source",
68
- "required_test_ids",
69
- "explicit_no_test_scope",
70
- "hard_blockers",
71
- "validates_explanation",
72
- "does_not_validate_explanation",
73
- "final_evidence_expected",
74
- "test_cases"
75
- ]);
6
+ const PRODUCT_FIELD_SET = fieldSet(PRODUCT_FIELDS);
7
+ const PLAN_FIELD_SET = fieldSet(PLAN_FIELDS);
8
+ const ACCEPTANCE_FIELD_SET = fieldSet(ACCEPTANCE_FIELDS);
76
9
  export function parseProductArchitectureScope(content, sourceFile) {
77
- const fields = parseDocumentFields(content, sourceFile, PRODUCT_FIELDS);
10
+ const fields = parseDocumentFields(content, sourceFile, PRODUCT_FIELD_SET);
78
11
  const errors = [];
12
+ const selectedScopeFitSlice = requireText(errors, "Product / Architecture Source", "selected_scope_fit_slice", fields, sourceFile, 1);
13
+ if (selectedScopeFitSlice && !isSelectedScopeFitSlice(selectedScopeFitSlice)) {
14
+ errors.push(`Product / Architecture Source invalid selected_scope_fit_slice: ${selectedScopeFitSlice} at ${sourceFile}:${fieldLine(fields, "selected_scope_fit_slice") ?? 1}; allowed: none or SFC-###${compileReportSuffix("blocking_unparseable_object", sourceFile, fieldLine(fields, "selected_scope_fit_slice") ?? 1, "selected_scope_fit_slice", "value must be none or an SFC-### id", "fix selected_scope_fit_slice and rerun compile")}`);
15
+ }
79
16
  const scope = {
80
17
  delivery_scope: requireEnum(errors, "Product / Architecture Source", "delivery_scope", fields, PRODUCT_DELIVERY_SCOPES, sourceFile, 1),
81
18
  full_population_required: requireBoolean(errors, "Product / Architecture Source", "full_population_required", fields, sourceFile, 1),
82
19
  representative_samples_validate: requireArray(errors, "Product / Architecture Source", "representative_samples_validate", fields, sourceFile, 1),
83
20
  representative_samples_do_not_validate: requireArray(errors, "Product / Architecture Source", "representative_samples_do_not_validate", fields, sourceFile, 1),
84
- out_of_scope_backlog: requireArray(errors, "Product / Architecture Source", "out_of_scope_backlog", fields, sourceFile, 1)
21
+ out_of_scope_backlog: requireArray(errors, "Product / Architecture Source", "out_of_scope_backlog", fields, sourceFile, 1),
22
+ scope_fit_decision: requireEnum(errors, "Product / Architecture Source", "scope_fit_decision", fields, SCOPE_FIT_DECISIONS, sourceFile, 1),
23
+ selected_scope_fit_slice: selectedScopeFitSlice,
24
+ owner_boundary: requireText(errors, "Product / Architecture Source", "owner_boundary", fields, sourceFile, 1),
25
+ primary_capability_path: requireText(errors, "Product / Architecture Source", "primary_capability_path", fields, sourceFile, 1),
26
+ non_completing_outcomes: requireArray(errors, "Product / Architecture Source", "non_completing_outcomes", fields, sourceFile, 1),
27
+ assertion_policy: requireText(errors, "Product / Architecture Source", "assertion_policy", fields, sourceFile, 1),
28
+ source_authority: requireText(errors, "Product / Architecture Source", "source_authority", fields, sourceFile, 1),
29
+ product_goal: requireText(errors, "Product / Architecture Source", "product_goal", fields, sourceFile, 1),
30
+ surface_ia_lock: optionalText(fields, "surface_ia_lock"),
31
+ decision_lock: optionalText(fields, "decision_lock"),
32
+ context_delta: optionalText(fields, "context_delta"),
33
+ source_to_context_coverage: optionalText(fields, "source_to_context_coverage"),
34
+ acceptance_semantics: optionalText(fields, "acceptance_semantics"),
35
+ impact: optionalText(fields, "impact")
85
36
  };
86
37
  throwCompileErrors(errors);
87
38
  return scope;
@@ -89,7 +40,7 @@ export function parseProductArchitectureScope(content, sourceFile) {
89
40
  export function parsePlanItems(content, sourceFile) {
90
41
  const items = {};
91
42
  const errors = [];
92
- for (const definition of parseHeadingDefinitions(content, { kind: "PI", sourceFile, allowedFields: PLAN_FIELDS })) {
43
+ for (const definition of parseHeadingDefinitions(content, { kind: "PI", sourceFile, allowedFields: PLAN_FIELD_SET })) {
93
44
  const fields = definition.fields;
94
45
  items[definition.id] = {
95
46
  requirement: definition.title,
@@ -101,10 +52,35 @@ export function parsePlanItems(content, sourceFile) {
101
52
  representative_samples: requireArray(errors, definition.id, "representative_samples", fields, sourceFile, definition.source_start_line),
102
53
  full_population_boundary: requireText(errors, definition.id, "full_population_boundary", fields, sourceFile, definition.source_start_line),
103
54
  non_required_population: requireArray(errors, definition.id, "non_required_population", fields, sourceFile, definition.source_start_line),
55
+ owner_boundary: requireText(errors, definition.id, "owner_boundary", fields, sourceFile, definition.source_start_line),
56
+ primary_capability_path: requireText(errors, definition.id, "primary_capability_path", fields, sourceFile, definition.source_start_line),
57
+ trigger_contract: requireText(errors, definition.id, "trigger_contract", fields, sourceFile, definition.source_start_line),
58
+ state_transition_contract: requireText(errors, definition.id, "state_transition_contract", fields, sourceFile, definition.source_start_line),
59
+ observable_result_contract: requireText(errors, definition.id, "observable_result_contract", fields, sourceFile, definition.source_start_line),
60
+ assertion_support: requireText(errors, definition.id, "assertion_support", fields, sourceFile, definition.source_start_line),
61
+ required_assertion_commands: requireArray(errors, definition.id, "required_assertion_commands", fields, sourceFile, definition.source_start_line),
62
+ invalid_implementation_shortcuts: requireArray(errors, definition.id, "invalid_implementation_shortcuts", fields, sourceFile, definition.source_start_line),
104
63
  owner_surfaces: optionalArray(fields, "owner_surfaces"),
105
64
  forbidden_surfaces: optionalArray(fields, "forbidden_surfaces"),
106
- implementation_paths: optionalArray(fields, "implementation_paths"),
65
+ implementation_paths: requireArray(errors, definition.id, "implementation_paths", fields, sourceFile, definition.source_start_line),
107
66
  required_tests: optionalArray(fields, "required_tests"),
67
+ proof_layer_ids: optionalArray(fields, "proof_layer_ids").map(normalizeLayerId),
68
+ requirement_ref: optionalText(fields, "requirement_ref"),
69
+ decision_id: optionalText(fields, "decision_id"),
70
+ api_schema_changes: optionalText(fields, "api_schema_changes"),
71
+ state_machine: optionalText(fields, "state_machine"),
72
+ data_flow: optionalText(fields, "data_flow"),
73
+ worker_runtime_behavior: optionalText(fields, "worker_runtime_behavior"),
74
+ ui_ia_changes: optionalText(fields, "ui_ia_changes"),
75
+ migration_plan: optionalText(fields, "migration_plan"),
76
+ evidence_artifacts: optionalArray(fields, "evidence_artifacts"),
77
+ non_completing_shortcuts: optionalArray(fields, "non_completing_shortcuts"),
78
+ substitution_policy: optionalArray(fields, "substitution_policy"),
79
+ drift_severity: optionalText(fields, "drift_severity"),
80
+ partial_conditions: optionalArray(fields, "partial_conditions"),
81
+ blockers: optionalArray(fields, "blockers"),
82
+ explicit_no_test_scope: fieldBoolean(fields, "explicit_no_test_scope") === true,
83
+ context_fact_refs: optionalArray(fields, "context_fact_refs"),
108
84
  status: "not_started",
109
85
  related_acs: optionalArray(fields, "related_acs").map((item) => item.toUpperCase()),
110
86
  required_proof_layers: []
@@ -116,9 +92,10 @@ export function parsePlanItems(content, sourceFile) {
116
92
  export function parseAcceptanceCriteria(content, sourceFile) {
117
93
  const items = {};
118
94
  const errors = [];
119
- for (const definition of parseHeadingDefinitions(content, { kind: "AC", sourceFile, allowedFields: ACCEPTANCE_FIELDS })) {
95
+ for (const definition of parseHeadingDefinitions(content, { kind: "AC", sourceFile, allowedFields: ACCEPTANCE_FIELD_SET })) {
120
96
  const fields = definition.fields;
121
- const layers = optionalArray(fields, "required_proof_layers").map(normalizeLayer).filter(Boolean);
97
+ const layers = requireArray(errors, definition.id, "required_proof_layers", fields, sourceFile, definition.source_start_line).map(normalizeLayer).filter(Boolean);
98
+ const requiredProofLayers = layers.length > 0 ? layers : DEFAULT_LAYERS;
122
99
  items[definition.id] = {
123
100
  scope: definition.title,
124
101
  source_file: definition.source_file,
@@ -129,8 +106,32 @@ export function parseAcceptanceCriteria(content, sourceFile) {
129
106
  ac_does_not_validate: requireArray(errors, definition.id, "ac_does_not_validate", fields, sourceFile, definition.source_start_line),
130
107
  sample_boundary: requireText(errors, definition.id, "sample_boundary", fields, sourceFile, definition.source_start_line),
131
108
  full_population_required: requireBoolean(errors, definition.id, "full_population_required", fields, sourceFile, definition.source_start_line),
132
- related_plan_items: optionalArray(fields, "related_plan_items").map((item) => item.toUpperCase()),
133
- required_proof_layers: layers.length > 0 ? layers : DEFAULT_LAYERS,
109
+ related_plan_items: requireArray(errors, definition.id, "related_plan_items", fields, sourceFile, definition.source_start_line).map((item) => item.toUpperCase()),
110
+ required_proof_layers: requiredProofLayers,
111
+ assertion_requirements: assertionRequirements(fields, requiredProofLayers),
112
+ assertion_command: requireText(errors, definition.id, "assertion_command", fields, sourceFile, definition.source_start_line),
113
+ assertion_artifacts: requireArray(errors, definition.id, "assertion_artifacts", fields, sourceFile, definition.source_start_line),
114
+ positive_assertions: requireArray(errors, definition.id, "positive_assertions", fields, sourceFile, definition.source_start_line),
115
+ negative_assertions: requireArray(errors, definition.id, "negative_assertions", fields, sourceFile, definition.source_start_line),
116
+ machine_blocking: requireBoolean(errors, definition.id, "machine_blocking", fields, sourceFile, definition.source_start_line),
117
+ invalid_completion_signals: requireArray(errors, definition.id, "invalid_completion_signals", fields, sourceFile, definition.source_start_line),
118
+ assertion_result_required: requireBoolean(errors, definition.id, "assertion_result_required", fields, sourceFile, definition.source_start_line),
119
+ ac_type: optionalText(fields, "ac_type"),
120
+ proof_chain: optionalArray(fields, "proof_chain").map(normalizeLayerId),
121
+ required_test_ids: optionalArray(fields, "required_test_ids"),
122
+ fail_conditions: optionalArray(fields, "fail_conditions"),
123
+ invalid_evidence: optionalArray(fields, "invalid_evidence"),
124
+ substitution_policy: optionalArray(fields, "substitution_policy"),
125
+ missing_layer_downgrade: optionalText(fields, "missing_layer_downgrade"),
126
+ auditor_expectation: optionalText(fields, "auditor_expectation"),
127
+ out_of_scope_na_approval_source: optionalText(fields, "out_of_scope_na_approval_source"),
128
+ hard_blockers: optionalArray(fields, "hard_blockers"),
129
+ validates_explanation: optionalText(fields, "validates_explanation"),
130
+ does_not_validate_explanation: optionalText(fields, "does_not_validate_explanation"),
131
+ final_evidence_expected: optionalArray(fields, "final_evidence_expected"),
132
+ verification_method: optionalArray(fields, "verification_method"),
133
+ test_cases: optionalArray(fields, "test_cases"),
134
+ explicit_no_test_scope: fieldBoolean(fields, "explicit_no_test_scope") === true,
134
135
  status: "not_run"
135
136
  };
136
137
  }
@@ -138,17 +139,51 @@ export function parseAcceptanceCriteria(content, sourceFile) {
138
139
  return items;
139
140
  }
140
141
  function normalizeLayer(value) {
141
- return value.trim().toLowerCase().replace(/[- ]+/g, "_");
142
+ return normalizeProofLayerName(value);
143
+ }
144
+ function normalizeLayerId(value) {
145
+ const trimmed = value.trim();
146
+ if (!trimmed.includes(".")) {
147
+ return normalizeLayer(trimmed);
148
+ }
149
+ const acId = trimmed.slice(0, trimmed.lastIndexOf(".")).toUpperCase();
150
+ const layer = trimmed.slice(trimmed.lastIndexOf(".") + 1);
151
+ return `${acId}.${normalizeLayer(layer)}`;
152
+ }
153
+ function assertionRequirements(fields, layers) {
154
+ const requiredTestIds = optionalArray(fields, "required_test_ids");
155
+ const positiveAssertions = unique(optionalArray(fields, "positive_assertions"));
156
+ const negativeAssertions = unique(optionalArray(fields, "negative_assertions"));
157
+ const assertionCommand = fieldText(fields, "assertion_command");
158
+ const assertionArtifacts = optionalArray(fields, "assertion_artifacts");
159
+ const machineBlocking = fieldBoolean(fields, "machine_blocking");
160
+ const assertionResultRequired = fieldBoolean(fields, "assertion_result_required");
161
+ const invalidCompletionSignals = optionalArray(fields, "invalid_completion_signals");
162
+ return layers.map((layer) => {
163
+ const normalized = proofLayerName(normalizeLayer(layer));
164
+ return {
165
+ proof_layer: normalized,
166
+ required: true,
167
+ machine_blocking: machineBlocking ?? MACHINE_VERIFIABLE_PROOF_LAYERS.has(normalized),
168
+ assertion_result_required: assertionResultRequired ?? MACHINE_VERIFIABLE_PROOF_LAYERS.has(normalized),
169
+ assertion_command: assertionCommand,
170
+ assertion_artifacts: assertionArtifacts,
171
+ invalid_completion_signals: invalidCompletionSignals,
172
+ required_test_ids: requiredTestIds,
173
+ positive_assertions: positiveAssertions,
174
+ negative_assertions: negativeAssertions
175
+ };
176
+ });
142
177
  }
143
178
  function requireEnum(errors, label, name, fields, allowed, sourceFile, fallbackLine) {
144
179
  const value = fieldText(fields, name);
145
180
  const line = fieldLine(fields, name) ?? fallbackLine;
146
181
  if (!value) {
147
- errors.push(`${label} missing ${name} at ${sourceFile}:${line}`);
182
+ errors.push(`${label} missing ${name} at ${sourceFile}:${line}${compileReportSuffix(missingCategory(label), sourceFile, line, name, "field is required", "add the required field and rerun compile")}`);
148
183
  return "";
149
184
  }
150
185
  if (!allowed.has(value)) {
151
- errors.push(`${label} invalid ${name}: ${value} at ${sourceFile}:${line}; allowed: ${[...allowed].join(", ")}`);
186
+ errors.push(`${label} invalid ${name}: ${value} at ${sourceFile}:${line}; allowed: ${[...allowed].join(", ")}${compileReportSuffix("blocking_unparseable_object", sourceFile, line, name, `value must be one of ${[...allowed].join(", ")}`, "fix the field value and rerun compile")}`);
152
187
  }
153
188
  return value;
154
189
  }
@@ -156,14 +191,14 @@ function requireText(errors, label, name, fields, sourceFile, fallbackLine) {
156
191
  const value = fieldText(fields, name);
157
192
  const line = fieldLine(fields, name) ?? fallbackLine;
158
193
  if (!value) {
159
- errors.push(`${label} missing ${name} at ${sourceFile}:${line}`);
194
+ errors.push(`${label} missing ${name} at ${sourceFile}:${line}${compileReportSuffix(missingCategory(label), sourceFile, line, name, "field is required", "add non-empty text and rerun compile")}`);
160
195
  }
161
196
  return value;
162
197
  }
163
198
  function requireArray(errors, label, name, fields, sourceFile, fallbackLine) {
164
199
  const line = fieldLine(fields, name) ?? fallbackLine;
165
200
  if (!fields[name]) {
166
- errors.push(`${label} missing ${name} at ${sourceFile}:${line}`);
201
+ errors.push(`${label} missing ${name} at ${sourceFile}:${line}${compileReportSuffix(missingCategory(label), sourceFile, line, name, "field is required", "add the list field and rerun compile")}`);
167
202
  return [];
168
203
  }
169
204
  return fieldArray(fields, name);
@@ -171,20 +206,21 @@ function requireArray(errors, label, name, fields, sourceFile, fallbackLine) {
171
206
  function requireBoolean(errors, label, name, fields, sourceFile, fallbackLine) {
172
207
  const line = fieldLine(fields, name) ?? fallbackLine;
173
208
  if (!fields[name]) {
174
- errors.push(`${label} missing ${name} at ${sourceFile}:${line}`);
209
+ errors.push(`${label} missing ${name} at ${sourceFile}:${line}${compileReportSuffix(missingCategory(label), sourceFile, line, name, "field is required", "add true or false and rerun compile")}`);
175
210
  return null;
176
211
  }
177
212
  const value = fieldBoolean(fields, name);
178
213
  if (value === null) {
179
- errors.push(`${label} invalid ${name}: ${fieldText(fields, name)} at ${sourceFile}:${line}; must be true or false`);
214
+ errors.push(`${label} invalid ${name}: ${fieldText(fields, name)} at ${sourceFile}:${line}; must be true or false${compileReportSuffix("blocking_unparseable_object", sourceFile, line, name, "value must be true or false", "fix the boolean and rerun compile")}`);
180
215
  }
181
216
  return value;
182
217
  }
183
218
  function optionalArray(fields, name) {
184
219
  return fields[name] ? fieldArray(fields, name) : [];
185
220
  }
186
- function throwCompileErrors(errors) {
187
- if (errors.length > 0) {
188
- throw new Error(`Superpowers source compile failed:\n- ${errors.join("\n- ")}`);
189
- }
221
+ function optionalText(fields, name) {
222
+ return fields[name] ? fieldText(fields, name) : "";
223
+ }
224
+ function unique(values) {
225
+ return [...new Set(values.filter(Boolean))];
190
226
  }
@@ -1,3 +1,4 @@
1
+ import { compileError, throwCompileErrors } from "./superpowers-task-compile-diagnostics.js";
1
2
  export function parseHeadingDefinitions(content, options) {
2
3
  const lines = splitLines(content);
3
4
  const errors = [];
@@ -8,7 +9,7 @@ export function parseHeadingDefinitions(content, options) {
8
9
  for (const heading of headings) {
9
10
  const firstLine = seen.get(heading.id);
10
11
  if (firstLine !== undefined) {
11
- errors.push(`${heading.id} duplicate definition at ${options.sourceFile}:${firstLine} and ${options.sourceFile}:${heading.line}`);
12
+ errors.push(compileError(`${heading.id} duplicate definition at ${options.sourceFile}:${firstLine} and ${options.sourceFile}:${heading.line}`, "blocking_unparseable_object", options.sourceFile, heading.line, heading.id, "duplicate object ids make PI/AC graph references ambiguous", "keep exactly one heading definition for this id"));
12
13
  continue;
13
14
  }
14
15
  seen.set(heading.id, heading.line);
@@ -24,15 +25,15 @@ export function parseHeadingDefinitions(content, options) {
24
25
  });
25
26
  }
26
27
  if (definitions.length === 0) {
27
- errors.push(`${options.sourceFile} must define ${options.kind} items with Markdown headings like "## ${options.kind}-001: ..."`);
28
+ errors.push(compileError(`${options.sourceFile} must define ${options.kind} items with Markdown headings like "## ${options.kind}-001: ..."`, options.kind === "PI" ? "blocking_missing_plan" : "blocking_missing_checklist", options.sourceFile, 1, `${options.kind}_heading`, "the source cannot compile without at least one object heading", `add headings like ## ${options.kind}-001: ...`));
28
29
  }
29
- throwIfErrors(errors);
30
+ throwCompileErrors(errors);
30
31
  return definitions;
31
32
  }
32
33
  export function parseDocumentFields(content, sourceFile, allowedFields) {
33
34
  const errors = [];
34
35
  const fields = parseFields(splitLines(content), sourceFile, 1, allowedFields, errors);
35
- throwIfErrors(errors);
36
+ throwCompileErrors(errors);
36
37
  return fields;
37
38
  }
38
39
  export function fieldText(fields, name) {
@@ -72,11 +73,11 @@ function parseFields(lines, sourceFile, startLine, allowedFields, errors) {
72
73
  const lineNumber = startLine + index;
73
74
  const heading = /^(#{1,6})\s+(.+?)\s*$/.exec(line);
74
75
  if (heading && allowedFields.has(heading[2].trim())) {
75
- errors.push(`${sourceFile}:${lineNumber} field headings are not supported; use "${heading[2].trim()}: ..."`);
76
+ errors.push(compileError(`${sourceFile}:${lineNumber} field headings are not supported; use "${heading[2].trim()}: ..."`, "blocking_unparseable_object", sourceFile, lineNumber, heading[2].trim(), "field heading syntax is ambiguous in compiled source", "use key: value fields"));
76
77
  continue;
77
78
  }
78
79
  if (/^\s*\|/.test(line) && containsKnownField(line, allowedFields)) {
79
- errors.push(`${sourceFile}:${lineNumber} table fields are not supported; use key: value fields`);
80
+ errors.push(compileError(`${sourceFile}:${lineNumber} table fields are not supported; use key: value fields`, "blocking_unparseable_object", sourceFile, lineNumber, "table_field", "table fields cannot be parsed into canonical state safely", "use key: value fields"));
80
81
  continue;
81
82
  }
82
83
  const match = /^([a-z][a-z0-9_]*)\s*:\s*(.*)$/.exec(line);
@@ -85,13 +86,11 @@ function parseFields(lines, sourceFile, startLine, allowedFields, errors) {
85
86
  }
86
87
  const name = match[1];
87
88
  if (!allowedFields.has(name)) {
88
- if (name.includes("_")) {
89
- errors.push(`${sourceFile}:${lineNumber} unknown field ${name}`);
90
- }
89
+ errors.push(compileError(`${sourceFile}:${lineNumber} unknown field ${name}`, "blocking_unparseable_object", sourceFile, lineNumber, name, "unknown fields may hide required source semantics", "rename the field to a supported canonical key"));
91
90
  continue;
92
91
  }
93
92
  if (fields[name]) {
94
- errors.push(`${sourceFile}:${lineNumber} duplicate field ${name}`);
93
+ errors.push(compileError(`${sourceFile}:${lineNumber} duplicate field ${name}`, "blocking_unparseable_object", sourceFile, lineNumber, name, "duplicate fields make canonical source values ambiguous", "keep one field value"));
95
94
  continue;
96
95
  }
97
96
  const parsed = parseFieldValue(lines, index, match[2], sourceFile, lineNumber, errors);
@@ -113,7 +112,7 @@ function parseFieldValue(lines, index, rest, sourceFile, lineNumber, errors) {
113
112
  block.push(next.replace(/^\s{0,2}/, ""));
114
113
  }
115
114
  if (block.length === 0) {
116
- errors.push(`${sourceFile}:${lineNumber} block field must include indented text`);
115
+ errors.push(compileError(`${sourceFile}:${lineNumber} block field must include indented text`, "blocking_unparseable_object", sourceFile, lineNumber, "block_field", "empty block field cannot prove source intent", "add indented text or remove the field"));
117
116
  }
118
117
  return { value: block.join("\n").trim(), endIndex: cursor - 1 };
119
118
  }
@@ -132,7 +131,7 @@ function parseFieldValue(lines, index, rest, sourceFile, lineNumber, errors) {
132
131
  }
133
132
  const listItem = /^\s*[-*+]\s+(.+?)\s*$/.exec(next);
134
133
  if (!listItem) {
135
- errors.push(`${sourceFile}:${cursor + 1} field lists must use indented "- item" entries or key: | blocks`);
134
+ errors.push(compileError(`${sourceFile}:${cursor + 1} field lists must use indented "- item" entries or key: | blocks`, "blocking_unparseable_object", sourceFile, cursor + 1, "list_field", "list syntax cannot be parsed into canonical arrays", "use indented '- item' entries or key: | blocks"));
136
135
  continue;
137
136
  }
138
137
  values.push(cleanValue(listItem[1]));
@@ -158,7 +157,7 @@ function rejectListStyleDefinitions(lines, options, errors) {
158
157
  continue;
159
158
  }
160
159
  const id = match[1].toUpperCase();
161
- errors.push(`${id} list-style definition is not allowed at ${options.sourceFile}:${index + 1}; use "## ${id}: ..."`);
160
+ errors.push(compileError(`${id} list-style definition is not allowed at ${options.sourceFile}:${index + 1}; use "## ${id}: ..."`, "blocking_unparseable_object", options.sourceFile, index + 1, id, "list-style object definitions are not canonical PI/AC headings", `use "## ${id}: ..."`));
162
161
  }
163
162
  }
164
163
  function listItemBlock(lines, start) {
@@ -217,8 +216,3 @@ function splitLines(content) {
217
216
  function cleanValue(value) {
218
217
  return value.replace(/^[-#*\s]+/, "").trim();
219
218
  }
220
- function throwIfErrors(errors) {
221
- if (errors.length > 0) {
222
- throw new Error(`Superpowers source compile failed:\n- ${errors.join("\n- ")}`);
223
- }
224
- }
@@ -54,11 +54,12 @@ export declare const SUPERPOWERS_TASK_STATE_JSON_SCHEMA: {
54
54
  };
55
55
  };
56
56
  export type SuperpowersProofLayerStatus = "missing" | "satisfied" | "invalidated" | "blocked";
57
- export type SuperpowersPlanItemStatus = "not_started" | "complete" | "partial" | "sampled_only" | "not_implemented" | "blocked" | "scope_changed_requires_user_approval" | "contradicted_by_current_state" | "out_of_scope_NA";
57
+ export type SuperpowersPlanItemStatus = "not_started" | "in_progress" | "complete" | "partial" | "blocked" | "invalidated" | "out_of_scope_NA";
58
58
  export type SuperpowersAcceptanceStatus = "not_run" | "complete" | "partial" | "blocked" | "invalidated" | "out_of_scope_NA";
59
59
  export type SuperpowersProductDeliveryScope = "system_capability_build" | "representative_sample_validation" | "full_population_operation" | "mixed_scope_requires_boundary";
60
60
  export type SuperpowersPlanDeliveryScope = "system_capability_build" | "representative_sample_validation" | "full_population_operation" | "out_of_scope_backlog";
61
61
  export type SuperpowersAcceptanceScope = "system_capability_build" | "representative_sample_validation" | "full_population_operation" | "full_population_not_required";
62
+ export type SuperpowersScopeFitDecision = "fit_for_three_inputs" | "selected_from_split" | "blocked_for_decision" | "";
62
63
  export interface SuperpowersTaskState {
63
64
  meta: {
64
65
  task_id: string;
@@ -95,6 +96,7 @@ export interface SuperpowersTaskState {
95
96
  acceptance_target_status: string;
96
97
  audit_task_complete: boolean;
97
98
  completion_basis: string[];
99
+ next_required_actions?: string[];
98
100
  };
99
101
  }
100
102
  export interface SuperpowersSourceRecord {
@@ -112,6 +114,20 @@ export interface SuperpowersProductArchitectureScope {
112
114
  representative_samples_validate: string[];
113
115
  representative_samples_do_not_validate: string[];
114
116
  out_of_scope_backlog: string[];
117
+ scope_fit_decision: SuperpowersScopeFitDecision;
118
+ selected_scope_fit_slice: string;
119
+ owner_boundary: string;
120
+ primary_capability_path: string;
121
+ non_completing_outcomes: string[];
122
+ assertion_policy: string;
123
+ source_authority: string;
124
+ product_goal: string;
125
+ surface_ia_lock?: string;
126
+ decision_lock?: string;
127
+ context_delta?: string;
128
+ source_to_context_coverage?: string;
129
+ acceptance_semantics?: string;
130
+ impact?: string;
115
131
  }
116
132
  export interface SuperpowersProgressState {
117
133
  system_capability_progress: Record<string, unknown>;
@@ -130,10 +146,35 @@ export interface SuperpowersPlanItem {
130
146
  representative_samples: string[];
131
147
  full_population_boundary: string;
132
148
  non_required_population: string[];
149
+ owner_boundary: string;
150
+ primary_capability_path: string;
151
+ trigger_contract: string;
152
+ state_transition_contract: string;
153
+ observable_result_contract: string;
154
+ assertion_support: string;
155
+ required_assertion_commands: string[];
156
+ invalid_implementation_shortcuts: string[];
133
157
  owner_surfaces: string[];
134
158
  forbidden_surfaces: string[];
135
159
  implementation_paths: string[];
136
160
  required_tests: string[];
161
+ proof_layer_ids?: string[];
162
+ requirement_ref?: string;
163
+ decision_id?: string;
164
+ api_schema_changes?: string;
165
+ state_machine?: string;
166
+ data_flow?: string;
167
+ worker_runtime_behavior?: string;
168
+ ui_ia_changes?: string;
169
+ migration_plan?: string;
170
+ evidence_artifacts?: string[];
171
+ non_completing_shortcuts?: string[];
172
+ substitution_policy?: string[];
173
+ drift_severity?: string;
174
+ partial_conditions?: string[];
175
+ blockers?: string[];
176
+ explicit_no_test_scope?: boolean;
177
+ context_fact_refs?: string[];
137
178
  status: SuperpowersPlanItemStatus;
138
179
  related_acs: string[];
139
180
  required_proof_layers: string[];
@@ -150,8 +191,44 @@ export interface SuperpowersAcceptanceCriterion {
150
191
  full_population_required: boolean | null;
151
192
  related_plan_items: string[];
152
193
  required_proof_layers: string[];
194
+ assertion_requirements?: AssertionRequirement[];
195
+ assertion_command?: string;
196
+ assertion_artifacts?: string[];
197
+ positive_assertions?: string[];
198
+ negative_assertions?: string[];
199
+ machine_blocking?: boolean | null;
200
+ invalid_completion_signals?: string[];
201
+ assertion_result_required?: boolean | null;
202
+ ac_type?: string;
203
+ proof_chain?: string[];
204
+ required_test_ids?: string[];
205
+ fail_conditions?: string[];
206
+ invalid_evidence?: string[];
207
+ substitution_policy?: string[];
208
+ missing_layer_downgrade?: string;
209
+ auditor_expectation?: string;
210
+ out_of_scope_na_approval_source?: string;
211
+ hard_blockers?: string[];
212
+ validates_explanation?: string;
213
+ does_not_validate_explanation?: string;
214
+ final_evidence_expected?: string[];
215
+ verification_method?: string[];
216
+ test_cases?: string[];
217
+ explicit_no_test_scope?: boolean;
153
218
  status: SuperpowersAcceptanceStatus;
154
219
  }
220
+ export interface AssertionRequirement {
221
+ proof_layer: string;
222
+ required: boolean;
223
+ machine_blocking: boolean;
224
+ assertion_result_required?: boolean;
225
+ assertion_command?: string;
226
+ assertion_artifacts?: string[];
227
+ invalid_completion_signals?: string[];
228
+ required_test_ids: string[];
229
+ positive_assertions: string[];
230
+ negative_assertions: string[];
231
+ }
155
232
  export interface SuperpowersProofLayer {
156
233
  required: boolean;
157
234
  status: SuperpowersProofLayerStatus;
@@ -190,6 +267,7 @@ export interface SuperpowersEvidenceRecord {
190
267
  stale_after: string | null;
191
268
  };
192
269
  command?: string;
270
+ command_exit_code?: number;
193
271
  artifact_paths: string[];
194
272
  proves: string[];
195
273
  does_not_prove: string[];
@@ -201,8 +279,49 @@ export interface SuperpowersEvidenceRecord {
201
279
  external_reviewer_can_reproduce: boolean;
202
280
  reproduction_steps: string;
203
281
  };
282
+ assertion_result?: AssertionResult;
283
+ negative_evidence_scan?: NegativeEvidenceScan;
204
284
  sibling_substitution_used?: boolean;
205
285
  sibling_substitution_approval_source?: string;
206
286
  }
287
+ export interface AssertionResult {
288
+ schema_version: "assertion-result-v1";
289
+ status: "passed" | "failed" | "blocked" | "stale";
290
+ runner: string;
291
+ exit_code: number;
292
+ target_ac_ids: string[];
293
+ target_proof_layers: string[];
294
+ owner_surface?: string;
295
+ route?: string;
296
+ action?: string;
297
+ positive_assertions: AssertionCheck[];
298
+ negative_assertions: AssertionCheck[];
299
+ artifacts?: string[];
300
+ }
301
+ export interface AssertionCheck {
302
+ id: string;
303
+ status: "passed" | "failed" | "blocked" | "stale";
304
+ actual?: string;
305
+ expected?: string;
306
+ forbidden_text?: string;
307
+ }
308
+ export interface NegativeEvidenceScan {
309
+ schema_version: "negative-evidence-scan-v1";
310
+ status: "passed" | "failed" | "blocked" | "stale";
311
+ target_ac_ids: string[];
312
+ target_proof_layers?: string[];
313
+ invalid_completion_signals_checked?: string[];
314
+ owner_surface?: string;
315
+ route?: string;
316
+ forbidden_findings: NegativeFinding[];
317
+ required_findings: AssertionCheck[];
318
+ artifacts: string[];
319
+ }
320
+ export interface NegativeFinding {
321
+ id: string;
322
+ status: "found" | "not_found";
323
+ forbidden_text?: string;
324
+ actual?: string;
325
+ }
207
326
  export declare function isRecord(value: unknown): value is Record<string, unknown>;
208
327
  export declare function asStringArray(value: unknown): string[];