@peterxiaoyang/superspec 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +4 -4
  2. package/adapters/codex/agents/explore.toml +13 -0
  3. package/adapters/codex/install-map.json +10 -0
  4. package/dist/src/apply_worker_chain.d.ts +6 -3
  5. package/dist/src/apply_worker_chain.js +125 -30
  6. package/dist/src/apply_worker_chain_lifecycle.d.ts +7 -5
  7. package/dist/src/apply_worker_chain_lifecycle.js +153 -22
  8. package/dist/src/cli_args.d.ts +1 -0
  9. package/dist/src/cli_args.js +33 -15
  10. package/dist/src/disclosure.js +2 -2
  11. package/dist/src/evidence.js +104 -8
  12. package/dist/src/gates.d.ts +1 -0
  13. package/dist/src/gates.js +160 -27
  14. package/dist/src/hooks/guard_api.js +2 -2
  15. package/dist/src/hooks/policy_event.js +11 -1
  16. package/dist/src/i18n.js +63 -3
  17. package/dist/src/init_cli.js +1 -1
  18. package/dist/src/openspec.d.ts +2 -0
  19. package/dist/src/openspec.js +31 -0
  20. package/dist/src/packet_render.d.ts +1 -0
  21. package/dist/src/packet_render.js +248 -31
  22. package/dist/src/packet_schema.d.ts +2 -0
  23. package/dist/src/tasks.d.ts +5 -0
  24. package/dist/src/tasks.js +62 -0
  25. package/dist/src/util.d.ts +4 -0
  26. package/dist/src/util.js +13 -0
  27. package/dist/superspec.js +4 -4
  28. package/package.json +3 -3
  29. package/templates/sidecar/discovery.md +9 -0
  30. package/templates/sidecar/test-contract.md +2 -1
  31. package/templates/workflow/prompts/code-reviewer.md +1 -1
  32. package/templates/workflow/prompts/executor.md +1 -1
  33. package/templates/workflow/prompts/explore.md +27 -0
  34. package/templates/workflow/prompts/test-engineer.md +1 -0
  35. package/templates/workflow/prompts/test-runner.md +3 -1
  36. package/templates/workflow/prompts/verifier.md +9 -9
  37. package/templates/workflow/skills/superspec-apply/SKILL.md +58 -33
  38. package/templates/workflow/skills/superspec-archive/SKILL.md +5 -5
  39. package/templates/workflow/skills/superspec-explore/SKILL.md +31 -13
  40. package/templates/workflow/skills/superspec-propose/SKILL.md +26 -15
  41. package/templates/workflow/skills/superspec-review/SKILL.md +17 -17
  42. package/dist/src/packet_measure.d.ts +0 -43
  43. package/dist/src/packet_measure.js +0 -382
  44. /package/bin/{superspec-guard.js → superspec-check.js} +0 -0
package/README.md CHANGED
@@ -246,10 +246,10 @@ superspec doctor
246
246
  SuperSpec 内部还有一些检查命令,例如:
247
247
 
248
248
  ```bash
249
- superspec guard check-init --change <变更ID>
250
- superspec guard check-apply-ready --change <变更ID>
251
- superspec guard check-review-ready --change <变更ID>
252
- superspec guard check-archive-ready --change <变更ID>
249
+ superspec check check-init --change <变更ID>
250
+ superspec check check-apply-ready --change <变更ID>
251
+ superspec check check-review-ready --change <变更ID>
252
+ superspec check check-archive-ready --change <变更ID>
253
253
  ```
254
254
 
255
255
  普通使用者通常不需要手动运行这些命令;对应的阶段入口会在需要时使用它们。
@@ -0,0 +1,13 @@
1
+ # oh-my-codex agent: explore
2
+ name = "explore"
3
+ description = "Repo-local read-only factual scan for SuperSpec discovery"
4
+ model_reasoning_effort = "xhigh"
5
+ developer_instructions = """
6
+ Role: Explore. Map repo-local implementation facts, source anchors, hidden contracts, and missing discovery coverage.
7
+
8
+ Prompt binding: load `.codex/prompts/explore.md` first, then read the task prompt, `workflow-packet`, or `prompt_ref`. Packet refs and stop conditions override static prompt memory.
9
+
10
+ Boundary: read-only. Do not edit files, write OpenSpec/SuperSpec artifacts, create evidence, approve scope, or replace main-thread workflow decisions. Report findings upward with concrete anchors.
11
+
12
+ Output: concise Simplified Chinese. Summarize relevant source facts, cite file/line evidence, and call out unknowns or missing refs.
13
+ """
@@ -52,6 +52,11 @@
52
52
  "source": "templates/workflow/prompts/executor.md",
