@peterxiaoyang/superspec 0.1.14 → 0.1.16-alpha

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 (131) hide show
  1. package/README.md +37 -36
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +301 -0
  4. package/dist/format.d.ts +29 -0
  5. package/dist/format.js +141 -0
  6. package/dist/install.d.ts +18 -0
  7. package/dist/install.js +161 -0
  8. package/dist/next.d.ts +3 -0
  9. package/dist/next.js +161 -0
  10. package/dist/openspec.d.ts +9 -0
  11. package/dist/openspec.js +41 -0
  12. package/dist/record.d.ts +20 -0
  13. package/dist/record.js +266 -0
  14. package/dist/skill_loop.d.ts +23 -0
  15. package/dist/skill_loop.js +58 -0
  16. package/dist/store.d.ts +31 -0
  17. package/dist/store.js +213 -0
  18. package/dist/sync.d.ts +3 -0
  19. package/dist/sync.js +135 -0
  20. package/dist/task.d.ts +7 -0
  21. package/dist/task.js +44 -0
  22. package/dist/transition.d.ts +34 -0
  23. package/dist/transition.js +400 -0
  24. package/dist/types.d.ts +141 -0
  25. package/dist/types.js +3 -0
  26. package/package.json +8 -53
  27. package/templates/workflow/agents/architect.toml +13 -0
  28. package/{adapters/codex → templates/workflow}/agents/code-reviewer.toml +2 -2
  29. package/templates/workflow/agents/critic.toml +13 -0
  30. package/{adapters/codex → templates/workflow}/agents/executor.toml +2 -2
  31. package/{adapters/codex → templates/workflow}/agents/explore.toml +3 -3
  32. package/templates/workflow/agents/final-audit.toml +13 -0
  33. package/templates/workflow/agents/proposal-auditor.toml +13 -0
  34. package/{adapters/codex → templates/workflow}/agents/test-engineer.toml +4 -4
  35. package/{adapters/codex → templates/workflow}/agents/test-runner.toml +2 -2
  36. package/{adapters/codex → templates/workflow}/agents/verifier.toml +2 -2
  37. package/templates/workflow/prompts/architect.md +16 -0
  38. package/templates/workflow/prompts/critic.md +16 -0
  39. package/templates/workflow/prompts/explore.md +1 -1
  40. package/templates/workflow/prompts/final-audit.md +32 -0
  41. package/templates/workflow/prompts/proposal-auditor.md +34 -0
  42. package/templates/workflow/prompts/test-engineer.md +16 -0
  43. package/templates/workflow/skills/superspec-apply/SKILL.md +39 -121
  44. package/templates/workflow/skills/superspec-archive/SKILL.md +17 -49
  45. package/templates/workflow/skills/superspec-explore/SKILL.md +34 -70
  46. package/templates/workflow/skills/superspec-propose/SKILL.md +57 -60
  47. package/templates/workflow/skills/superspec-review/SKILL.md +18 -85
  48. package/adapters/codex/agents/architect.toml +0 -13
  49. package/adapters/codex/agents/critic.toml +0 -13
  50. package/adapters/codex/install-map.json +0 -116
  51. package/bin/launch.js +0 -37
  52. package/bin/superspec-check.js +0 -4
  53. package/bin/superspec-hook.js +0 -4
  54. package/bin/superspec-init.js +0 -4
  55. package/bin/superspec.js +0 -4
  56. package/dist/src/apply_worker_chain.d.ts +0 -60
  57. package/dist/src/apply_worker_chain.js +0 -1283
  58. package/dist/src/apply_worker_chain_lifecycle.d.ts +0 -21
  59. package/dist/src/apply_worker_chain_lifecycle.js +0 -409
  60. package/dist/src/archive.d.ts +0 -23
  61. package/dist/src/archive.js +0 -430
  62. package/dist/src/cli.d.ts +0 -1
  63. package/dist/src/cli.js +0 -33
  64. package/dist/src/cli_args.d.ts +0 -32
  65. package/dist/src/cli_args.js +0 -454
  66. package/dist/src/core.d.ts +0 -20
  67. package/dist/src/core.js +0 -394
  68. package/dist/src/disclosure.d.ts +0 -35
  69. package/dist/src/disclosure.js +0 -671
  70. package/dist/src/doctor.d.ts +0 -44
  71. package/dist/src/doctor.js +0 -230
  72. package/dist/src/evidence.d.ts +0 -29
  73. package/dist/src/evidence.js +0 -1107
  74. package/dist/src/gates.d.ts +0 -19
  75. package/dist/src/gates.js +0 -1631
  76. package/dist/src/git.d.ts +0 -8
  77. package/dist/src/git.js +0 -112
  78. package/dist/src/hooks/adapter.d.ts +0 -5
  79. package/dist/src/hooks/adapter.js +0 -347
  80. package/dist/src/hooks/guard_api.d.ts +0 -12
  81. package/dist/src/hooks/guard_api.js +0 -797
  82. package/dist/src/hooks/health.d.ts +0 -4
  83. package/dist/src/hooks/health.js +0 -86
  84. package/dist/src/hooks/policy_event.d.ts +0 -41
  85. package/dist/src/hooks/policy_event.js +0 -2634
  86. package/dist/src/hooks/types.d.ts +0 -72
  87. package/dist/src/hooks/types.js +0 -1
  88. package/dist/src/hooks/validation.d.ts +0 -3
  89. package/dist/src/hooks/validation.js +0 -70
  90. package/dist/src/i18n.d.ts +0 -21
  91. package/dist/src/i18n.js +0 -720
  92. package/dist/src/init_cli.d.ts +0 -28
  93. package/dist/src/init_cli.js +0 -404
  94. package/dist/src/install_engine.d.ts +0 -71
  95. package/dist/src/install_engine.js +0 -538
  96. package/dist/src/invariants.d.ts +0 -16
  97. package/dist/src/invariants.js +0 -363
  98. package/dist/src/openspec.d.ts +0 -37
  99. package/dist/src/openspec.js +0 -274
  100. package/dist/src/packet_render.d.ts +0 -5
  101. package/dist/src/packet_render.js +0 -1767
  102. package/dist/src/packet_schema.d.ts +0 -59
  103. package/dist/src/packet_schema.js +0 -1
  104. package/dist/src/paths.d.ts +0 -22
  105. package/dist/src/paths.js +0 -203
  106. package/dist/src/project_init.d.ts +0 -33
  107. package/dist/src/project_init.js +0 -191
  108. package/dist/src/self_update.d.ts +0 -14
  109. package/dist/src/self_update.js +0 -56
  110. package/dist/src/state.d.ts +0 -37
  111. package/dist/src/state.js +0 -464
  112. package/dist/src/tasks.d.ts +0 -38
  113. package/dist/src/tasks.js +0 -373
  114. package/dist/src/util.d.ts +0 -163
  115. package/dist/src/util.js +0 -792
  116. package/dist/superspec.d.ts +0 -6
  117. package/dist/superspec.js +0 -97
  118. package/dist/superspec_guard.d.ts +0 -4
  119. package/dist/superspec_guard.js +0 -19
  120. package/dist/superspec_hook.d.ts +0 -4
  121. package/dist/superspec_hook.js +0 -35
  122. package/dist/superspec_init.d.ts +0 -2
  123. package/dist/superspec_init.js +0 -17
  124. package/schemas/hook-event.schema.json +0 -27
  125. package/schemas/install-manifest.schema.json +0 -97
  126. package/templates/hooks/codex-hooks.json +0 -35
  127. package/templates/sidecar/archive-preservation.json +0 -11
  128. package/templates/sidecar/business-invariants.md +0 -38
  129. package/templates/sidecar/config.yaml +0 -13
  130. package/templates/sidecar/discovery.md +0 -33
  131. package/templates/sidecar/test-contract.md +0 -27
