@peterxiaoyang/superspec 0.1.10 → 0.1.12
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.
- package/README.md +8 -10
- package/dist/src/apply_worker_chain.d.ts +6 -3
- package/dist/src/apply_worker_chain.js +125 -30
- package/dist/src/apply_worker_chain_lifecycle.d.ts +7 -5
- package/dist/src/apply_worker_chain_lifecycle.js +153 -22
- package/dist/src/cli_args.d.ts +1 -0
- package/dist/src/cli_args.js +33 -15
- package/dist/src/disclosure.js +2 -2
- package/dist/src/evidence.js +104 -8
- package/dist/src/gates.d.ts +1 -0
- package/dist/src/gates.js +160 -27
- package/dist/src/hooks/adapter.js +43 -7
- package/dist/src/hooks/guard_api.js +2 -2
- package/dist/src/hooks/health.js +0 -12
- package/dist/src/hooks/policy_event.js +11 -1
- package/dist/src/i18n.js +63 -3
- package/dist/src/init_cli.js +1 -1
- package/dist/src/install_engine.js +64 -0
- package/dist/src/openspec.d.ts +2 -0
- package/dist/src/openspec.js +31 -0
- package/dist/src/packet_render.d.ts +1 -0
- package/dist/src/packet_render.js +248 -31
- package/dist/src/packet_schema.d.ts +2 -0
- package/dist/src/tasks.d.ts +5 -0
- package/dist/src/tasks.js +62 -0
- package/dist/src/util.d.ts +4 -0
- package/dist/src/util.js +13 -0
- package/dist/superspec.js +4 -4
- package/package.json +3 -3
- package/templates/hooks/codex-hooks.json +0 -26
- package/templates/sidecar/discovery.md +9 -0
- package/templates/sidecar/test-contract.md +2 -1
- package/templates/workflow/prompts/code-reviewer.md +1 -1
- package/templates/workflow/prompts/executor.md +1 -1
- package/templates/workflow/prompts/test-engineer.md +1 -0
- package/templates/workflow/prompts/test-runner.md +3 -1
- package/templates/workflow/prompts/verifier.md +9 -9
- package/templates/workflow/skills/superspec-apply/SKILL.md +58 -40
- package/templates/workflow/skills/superspec-archive/SKILL.md +5 -13
- package/templates/workflow/skills/superspec-explore/SKILL.md +17 -18
- package/templates/workflow/skills/superspec-propose/SKILL.md +26 -22
- package/templates/workflow/skills/superspec-review/SKILL.md +17 -24
- package/dist/src/packet_measure.d.ts +0 -43
- package/dist/src/packet_measure.js +0 -382
- /package/bin/{superspec-guard.js → superspec-check.js} +0 -0
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ superspec init --scope project
|
|
|
82
82
|
|
|
83
83
|
这条命令的意思是:把 SuperSpec 当前可用的工作流入口安装到项目里。
|
|
84
84
|
|
|
85
|
-
初始化还会安装托管的 `.codex/hooks.json
|
|
85
|
+
初始化还会安装托管的 `.codex/hooks.json`。默认 manifest 只在子智能体启动和停止时调用 SuperSpec,记录 best-effort 审计信息;它不会拦截普通文件写入,也不会在测试命令后自动记录结果。
|
|
86
86
|
|
|
87
87
|
Windows PowerShell 如果拦截 npm 的 `.ps1` 脚本,请改用:
|
|
88
88
|
|
|
@@ -161,15 +161,13 @@ openspec/changes/<变更ID>/.superspec/
|
|
|
161
161
|
|
|
162
162
|
## Hook 会做什么
|
|
163
163
|
|
|
164
|
-
SuperSpec
|
|
164
|
+
SuperSpec 默认安装的 hook 只在子智能体启动和停止时运行:
|
|
165
165
|
|
|
166
|
-
- 写文件前:检查是否会改到 SuperSpec 的过程记录、提前归档、绕过任务检查,或写到当前任务不该写的地方
|
|
167
|
-
- 工具执行后:如果刚跑的是测试或验证命令,就记录这次结果
|
|
168
166
|
- 子智能体启动和停止时:记录这次子智能体运行的基本信息
|
|
169
167
|
|
|
170
168
|
这些 hook 的默认超时时间是 `120` 秒。这个时间限制的是 hook 自己的检查过程,不限制 `npm test`、构建命令或子智能体本身能运行多久。
|
|
171
169
|
|
|
172
|
-
hook
|
|
170
|
+
hook 不是安全沙箱。默认 hook 只留下子智能体审计线索;它不会机械阻止写入,也不能把记录变成不可伪造的安全证明。
|
|
173
171
|
|
|
174
172
|
## 重要边界
|
|
175
173
|
|
|
@@ -189,7 +187,7 @@ SuperSpec 能让流程更规范,但它不是安全锁。
|
|
|
189
187
|
- 阻止恶意伪造记录
|
|
190
188
|
- 替代正式的安全审计、合规审计或法律证明
|
|
191
189
|
|
|
192
|
-
也就是说,SuperSpec 目前是“流程纪律 +
|
|
190
|
+
也就是说,SuperSpec 目前是“流程纪律 + 审计辅助工具”,不是“强制安全系统”。默认 hook 只增强子智能体活动的可见性;显式/manual `PreToolUse` 才会进入保守写入策略,但仍然不能替代正式的安全控制。
|
|
193
191
|
|
|
194
192
|
## 常用命令
|
|
195
193
|
|
|
@@ -248,10 +246,10 @@ superspec doctor
|
|
|
248
246
|
SuperSpec 内部还有一些检查命令,例如:
|
|
249
247
|
|
|
250
248
|
```bash
|
|
251
|
-
superspec
|
|
252
|
-
superspec
|
|
253
|
-
superspec
|
|
254
|
-
superspec
|
|
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>
|
|
255
253
|
```
|
|
256
254
|
|
|
257
255
|
普通使用者通常不需要手动运行这些命令;对应的阶段入口会在需要时使用它们。
|
|
@@ -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", "
|
|
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
|
|
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
|
|
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
|
-
|
|
793
|
-
|
|
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
|
|
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
|
-
|
|
1085
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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[];
|