53
53
  "target": ".codex/prompts/executor.md"
54
54
  },
55
+ {
56
+ "kind": "prompt",
57
+ "source": "templates/workflow/prompts/explore.md",
58
+ "target": ".codex/prompts/explore.md"
59
+ },
55
60
  {
56
61
  "kind": "prompt",
57
62
  "source": "templates/workflow/prompts/test-runner.md",
@@ -82,6 +87,11 @@
82
87
  "source": "adapters/codex/agents/critic.toml",
83
88
  "target": ".codex/agents/critic.toml"
84
89
  },
90
+ {
91
+ "kind": "agent",
92
+ "source": "adapters/codex/agents/explore.toml",
93
+ "target": ".codex/agents/explore.toml"
94
+ },
85
95
  {
86
96
  "kind": "agent",
87
97
  "source": "adapters/codex/agents/executor.toml",
@@ -32,7 +32,7 @@ export declare const APPLY_WORKER_MAX_INLINE_REPORT_CHARS = 12000;
32
32
  export declare const APPLY_TEST_RUNNER_REPORT_REQUIRED_FIELDS: readonly ["role", "command", "command_source", "cwd", "phase", "task_id", "test_id", "exit_code", "semantic_status_candidate", "result_summary", "runtime_raw_transcript_ref", "repo_head", "pre_dirty_state", "post_dirty_state", "changed_files", "untracked_files", "invariant_refs", "source_refs", "origin_packet_fingerprint", "input_ref_digest", "source_implementation_fingerprint", "observed_implementation_fingerprint", "guard_fingerprint", "unverified_items"];
33
33
  export declare const APPLY_EXECUTOR_REPORT_REQUIRED_FIELDS: readonly ["role", "task_id", "apply_worker_chain_id", "cwd", "repo_head", "guard_fingerprint", "changed_files", "suggested_green_checks", "test_invariant_mapping", "runtime_artifact_refs", "origin_packet_fingerprint", "input_ref_digest", "source_implementation_fingerprint", "produced_implementation_fingerprint", "unverified_items", "risk_notes"];
34
34
  export declare const APPLY_CODE_REVIEW_REPORT_REQUIRED_FIELDS: readonly ["role", "review_status_candidate", "cwd", "repo_head", "guard_fingerprint", "executor_report_ref", "actual_changed_files", "changed_files", "untracked_files", "implementation_dirty_file_list", "implementation_fingerprint", "guard_artifact_manifest_fingerprint", "scope_verdict", "protected_path_verdict", "executor_report_mismatch", "test_invariant_mapping_verdict", "suggested_green_test_ids", "risk_notes", "runtime_raw_git_status_transcript_ref", "runtime_raw_git_diff_name_status_transcript_ref", "runtime_path_scoped_diff_transcript_refs", "origin_packet_fingerprint", "input_ref_digest", "source_implementation_fingerprint", "observed_implementation_fingerprint", "unverified_items"];
35
- export declare const APPLY_VERIFIER_REPORT_REQUIRED_FIELDS: readonly ["role", "verification_status_candidate", "task_completion_verdict", "chain_consistency_verdict", "acceptance_coverage_verdict", "invariant_coverage_verdict", "test_coverage_verdict", "cwd", "repo_head", "guard_fingerprint", "expected_freshness_fingerprint", "observed_freshness_fingerprint", "freshness_verdict", "green_test_run_evidence_refs", "executor_report_ref", "task_code_review_report_ref", "actual_changed_files", "changed_files", "untracked_files", "implementation_dirty_file_list", "implementation_fingerprint", "guard_artifact_manifest_fingerprint", "unexpected_guard_owned_dirty_paths", "scope_verdict", "protected_path_verdict", "executor_code_review_mismatch", "test_evidence_mismatch", "runtime_raw_git_status_transcript_ref", "runtime_raw_git_diff_name_status_transcript_ref", "runtime_path_scoped_diff_transcript_refs", "diff_summary_refs", "origin_packet_fingerprint", "input_ref_digest", "source_implementation_fingerprint", "observed_implementation_fingerprint", "risk_notes", "triggered_stop_conditions", "unverified_items"];
35
+ export declare const APPLY_VERIFIER_REPORT_REQUIRED_FIELDS: readonly ["role", "completion_proof_kind", "pre_edit_proof_kind", "verification_status_candidate", "task_completion_verdict", "chain_consistency_verdict", "acceptance_coverage_verdict", "invariant_coverage_verdict", "test_coverage_verdict", "cwd", "repo_head", "guard_fingerprint", "expected_freshness_fingerprint", "observed_freshness_fingerprint", "freshness_verdict", "executor_report_ref", "task_code_review_report_ref", "actual_changed_files", "changed_files", "untracked_files", "implementation_dirty_file_list", "implementation_fingerprint", "guard_artifact_manifest_fingerprint", "unexpected_guard_owned_dirty_paths", "scope_verdict", "protected_path_verdict", "executor_code_review_mismatch", "test_evidence_mismatch", "runtime_raw_git_status_transcript_ref", "runtime_raw_git_diff_name_status_transcript_ref", "runtime_path_scoped_diff_transcript_refs", "diff_summary_refs", "origin_packet_fingerprint", "input_ref_digest", "source_implementation_fingerprint", "observed_implementation_fingerprint", "risk_notes", "triggered_stop_conditions", "unverified_items"];
36
36
  export declare function apply_worker_implementation_fingerprint(repoRoot: string, changeRoot: string, expectedGuardRefs?: unknown[], opts?: {
37
37
  declaredTaskWriteScope?: string[];
38
38
  protectedPathRefs?: unknown[];
@@ -47,11 +47,14 @@ export declare function read_pinned_artifact_json(changeRoot: string, refItem: u
47
47
  export declare function materialize_apply_worker_artifact_ref(changeRoot: string, input: ApplyWorkerArtifactMaterializeInput): JsonMap;
48
48
  export declare function pinned_artifact_ref_reasons(changeRoot: string, refItem: unknown, label: string, expected?: ArtifactRefExpected, code?: string): Reason[];
49
49
  export declare function worker_test_run_reasons(changeRoot: string, ev: JsonMap, taskId: string, chainId: string | null, code?: string): Reason[];
50
- export declare function pre_edit_evidence_ref_reasons(evidences: JsonMap[], active: JsonMap | null | undefined, taskId: string, code?: string): Reason[];
50
+ export declare function pre_edit_worker_test_run_reasons(changeRoot: string, ev: JsonMap, taskId: string, code?: string): Reason[];
51
+ export declare function pre_edit_evidence_ref_reasons(changeRoot: string, evidences: JsonMap[], active: JsonMap | null | undefined, taskId: string, code?: string): Reason[];
51
52
  export declare function compute_apply_worker_freshness(repoRoot: string, changeRoot: string, evidences: JsonMap[], taskId: string, chainId: string, refs: {
52
53
  executor_report_ref: unknown;
53
54
  task_code_review_report_ref: unknown;
54
- green_test_run_evidence_ref: string;
55
+ green_test_run_evidence_ref?: string;
55
56
  green_test_run_evidence_refs?: string[];
57
+ alternative_verification_evidence_refs?: string[];
58
+ completion_proof_kind?: "green_tests" | "alternative_verification";
56
59
  verifier_report_ref?: unknown;
57
60
  }): JsonMap;
@@ -1,7 +1,8 @@
1
1
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
2
2
  import { dirname, isAbsolute, relative } from "node:path";
3
- import { deepEqual, fingerprint_obj, GuardError, REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_SUPERSPEC_WORKFLOW_SKILLS, isObject, reason, renderList, runtime, safe_within, sha256_text, } from "./util.js";
3
+ import { deepEqual, fingerprint_obj, GuardError, REQUIRED_SUPERSPEC_AGENT_ROLES, REQUIRED_SUPERSPEC_WORKFLOW_SKILLS, NO_TDD_REASONS, isObject, reason, renderList, runtime, safe_within, sha256_text, } from "./util.js";
4
4
  import { dirty_worktree_paths, file_blob_sha } from "./git.js";
5
+ import { effective_superseded_ids } from "./openspec.js";
5
6
  const APPLY_WORKER_ARTIFACT_KINDS = new Set(["worker_report", "raw_transcript", "diff_transcript", "status_report"]);
6
7
  const APPLY_WORKER_ARTIFACT_ROLES = new Set(["test-runner", "executor", "code-reviewer", "verifier"]);
7
8
  const DEFAULT_APPLY_WORKER_ARTIFACT_MAX_BYTES = 1024 * 1024;
@@ -80,6 +81,8 @@ export const APPLY_CODE_REVIEW_REPORT_REQUIRED_FIELDS = [
80
81
  ];
81
82
  export const APPLY_VERIFIER_REPORT_REQUIRED_FIELDS = [
82
83
  "role",
84
+ "completion_proof_kind",
85
+ "pre_edit_proof_kind",
83
86
  "verification_status_candidate",
84
87
  "task_completion_verdict",
85
88
  "chain_consistency_verdict",
@@ -92,7 +95,6 @@ export const APPLY_VERIFIER_REPORT_REQUIRED_FIELDS = [
92
95
  "expected_freshness_fingerprint",
93
96
  "observed_freshness_fingerprint",
94
97
  "freshness_verdict",
95
- "green_test_run_evidence_refs",
96
98
  "executor_report_ref",
97
99
  "task_code_review_report_ref",
98
100
  "actual_changed_files",
@@ -318,25 +320,34 @@ function evidence_file_ref(changeRoot, ev) {
318
320
  }
319
321
  export function apply_worker_executor_input_ref_digest(evidences, active) {
320
322
  const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean).sort() : [];
323
+ const activeInput = {
324
+ kind: "apply_worker_chain",
325
+ evidence_id: active.evidence_id,
326
+ task_id: active.task_id,
327
+ apply_worker_chain_id: active.apply_worker_chain_id,
328
+ executor_packet_fingerprint: active.executor_packet_fingerprint,
329
+ source_implementation_fingerprint: active.source_implementation_fingerprint,
330
+ declared_task_write_scope: active.declared_task_write_scope,
331
+ pre_edit_evidence_refs: preIds,
332
+ };
333
+ for (const field of ["pre_edit_proof_kind", "apply_execution_surface", "tdd_required", "no_tdd_reason"]) {
334
+ if (active[field] !== undefined)
335
+ activeInput[field] = active[field];
336
+ }
321
337
  return worker_input_ref_digest([
322
- {
323
- kind: "apply_worker_chain",
324
- evidence_id: active.evidence_id,
325
- task_id: active.task_id,
326
- apply_worker_chain_id: active.apply_worker_chain_id,
327
- executor_packet_fingerprint: active.executor_packet_fingerprint,
328
- source_implementation_fingerprint: active.source_implementation_fingerprint,
329
- declared_task_write_scope: active.declared_task_write_scope,
330
- pre_edit_evidence_refs: preIds,
331
- },
338
+ activeInput,
332
339
  ...preIds.map((id) => evidence_summary(evidences.find((ev) => String(ev.evidence_id ?? "") === id))).filter(Boolean),
333
340
  ]);
334
341
  }
335
342
  export function apply_worker_guard_artifact_manifest_fingerprint(items) {
336
343
  const stable = {
344
+ completion_proof_kind: items.completion_proof_kind ?? "green_tests",
345
+ pre_edit_proof_kind: items.pre_edit_proof_kind ?? "red_or_characterization",
337
346
  pre_edit_evidence: Array.isArray(items.pre_edit_evidence) ? items.pre_edit_evidence : [],
338
347
  green_test_run: items.green_test_run ?? null,
339
348
  green_test_runs: Array.isArray(items.green_test_runs) ? items.green_test_runs : [],
349
+ alternative_verification: items.alternative_verification ?? null,
350
+ alternative_verifications: Array.isArray(items.alternative_verifications) ? items.alternative_verifications : [],
340
351
  executor_report_ref: pinned_summary(items.executor_report_ref),
341
352
  task_code_review_report_ref: pinned_summary(items.task_code_review_report_ref),
342
353
  accepted_test_runner_report_ref: pinned_summary(items.accepted_test_runner_report_ref),
@@ -620,7 +631,11 @@ const WORKER_REPORT_FIELD_TYPES = {
620
631
  expected_freshness_fingerprint: "fingerprint",
621
632
  observed_freshness_fingerprint: "fingerprint",
622
633
  freshness_verdict: "string",
634
+ completion_proof_kind: "string",
635
+ pre_edit_proof_kind: "string",
623
636
  green_test_run_evidence_refs: "array",
637
+ alternative_verification_evidence_refs: "array",
638
+ apply_execution_surface: "string",
624
639
  task_code_review_report_ref: "ref",
625
640
  unexpected_guard_owned_dirty_paths: "array",
626
641
  executor_code_review_mismatch: "mismatch",
@@ -789,8 +804,46 @@ function validate_worker_report_content(content, refItem, label, expected, code)
789
804
  }
790
805
  if (expected.role === "verifier") {
791
806
  problems.push(...report_required_field_reasons(content, APPLY_VERIFIER_REPORT_REQUIRED_FIELDS, label, code));
792
- if (!Array.isArray(content.red_test_run_evidence_refs) && !Array.isArray(content.characterization_test_run_evidence_refs)) {
793
- problems.push(reason(code, `${label}: verifier report requires red_test_run_evidence_refs or characterization_test_run_evidence_refs`, [label]));
807
+ const proofKind = String(content.completion_proof_kind ?? "green_tests");
808
+ if (proofKind !== "green_tests" && proofKind !== "alternative_verification") {
809
+ problems.push(reason(code, `${label}: verifier report completion_proof_kind must be green_tests or alternative_verification`, [label]));
810
+ }
811
+ else if (proofKind === "green_tests") {
812
+ if (String(content.pre_edit_proof_kind ?? "red_or_characterization") !== "red_or_characterization") {
813
+ problems.push(reason(code, `${label}: green_tests verifier report requires pre_edit_proof_kind=red_or_characterization`, [label]));
814
+ }
815
+ if (!Array.isArray(content.green_test_run_evidence_refs) || content.green_test_run_evidence_refs.length === 0) {
816
+ problems.push(reason(code, `${label}: green_tests verifier report requires green_test_run_evidence_refs`, [label]));
817
+ }
818
+ if (!Array.isArray(content.red_test_run_evidence_refs) && !Array.isArray(content.characterization_test_run_evidence_refs)) {
819
+ problems.push(reason(code, `${label}: green_tests verifier report requires red_test_run_evidence_refs or characterization_test_run_evidence_refs`, [label]));
820
+ }
821
+ }
822
+ else {
823
+ if (content.pre_edit_proof_kind !== "no_tdd_declared") {
824
+ problems.push(reason(code, `${label}: alternative_verification verifier report requires pre_edit_proof_kind=no_tdd_declared`, [label]));
825
+ }
826
+ if (!Array.isArray(content.alternative_verification_evidence_refs) || content.alternative_verification_evidence_refs.length === 0) {
827
+ problems.push(reason(code, `${label}: alternative_verification verifier report requires alternative_verification_evidence_refs`, [label]));
828
+ }
829
+ if (Array.isArray(content.green_test_run_evidence_refs) && content.green_test_run_evidence_refs.length > 0) {
830
+ problems.push(reason(code, `${label}: alternative_verification verifier report must not claim green_test_run_evidence_refs`, [label]));
831
+ }
832
+ if (Array.isArray(content.red_test_run_evidence_refs) && content.red_test_run_evidence_refs.length > 0) {
833
+ problems.push(reason(code, `${label}: alternative_verification verifier report must not claim red_test_run_evidence_refs`, [label]));
834
+ }
835
+ if (Array.isArray(content.characterization_test_run_evidence_refs) && content.characterization_test_run_evidence_refs.length > 0) {
836
+ problems.push(reason(code, `${label}: alternative_verification verifier report must not claim characterization_test_run_evidence_refs`, [label]));
837
+ }
838
+ if (content.tdd_required !== false) {
839
+ problems.push(reason(code, `${label}: alternative_verification verifier report requires tdd_required=false`, [label]));
840
+ }
841
+ if (content.apply_execution_surface !== "implementation" && content.apply_execution_surface !== "runtime_config") {
842
+ problems.push(reason(code, `${label}: alternative_verification verifier report requires implementation/runtime_config apply_execution_surface`, [label]));
843
+ }
844
+ if (!NO_TDD_REASONS.has(String(content.no_tdd_reason ?? ""))) {
845
+ problems.push(reason(code, `${label}: alternative_verification verifier report requires valid no_tdd_reason`, [label]));
846
+ }
794
847
  }
795
848
  problems.push(...report_pass_verdict_reasons(content, [
796
849
  "verification_status_candidate",
@@ -1055,10 +1108,25 @@ export function worker_test_run_reasons(changeRoot, ev, taskId, chainId, code =
1055
1108
  }
1056
1109
  return problems;
1057
1110
  }
1111
+ export function pre_edit_worker_test_run_reasons(changeRoot, ev, taskId, code = "pre_edit_test_run_invalid") {
1112
+ const problems = [];
1113
+ if (ev.kind !== "test_run")
1114
+ problems.push(reason(code, `${ev._path}: pre-edit evidence must be kind=test_run`));
1115
+ if (ev.gate !== "task_edit")
1116
+ problems.push(reason(code, `${ev._path}: pre-edit evidence must be gate=task_edit`));
1117
+ if (ev.task_id !== taskId)
1118
+ problems.push(reason(code, `${ev._path}: pre-edit evidence task_id must be ${taskId}`));
1119
+ const phase = typeof ev.phase === "string" ? ev.phase : "";
1120
+ const redOk = ev.semantic_status === "expected_failure" && (phase === "" || phase === "red");
1121
+ const characterizationOk = ev.semantic_status === "expected_success" && phase === "characterization";
1122
+ if (!redOk && !characterizationOk) {
1123
+ problems.push(reason(code, `${ev._path}: pre-edit evidence must be worker RED or characterization test_run`));
1124
+ }
1125
+ problems.push(...worker_test_run_reasons(changeRoot, ev, taskId, null, code));
1126
+ return problems;
1127
+ }
1058
1128
  function superseded_ids(evidences) {
1059
- return new Set(evidences
1060
- .filter((ev) => isObject(ev) && ev.status === "superseded" && typeof ev.supersedes === "string" && ev.supersedes)
1061
- .map((ev) => String(ev.supersedes)));
1129
+ return effective_superseded_ids(evidences);
1062
1130
  }
1063
1131
  function live_pass_by_id(evidences, evidenceId) {
1064
1132
  const dead = superseded_ids(evidences);
@@ -1068,11 +1136,28 @@ function live_pass_by_id(evidences, evidenceId) {
1068
1136
  && String(ev.evidence_id ?? "") === evidenceId
1069
1137
  && !dead.has(evidenceId));
1070
1138
  }
1071
- export function pre_edit_evidence_ref_reasons(evidences, active, taskId, code = "pre_edit_evidence_ref_invalid") {
1139
+ export function pre_edit_evidence_ref_reasons(changeRoot, evidences, active, taskId, code = "pre_edit_evidence_ref_invalid") {
1072
1140
  const problems = [];
1073
1141
  if (!isObject(active))
1074
1142
  return [reason(code, `task ${taskId} requires an active apply_worker_chain marker for pre-edit evidence validation`)];
1075
1143
  const preIds = Array.isArray(active.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String).filter(Boolean) : [];
1144
+ const proofKind = String(active.pre_edit_proof_kind ?? "red_or_characterization");
1145
+ if (proofKind !== "red_or_characterization" && proofKind !== "no_tdd_declared") {
1146
+ return [reason(code, `task ${taskId} active apply_worker_chain has invalid pre_edit_proof_kind=${proofKind}`)];
1147
+ }
1148
+ if (proofKind === "no_tdd_declared") {
1149
+ if (preIds.length > 0)
1150
+ problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared must have empty pre_edit_evidence_refs`, preIds));
1151
+ if (active.tdd_required !== false)
1152
+ problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires tdd_required=false`));
1153
+ if (active.apply_execution_surface !== "implementation" && active.apply_execution_surface !== "runtime_config") {
1154
+ problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires implementation/runtime_config apply_execution_surface`));
1155
+ }
1156
+ if (!NO_TDD_REASONS.has(String(active.no_tdd_reason ?? ""))) {
1157
+ problems.push(reason(code, `task ${taskId} active apply_worker_chain no_tdd_declared requires valid no_tdd_reason`));
1158
+ }
1159
+ return problems;
1160
+ }
1076
1161
  if (preIds.length === 0)
1077
1162
  return [reason(code, `task ${taskId} active apply_worker_chain has no pre_edit_evidence_refs`)];
1078
1163
  for (const evidenceId of preIds) {
@@ -1081,18 +1166,8 @@ export function pre_edit_evidence_ref_reasons(evidences, active, taskId, code =
1081
1166
  problems.push(reason(code, `pre_edit_evidence_ref is not live/pass: ${evidenceId}`, [evidenceId]));
1082
1167
  continue;
1083
1168
  }
1084
- if (ev.kind !== "test_run")
1085
- problems.push(reason(code, `${evidenceId}: pre-edit evidence must be kind=test_run`, [evidenceId]));
1086
- if (ev.gate !== "task_edit")
1087
- problems.push(reason(code, `${evidenceId}: pre-edit evidence must be gate=task_edit`, [evidenceId]));
1088
- if (ev.task_id !== taskId)
1089
- problems.push(reason(code, `${evidenceId}: pre-edit evidence task_id must be ${taskId}`, [evidenceId]));
1090
- const phase = typeof ev.phase === "string" ? ev.phase : "";
1091
- const redOk = ev.semantic_status === "expected_failure" && (phase === "" || phase === "red");
1092
- const characterizationOk = ev.semantic_status === "expected_success" && phase === "characterization";
1093
- if (!redOk && !characterizationOk) {
1094
- problems.push(reason(code, `${evidenceId}: pre-edit evidence must be RED or characterization test_run`, [evidenceId]));
1095
- }
1169
+ problems.push(...pre_edit_worker_test_run_reasons(changeRoot, ev, taskId, code)
1170
+ .map((item) => ({ ...item, refs: item.refs.length > 0 ? item.refs : [evidenceId] })));
1096
1171
  }
1097
1172
  return problems;
1098
1173
  }
@@ -1109,6 +1184,13 @@ export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences,
1109
1184
  .filter((ev) => ev.gate === "task_complete" && ev.kind === "test_run" && ev.task_id === taskId)
1110
1185
  .find((ev) => String(ev.evidence_id ?? "") === greenId)).filter((ev) => isObject(ev));
1111
1186
  const green = greens[0];
1187
+ const alternativeIds = [...new Set((Array.isArray(refs.alternative_verification_evidence_refs) ? refs.alternative_verification_evidence_refs : []).map(String).filter(Boolean))].sort();
1188
+ const alternatives = alternativeIds.map((evidenceId) => passEvidences
1189
+ .filter((ev) => (ev.kind === "alternative_verification" || ev.kind === "manual_verification") && ev.task_id === taskId)
1190
+ .find((ev) => String(ev.evidence_id ?? "") === evidenceId)).filter((ev) => isObject(ev));
1191
+ const alternative = alternatives[0];
1192
+ const completionProofKind = refs.completion_proof_kind ?? (alternativeIds.length > 0 ? "alternative_verification" : "green_tests");
1193
+ const preEditProofKind = String(active?.pre_edit_proof_kind ?? "red_or_characterization");
1112
1194
  const preIds = Array.isArray(active?.pre_edit_evidence_refs) ? active.pre_edit_evidence_refs.map(String) : [];
1113
1195
  const preEditEvidence = preIds.map((id) => evidences.find((ev) => String(ev.evidence_id ?? "") === id)).filter((ev) => isObject(ev));
1114
1196
  const preEdit = preEditEvidence.map(evidence_summary).filter(Boolean);
@@ -1118,6 +1200,7 @@ export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences,
1118
1200
  evidence_file_ref(changeRoot, active),
1119
1201
  ...preEditEvidence.map((ev) => evidence_file_ref(changeRoot, ev)),
1120
1202
  ...greens.map((ev) => evidence_file_ref(changeRoot, ev)),
1203
+ ...alternatives.map((ev) => evidence_file_ref(changeRoot, ev)),
1121
1204
  ].filter((item) => isObject(item));
1122
1205
  const expectedGuardRefs = [
1123
1206
  refs.executor_report_ref,
@@ -1131,9 +1214,13 @@ export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences,
1131
1214
  const implementation = apply_worker_implementation_fingerprint(repoRoot, changeRoot, expectedGuardRefs, { declaredTaskWriteScope: activeScope });
1132
1215
  const greenImplementationDigest = fingerprint_digest(green?.implementation_fingerprint);
1133
1216
  const guardArtifact = apply_worker_guard_artifact_manifest_fingerprint({
1217
+ completion_proof_kind: completionProofKind,
1218
+ pre_edit_proof_kind: preEditProofKind,
1134
1219
  pre_edit_evidence: preEdit,
1135
1220
  green_test_run: evidence_summary(green),
1136
1221
  green_test_runs: greens.map(evidence_summary).filter(Boolean),
1222
+ alternative_verification: evidence_summary(alternative),
1223
+ alternative_verifications: alternatives.map(evidence_summary).filter(Boolean),
1137
1224
  executor_report_ref: refs.executor_report_ref,
1138
1225
  task_code_review_report_ref: refs.task_code_review_report_ref,
1139
1226
  accepted_test_runner_report_ref: green?.accepted_test_runner_report_ref,
@@ -1148,11 +1235,17 @@ export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences,
1148
1235
  source_implementation_fingerprint: active.source_implementation_fingerprint,
1149
1236
  declared_task_write_scope: active.declared_task_write_scope,
1150
1237
  pre_edit_evidence_refs: active.pre_edit_evidence_refs,
1238
+ pre_edit_proof_kind: active.pre_edit_proof_kind,
1239
+ apply_execution_surface: active.apply_execution_surface,
1240
+ tdd_required: active.tdd_required,
1241
+ no_tdd_reason: active.no_tdd_reason,
1151
1242
  } : null,
1152
1243
  });
1153
1244
  const stable = {
1154
1245
  task_id: taskId,
1155
1246
  apply_worker_chain_id: chainId,
1247
+ completion_proof_kind: completionProofKind,
1248
+ pre_edit_proof_kind: preEditProofKind,
1156
1249
  repo_head: repo_head(repoRoot),
1157
1250
  implementation_fingerprint: {
1158
1251
  repo_head: implementation.repo_head,
@@ -1171,6 +1264,8 @@ export function compute_apply_worker_freshness(repoRoot, changeRoot, evidences,
1171
1264
  pre_edit_evidence_refs: preIds,
1172
1265
  green_test_run_evidence_ref: refs.green_test_run_evidence_ref,
1173
1266
  green_test_run_evidence_refs: greenIds,
1267
+ alternative_verification_evidence_ref: alternativeIds[0] ?? null,
1268
+ alternative_verification_evidence_refs: alternativeIds,
1174
1269
  executor_report_ref: pinned_summary(refs.executor_report_ref),
1175
1270
  task_code_review_report_ref: pinned_summary(refs.task_code_review_report_ref),
1176
1271
  };
@@ -1,4 +1,8 @@
1
1
  import type { JsonMap, Reason } from "./util.ts";
2
+ export type TakeoverBaseline = {
3
+ fingerprint: unknown;
4
+ successorGreenRefs: string[];
5
+ };
2
6
  export type ApplyWorkerChainLifecycleState = {
3
7
  completionReasons: Reason[];
4
8
  packetBlockers: Reason[];
@@ -9,11 +13,9 @@ export type ApplyWorkerChainLifecycleState = {
9
13
  validTerminalChainIds: Set<string>;
10
14
  validClosedChainIds: Set<string>;
11
15
  validClosedGreenEvidenceIds: Set<string>;
12
- takeoverBaselines: {
13
- fingerprint: unknown;
14
- successorGreenRefs: string[];
15
- }[];
16
+ validClosedAlternativeEvidenceIds: Set<string>;
17
+ validClosedAlternativeChainIds: Set<string>;
18
+ takeoverbaselines: TakeoverBaseline[];
16
19
  };
17
- export declare function serial_completion_green(ev: JsonMap): boolean;
18
20
  export declare function apply_worker_chain_lifecycle_state(repoRoot: string, changeRoot: string, evidences: JsonMap[], taskId: string): ApplyWorkerChainLifecycleState;
19
21
  export declare function apply_worker_chain_lifecycle_reasons(repoRoot: string, changeRoot: string, evidences: JsonMap[], taskId: string): Reason[];