@@ -1,21 +0,0 @@
1
- import type { JsonMap, Reason } from "./util.ts";
2
- export type TakeoverBaseline = {
3
- fingerprint: unknown;
4
- successorGreenRefs: string[];
5
- };
6
- export type ApplyWorkerChainLifecycleState = {
7
- completionReasons: Reason[];
8
- packetBlockers: Reason[];
9
- activeBlockingReasons: Reason[];
10
- activePresence: "none" | "single_open" | "blocked";
11
- active: JsonMap | null;
12
- openActiveChainIds: Set<string>;
13
- validTerminalChainIds: Set<string>;
14
- validClosedChainIds: Set<string>;
15
- validClosedGreenEvidenceIds: Set<string>;
16
- validClosedAlternativeEvidenceIds: Set<string>;
17
- validClosedAlternativeChainIds: Set<string>;
18
- takeoverbaselines: TakeoverBaseline[];
19
- };
20
- export declare function apply_worker_chain_lifecycle_state(repoRoot: string, changeRoot: string, evidences: JsonMap[], taskId: string): ApplyWorkerChainLifecycleState;
21
- export declare function apply_worker_chain_lifecycle_reasons(repoRoot: string, changeRoot: string, evidences: JsonMap[], taskId: string): Reason[];
@@ -1,409 +0,0 @@
1
- import { NO_TDD_REASONS, isObject, reason, renderList, repr } from "./util.js";
2
- import { find_pass, live_pass, live_user_confirmations } from "./evidence.js";
3
- import { effective_superseded_ids } from "./openspec.js";
4
- import { apply_worker_implementation_fingerprint, apply_worker_executor_input_ref_digest, compute_apply_worker_freshness, fingerprint_matches, pinned_artifact_ref_reasons as shared_pinned_artifact_ref_reasons, pre_edit_evidence_ref_reasons, read_pinned_artifact_json, worker_input_ref_digest, worker_test_run_reasons, } from "./apply_worker_chain.js";
5
- function pinned_artifact_ref_matches(changeRoot, refItem, role, taskId, chainId, kind = "worker_report") {
6
- return shared_pinned_artifact_ref_reasons(changeRoot, refItem, `${role}_ref`, { kind, role, taskId, chainId }).length === 0;
7
- }
8
- function executor_worker_test_run_refs_valid(changeRoot, ev, taskId, chainId) {
9
- return worker_test_run_reasons(changeRoot, ev, taskId, chainId).length === 0;
10
- }
11
- function report_origin_matches(refItem, expected) {
12
- return isObject(refItem) && typeof expected === "string" && refItem.origin_packet_fingerprint === expected;
13
- }
14
- function report_input_refs_match(refItem, refs) {
15
- return isObject(refItem) && refItem.input_ref_digest === worker_input_ref_digest(refs);
16
- }
17
- function report_input_digest_matches(refItem, expectedDigest) {
18
- return isObject(refItem) && refItem.input_ref_digest === expectedDigest;
19
- }
20
- function chain_green_ids(ev) {
21
- if (Array.isArray(ev.green_test_run_evidence_refs)) {
22
- return ev.green_test_run_evidence_refs.map(String).filter(Boolean).sort();
23
- }
24
- const greenId = isObject(ev.green_test_run_evidence_ref)
25
- ? String(ev.green_test_run_evidence_ref.evidence_id ?? "")
26
- : String(ev.green_test_run_evidence_ref ?? "");
27
- return greenId ? [greenId] : [];
28
- }
29
- function chain_alternative_ids(ev) {
30
- const refs = new Set();
31
- if (Array.isArray(ev.alternative_verification_evidence_refs)) {
32
- for (const item of ev.alternative_verification_evidence_refs) {
33
- if (isObject(item) && typeof item.evidence_id === "string" && item.evidence_id)
34
- refs.add(item.evidence_id);
35
- else if (typeof item === "string" && item)
36
- refs.add(item);
37
- }
38
- }
39
- const single = ev.alternative_verification_evidence_ref;
40
- if (isObject(single) && typeof single.evidence_id === "string" && single.evidence_id)
41
- refs.add(single.evidence_id);
42
- else if (typeof single === "string" && single)
43
- refs.add(single);
44
- return [...refs].sort();
45
- }
46
- function active_pre_edit_input_refs(evidences, active) {
47
- const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String) : [];
48
- return preIds.map((evidenceId) => {
49
- const ev = live_pass(evidences, { kind: "test_run" }).find((item) => String(item.evidence_id ?? "") === evidenceId);
50
- return ev
51
- ? { kind: "test_run", evidence_id: evidenceId, phase: ev.phase, semantic_status: ev.semantic_status }
52
- : { kind: "test_run", evidence_id: evidenceId };
53
- });
54
- }
55
- function active_chain_verifier_input_ref(active) {
56
- const result = {
57
- kind: "apply_worker_chain",
58
- evidence_id: active.evidence_id,
59
- task_id: active.task_id,
60
- apply_worker_chain_id: active.apply_worker_chain_id,
61
- pre_edit_proof_kind: active.pre_edit_proof_kind ?? "red_or_characterization",
62
- pre_edit_evidence_refs: Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean).sort() : [],
63
- };
64
- for (const field of ["apply_execution_surface", "tdd_required", "no_tdd_reason"]) {
65
- if (active[field] !== undefined)
66
- result[field] = active[field];
67
- }
68
- return result;
69
- }
70
- function active_no_tdd_declared_valid(active) {
71
- const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean) : [];
72
- return active.pre_edit_proof_kind === "no_tdd_declared"
73
- && preIds.length === 0
74
- && active.tdd_required === false
75
- && (active.apply_execution_surface === "implementation" || active.apply_execution_surface === "runtime_config")
76
- && NO_TDD_REASONS.has(String(active.no_tdd_reason ?? ""));
77
- }
78
- function alternative_evidence_input_ref(ev) {
79
- return {
80
- kind: ev.kind,
81
- evidence_id: ev.evidence_id,
82
- gate: ev.gate,
83
- task_id: ev.task_id,
84
- };
85
- }
86
- function closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId) {
87
- const active = live_pass(evidences, { gate: "task_complete", kind: "apply_worker_chain", task_id: taskId })
88
- .find((item) => item.chain_state === "active" && item.apply_worker_chain_id === chainId);
89
- if (!active)
90
- return false;
91
- if (!pinned_artifact_ref_matches(changeRoot, ev.executor_report_ref, "executor", taskId, chainId))
92
- return false;
93
- if (!pinned_artifact_ref_matches(changeRoot, ev.task_code_review_report_ref, "code-reviewer", taskId, chainId))
94
- return false;
95
- if (!pinned_artifact_ref_matches(changeRoot, ev.verifier_report_ref, "verifier", taskId, chainId))
96
- return false;
97
- if (!report_origin_matches(ev.executor_report_ref, active.executor_packet_fingerprint))
98
- return false;
99
- if (!report_input_digest_matches(ev.executor_report_ref, apply_worker_executor_input_ref_digest(evidences, active)))
100
- return false;
101
- if (!report_input_refs_match(ev.task_code_review_report_ref, [ev.executor_report_ref]))
102
- return false;
103
- if (typeof ev.observed_freshness_fingerprint !== "string" && !(isObject(ev.observed_freshness_fingerprint) && typeof ev.observed_freshness_fingerprint.fingerprint_digest === "string"))
104
- return false;
105
- const verifierReport = read_pinned_artifact_json(changeRoot, ev.verifier_report_ref);
106
- const verifierObserved = verifierReport?.observed_freshness_fingerprint ?? (isObject(ev.verifier_report_ref) ? ev.verifier_report_ref.observed_freshness_fingerprint : undefined);
107
- if (!fingerprint_matches(verifierObserved, ev.observed_freshness_fingerprint))
108
- return false;
109
- const completionProofKind = String(ev.completion_proof_kind ?? "green_tests");
110
- if (completionProofKind !== "green_tests" && completionProofKind !== "alternative_verification")
111
- return false;
112
- const preEditProofKind = String(active.pre_edit_proof_kind ?? "red_or_characterization");
113
- if (completionProofKind === "green_tests" && preEditProofKind !== "red_or_characterization")
114
- return false;
115
- if (completionProofKind === "alternative_verification" && !active_no_tdd_declared_valid(active))
116
- return false;
117
- if (pre_edit_evidence_ref_reasons(changeRoot, evidences, active, taskId).length > 0)
118
- return false;
119
- if (completionProofKind === "alternative_verification") {
120
- const alternativeIds = chain_alternative_ids(ev);
121
- if (alternativeIds.length === 0)
122
- return false;
123
- const alternatives = alternativeIds.map((evidenceId) => live_pass(evidences, { gate: "task_complete", task_id: taskId })
124
- .find((item) => (String(item.evidence_id ?? "") === evidenceId
125
- && (item.kind === "alternative_verification" || item.kind === "manual_verification")))).filter((item) => isObject(item));
126
- if (alternatives.length !== alternativeIds.length)
127
- return false;
128
- if (!report_input_refs_match(ev.verifier_report_ref, [
129
- ev.executor_report_ref,
130
- ev.task_code_review_report_ref,
131
- ...alternatives.map(alternative_evidence_input_ref),
132
- active_chain_verifier_input_ref(active),
133
- ]))
134
- return false;
135
- const currentFreshness = compute_apply_worker_freshness(repoRoot, changeRoot, evidences, taskId, chainId, {
136
- executor_report_ref: ev.executor_report_ref,
137
- task_code_review_report_ref: ev.task_code_review_report_ref,
138
- alternative_verification_evidence_refs: alternativeIds,
139
- completion_proof_kind: "alternative_verification",
140
- verifier_report_ref: ev.verifier_report_ref,
141
- });
142
- if (Array.isArray(currentFreshness.unexpected_guard_owned_dirty_paths) && currentFreshness.unexpected_guard_owned_dirty_paths.length > 0)
143
- return false;
144
- if (Array.isArray(currentFreshness.protected_dirty_paths) && currentFreshness.protected_dirty_paths.length > 0)
145
- return false;
146
- if (!fingerprint_matches(isObject(ev.task_code_review_report_ref) ? ev.task_code_review_report_ref.observed_implementation_fingerprint : undefined, currentFreshness.implementation_fingerprint))
147
- return false;
148
- return fingerprint_matches(currentFreshness, verifierObserved);
149
- }
150
- const greenIds = chain_green_ids(ev);
151
- if (greenIds.length === 0)
152
- return false;
153
- const greenRuns = greenIds.map((greenId) => live_pass(evidences, { gate: "task_complete", kind: "test_run", task_id: taskId }).find((item) => (String(item.evidence_id ?? "") === greenId
154
- && item.semantic_status === "expected_success"
155
- && (item.phase === undefined || item.phase === "green")
156
- && item.apply_execution_chain === "executor_worker"
157
- && item.apply_worker_chain_id === chainId
158
- && executor_worker_test_run_refs_valid(changeRoot, item, taskId, chainId)))).filter((item) => isObject(item));
159
- if (greenRuns.length !== greenIds.length)
160
- return false;
161
- if (!report_input_refs_match(ev.verifier_report_ref, [
162
- ev.executor_report_ref,
163
- ev.task_code_review_report_ref,
164
- ...greenRuns.map((green) => ({ kind: "test_run", evidence_id: String(green.evidence_id ?? ""), phase: green.phase, semantic_status: green.semantic_status })),
165
- ...active_pre_edit_input_refs(evidences, active),
166
- ]))
167
- return false;
168
- const currentFreshness = compute_apply_worker_freshness(repoRoot, changeRoot, evidences, taskId, chainId, {
169
- executor_report_ref: ev.executor_report_ref,
170
- task_code_review_report_ref: ev.task_code_review_report_ref,
171
- green_test_run_evidence_ref: greenIds[0],
172
- green_test_run_evidence_refs: greenIds,
173
- completion_proof_kind: "green_tests",
174
- verifier_report_ref: ev.verifier_report_ref,
175
- });
176
- if (Array.isArray(currentFreshness.unexpected_guard_owned_dirty_paths) && currentFreshness.unexpected_guard_owned_dirty_paths.length > 0)
177
- return false;
178
- if (Array.isArray(currentFreshness.protected_dirty_paths) && currentFreshness.protected_dirty_paths.length > 0)
179
- return false;
180
- if (!greenRuns.every((green) => fingerprint_matches(green.implementation_fingerprint, currentFreshness.implementation_fingerprint)))
181
- return false;
182
- if (!fingerprint_matches(isObject(ev.task_code_review_report_ref) ? ev.task_code_review_report_ref.observed_implementation_fingerprint : undefined, currentFreshness.implementation_fingerprint))
183
- return false;
184
- return fingerprint_matches(currentFreshness, verifierObserved);
185
- }
186
- function pinned_takeover_baseline_valid(changeRoot, refItem, taskId, chainId) {
187
- return shared_pinned_artifact_ref_reasons(changeRoot, refItem, "serial_takeover_baseline_ref", { kind: "status_report", role: "verifier", taskId, chainId }).length === 0;
188
- }
189
- function serial_takeover_baseline_ref_ids(ev) {
190
- const refs = new Set();
191
- if (isObject(ev.serial_takeover_baseline_ref)) {
192
- for (const field of ["path", "ref_path", "evidence_id"]) {
193
- const value = ev.serial_takeover_baseline_ref[field];
194
- if (typeof value === "string" && value)
195
- refs.add(value);
196
- }
197
- }
198
- return [...refs].sort();
199
- }
200
- function serial_takeover_confirmation_valid(evidences, ev, active) {
201
- const confirmationId = String(ev.takeover_confirmation_evidence_id ?? "");
202
- const activeId = String(active.evidence_id ?? "");
203
- const baselineIds = serial_takeover_baseline_ref_ids(ev);
204
- if (!confirmationId || !activeId || baselineIds.length === 0)
205
- return false;
206
- const confirmation = live_user_confirmations(evidences, "serial_takeover")
207
- .find((item) => String(item.evidence_id ?? "") === confirmationId);
208
- if (!confirmation)
209
- return false;
210
- const confirmed = new Set(Array.isArray(confirmation.confirmed_refs) ? confirmation.confirmed_refs.map(String).filter(Boolean) : []);
211
- return confirmed.has(activeId) && baselineIds.some((item) => confirmed.has(item));
212
- }
213
- function abandoned_apply_worker_chain_valid(repoRoot, changeRoot, ev, active, evidences, taskId, chainId) {
214
- if (!active)
215
- return false;
216
- const hasRestored = "restored_implementation_fingerprint" in ev;
217
- const hasSerialTakeover = "serial_takeover_baseline_ref" in ev;
218
- if (hasRestored && hasSerialTakeover)
219
- return false;
220
- if ("restored_implementation_fingerprint" in ev) {
221
- const activeScope = Array.isArray(active.declared_task_write_scope) ? active.declared_task_write_scope.map(String).filter(Boolean) : [];
222
- const current = apply_worker_implementation_fingerprint(repoRoot, changeRoot, [], { declaredTaskWriteScope: activeScope });
223
- if (fingerprint_matches(ev.restored_implementation_fingerprint, active.source_implementation_fingerprint)
224
- && fingerprint_matches(current, active.source_implementation_fingerprint))
225
- return true;
226
- }
227
- if (hasSerialTakeover) {
228
- return pinned_takeover_baseline_valid(changeRoot, ev.serial_takeover_baseline_ref, taskId, chainId)
229
- && serial_takeover_confirmation_valid(evidences, ev, active);
230
- }
231
- return false;
232
- }
233
- export function apply_worker_chain_lifecycle_state(repoRoot, changeRoot, evidences, taskId) {
234
- const chains = find_pass(evidences, { gate: "task_complete", kind: "apply_worker_chain", task_id: taskId });
235
- const supersededIds = effective_superseded_ids(evidences);
236
- const liveChainMarker = (ev) => !supersededIds.has(String(ev.evidence_id ?? ""));
237
- const activeByChain = new Map();
238
- const activeCounts = new Map();
239
- for (const ev of chains) {
240
- if (String(ev.chain_state ?? "") !== "active")
241
- continue;
242
- const chainId = String(ev.apply_worker_chain_id ?? "");
243
- if (!chainId)
244
- continue;
245
- const bucket = activeCounts.get(chainId) ?? [];
246
- bucket.push(ev);
247
- activeCounts.set(chainId, bucket);
248
- if (!activeByChain.has(chainId))
249
- activeByChain.set(chainId, ev);
250
- }
251
- const chainIdsWithActive = new Set([...activeByChain.keys()]);
252
- const terminalValidity = new Map();
253
- const chainIdsWithTerminal = new Set(chains
254
- .filter((ev) => {
255
- const chainId = String(ev.apply_worker_chain_id ?? "");
256
- if (!chainId)
257
- return false;
258
- let valid = false;
259
- if (String(ev.chain_state ?? "") === "closed")
260
- valid = closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId);
261
- if (String(ev.chain_state ?? "") === "abandoned")
262
- valid = abandoned_apply_worker_chain_valid(repoRoot, changeRoot, ev, activeByChain.get(chainId), evidences, taskId, chainId);
263
- terminalValidity.set(ev, valid);
264
- return valid && liveChainMarker(ev);
265
- })
266
- .map((ev) => String(ev.apply_worker_chain_id ?? ""))
267
- .filter(Boolean));
268
- const openActiveChainIds = new Set([...activeByChain.keys()].filter((chainId) => !chainIdsWithTerminal.has(chainId)));
269
- const validClosedChainIds = new Set(chains
270
- .filter((ev) => {
271
- const chainId = String(ev.apply_worker_chain_id ?? "");
272
- const valid = String(ev.chain_state ?? "") === "closed" && (terminalValidity.get(ev) ?? closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId));
273
- return chainId && valid && liveChainMarker(ev);
274
- })
275
- .map((ev) => String(ev.apply_worker_chain_id ?? ""))
276
- .filter(Boolean));
277
- const validClosedGreenEvidenceIds = new Set(chains
278
- .filter((ev) => {
279
- const chainId = String(ev.apply_worker_chain_id ?? "");
280
- const valid = String(ev.chain_state ?? "") === "closed" && (terminalValidity.get(ev) ?? closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId));
281
- return chainId && valid && liveChainMarker(ev);
282
- })
283
- .flatMap(chain_green_ids));
284
- const validClosedAlternativeChainIds = new Set(chains
285
- .filter((ev) => {
286
- const chainId = String(ev.apply_worker_chain_id ?? "");
287
- const valid = String(ev.chain_state ?? "") === "closed" && String(ev.completion_proof_kind ?? "green_tests") === "alternative_verification" && (terminalValidity.get(ev) ?? closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId));
288
- return chainId && valid && liveChainMarker(ev);
289
- })
290
- .map((ev) => String(ev.apply_worker_chain_id ?? ""))
291
- .filter(Boolean));
292
- const validClosedAlternativeEvidenceIds = new Set(chains
293
- .filter((ev) => {
294
- const chainId = String(ev.apply_worker_chain_id ?? "");
295
- const valid = String(ev.chain_state ?? "") === "closed" && String(ev.completion_proof_kind ?? "green_tests") === "alternative_verification" && (terminalValidity.get(ev) ?? closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId));
296
- return chainId && valid && liveChainMarker(ev);
297
- })
298
- .flatMap(chain_alternative_ids));
299
- const completionReasons = [];
300
- const duplicateActives = [...activeCounts.entries()]
301
- .filter(([chainId]) => openActiveChainIds.has(chainId))
302
- .map(([, items]) => items)
303
- .filter((items) => items.length > 1)
304
- .flatMap((items) => items.map((ev) => String(ev.evidence_id ?? ev.apply_worker_chain_id ?? "")))
305
- .filter(Boolean)
306
- .sort();
307
- const openActiveValues = [...openActiveChainIds].map((chainId) => activeByChain.get(chainId)).filter((ev) => isObject(ev));
308
- const parallelActives = openActiveValues.length > 1
309
- ? openActiveValues.map((ev) => String(ev.evidence_id ?? ev.apply_worker_chain_id ?? "")).filter(Boolean).sort()
310
- : [];
311
- const activeConflicts = [...new Set([...duplicateActives, ...parallelActives])].sort();
312
- if (activeConflicts.length > 0) {
313
- completionReasons.push(reason("apply_worker_chain_active_conflict", `task ${taskId} has conflicting active apply worker chain markers: ${renderList(activeConflicts)}`, activeConflicts));
314
- }
315
- const terminalsByChain = new Map();
316
- for (const ev of chains) {
317
- const state = String(ev.chain_state ?? "");
318
- if (state !== "closed" && state !== "abandoned")
319
- continue;
320
- const chainId = String(ev.apply_worker_chain_id ?? "");
321
- if (!chainId)
322
- continue;
323
- const bucket = terminalsByChain.get(chainId) ?? [];
324
- bucket.push(ev);
325
- terminalsByChain.set(chainId, bucket);
326
- }
327
- const duplicateTerminals = [...terminalsByChain.values()]
328
- .filter((items) => items.length > 1)
329
- .flatMap((items) => items.map((ev) => String(ev.evidence_id ?? ev.apply_worker_chain_id ?? "")))
330
- .filter(Boolean)
331
- .sort();
332
- if (duplicateTerminals.length > 0) {
333
- completionReasons.push(reason("apply_worker_chain_terminal_conflict", `task ${taskId} has duplicate apply worker chain terminal markers: ${renderList(duplicateTerminals)}`, duplicateTerminals));
334
- }
335
- const takeoverbaselines = [];
336
- const invalidTerminals = chains
337
- .filter((ev) => String(ev.chain_state ?? "") === "closed" || String(ev.chain_state ?? "") === "abandoned")
338
- .filter((ev) => {
339
- const chainId = String(ev.apply_worker_chain_id ?? "");
340
- if (!chainId)
341
- return true;
342
- if (String(ev.chain_state ?? "") === "closed")
343
- return !(terminalValidity.get(ev) ?? closed_apply_worker_chain_valid(repoRoot, changeRoot, ev, evidences, taskId, chainId));
344
- const valid = terminalValidity.get(ev) ?? abandoned_apply_worker_chain_valid(repoRoot, changeRoot, ev, activeByChain.get(chainId), evidences, taskId, chainId);
345
- if (valid && isObject(ev.serial_takeover_baseline_ref)) {
346
- const baseline = read_pinned_artifact_json(changeRoot, ev.serial_takeover_baseline_ref);
347
- if (baseline?.implementation_fingerprint !== undefined) {
348
- takeoverbaselines.push({
349
- fingerprint: baseline.implementation_fingerprint,
350
- successorGreenRefs: Array.isArray(ev.successor_green_evidence_refs) ? ev.successor_green_evidence_refs.map(String).filter(Boolean) : [],
351
- });
352
- }
353
- }
354
- return !valid;
355
- })
356
- .map((ev) => String(ev.evidence_id ?? ev.apply_worker_chain_id ?? ""))
357
- .filter(Boolean)
358
- .sort();
359
- if (invalidTerminals.length > 0) {
360
- completionReasons.push(reason("apply_worker_chain_terminal_invalid", `task ${taskId} has invalid apply worker chain terminal markers: ${renderList(invalidTerminals)}`, invalidTerminals));
361
- }
362
- for (const chainId of [...openActiveChainIds].sort()) {
363
- if (!chainIdsWithTerminal.has(chainId)) {
364
- completionReasons.push(reason("apply_worker_chain_active", `task ${taskId} has active apply worker chain and cannot use non-chain task completion: ${chainId}`, [chainId]));
365
- }
366
- }
367
- for (const ev of evidences) {
368
- if (!isObject(ev) || ev._invalid || ev.status !== "pass" || ev.task_id !== taskId)
369
- continue;
370
- const chainId = typeof ev.apply_worker_chain_id === "string" ? ev.apply_worker_chain_id : "";
371
- if (!chainId)
372
- continue;
373
- if (!chainIdsWithActive.has(chainId)) {
374
- completionReasons.push(reason("apply_worker_chain_missing_active", `task ${taskId} references apply_worker_chain_id=${repr(chainId)} without a matching active marker`, [chainId]));
375
- }
376
- }
377
- if (duplicateTerminals.length > 0 || activeConflicts.length > 0) {
378
- validClosedChainIds.clear();
379
- validClosedGreenEvidenceIds.clear();
380
- validClosedAlternativeChainIds.clear();
381
- validClosedAlternativeEvidenceIds.clear();
382
- }
383
- const activeBlockingReasons = completionReasons.filter((item) => (item.code === "apply_worker_chain_active_conflict"
384
- || item.code === "apply_worker_chain_terminal_conflict"
385
- || item.code === "apply_worker_chain_terminal_invalid"
386
- || item.code === "apply_worker_chain_missing_active"));
387
- const activePresence = activeBlockingReasons.length > 0
388
- ? "blocked"
389
- : openActiveValues.length === 1
390
- ? "single_open"
391
- : "none";
392
- return {
393
- completionReasons,
394
- packetBlockers: activeBlockingReasons,
395
- activeBlockingReasons,
396
- activePresence,
397
- active: activePresence === "single_open" ? openActiveValues[0] : null,
398
- openActiveChainIds,
399
- validTerminalChainIds: chainIdsWithTerminal,
400
- validClosedChainIds,
401
- validClosedGreenEvidenceIds,
402
- validClosedAlternativeEvidenceIds,
403
- validClosedAlternativeChainIds,
404
- takeoverbaselines,
405
- };
406
- }
407
- export function apply_worker_chain_lifecycle_reasons(repoRoot, changeRoot, evidences, taskId) {
408
- return apply_worker_chain_lifecycle_state(repoRoot, changeRoot, evidences, taskId).completionReasons;
409
- }
@@ -1,23 +0,0 @@
1
- import type { Decision, JsonMap, Reason } from "./util.ts";
2
- export declare function archive_manifest_path(changeRoot: string): string;
3
- export declare function archive_preservation_dir(changeRoot: string): string;
4
- export declare function archive_preservation_manifest_path(changeRoot: string): string;
5
- export declare function sidecar_manifest_entries(changeRoot: string): JsonMap[];
6
- export declare function write_archive_manifest(change: string, changeRoot: string): string;
7
- export declare function begin_archive_preservation_bundle(change: string, changeRoot: string, opts?: {
8
- file_overrides?: Record<string, string>;
9
- }): {
10
- manifest_path: string;
11
- bundle_manifest_path: string;
12
- commit: () => void;
13
- rollback: () => void;
14
- };
15
- export declare function write_archive_preservation_bundle(change: string, changeRoot: string, opts?: {
16
- file_overrides?: Record<string, string>;
17
- }): string;
18
- export declare function find_archived_change(repoRoot: string, change: string): string | null;
19
- export declare function check_archived(change: string, repoRoot: string): Decision;
20
- export declare function check_archived_preservation_bundle(change: string, archived: string, manifestPath: string): Decision;
21
- export declare function preset_upgrade_required(preset: string, changedPaths: string[], flags?: JsonMap): boolean;
22
- export declare function preset_upgrade_reasons(config: JsonMap, changedPaths: string[], humanConfirmed?: boolean, flags?: JsonMap): Reason[];
23
- export declare function preset_upgrade_required_from_context(config: JsonMap, changedPaths: string[]): boolean;