gentle-pi 2.1.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +70 -12
  2. package/assets/agents/gentle-ai-worker.md +7 -3
  3. package/assets/agents/jd-fix-agent.md +1 -1
  4. package/assets/agents/jd-judge-a.md +3 -1
  5. package/assets/agents/jd-judge-b.md +3 -1
  6. package/assets/agents/review-readability.md +4 -1
  7. package/assets/agents/review-reliability.md +4 -1
  8. package/assets/agents/review-resilience.md +4 -1
  9. package/assets/agents/review-risk.md +4 -1
  10. package/assets/agents/sdd-apply.md +6 -1
  11. package/assets/agents/sdd-archive.md +6 -1
  12. package/assets/agents/sdd-design.md +6 -1
  13. package/assets/agents/sdd-explore.md +6 -2
  14. package/assets/agents/sdd-init.md +10 -2
  15. package/assets/agents/sdd-onboard.md +6 -1
  16. package/assets/agents/sdd-proposal.md +6 -1
  17. package/assets/agents/sdd-spec.md +6 -1
  18. package/assets/agents/sdd-status.md +6 -1
  19. package/assets/agents/sdd-sync.md +6 -1
  20. package/assets/agents/sdd-tasks.md +6 -1
  21. package/assets/agents/sdd-verify.md +6 -1
  22. package/assets/chains/4r-review.chain.md +2 -0
  23. package/assets/chains/sdd-full.chain.md +1 -1
  24. package/assets/chains/sdd-plan.chain.md +1 -1
  25. package/assets/chains/sdd-verify.chain.md +1 -1
  26. package/assets/orchestrator-delegation.md +246 -67
  27. package/assets/orchestrator.md +7 -14
  28. package/assets/sdd-orchestrator-workflow.md +154 -9
  29. package/assets/support/sdd-status-contract.md +19 -1
  30. package/contracts/review-integration/v1/fixtures/consent.fixture.json +3 -3
  31. package/contracts/review-integration/v1/fixtures/start-v2.fixture.json +19 -28
  32. package/contracts/review-integration/v1/fixtures/start.fixture.json +1 -10
  33. package/contracts/review-integration/v1/fixtures/status-v2.fixture.json +12 -21
  34. package/contracts/review-integration/v1/schemas/correction-plan-request.schema.json +49 -0
  35. package/contracts/review-integration/v1/schemas/operation.schema.json +76 -0
  36. package/contracts/review-integration/v1/schemas/repair.schema.json +39 -0
  37. package/contracts/review-integration/v1/schemas/status-v2.schema.json +4 -2
  38. package/contracts/review-integration/v1/schemas/status.schema.json +4 -2
  39. package/contracts/review-integration/v2/fixtures/consent.fixture.json +1 -1
  40. package/contracts/review-integration/v2/fixtures/start.fixture.json +1 -10
  41. package/contracts/review-integration/v2/fixtures/status.fixture.json +1 -10
  42. package/contracts/review-integration/v2/schemas/failure.schema.json +5 -1
  43. package/contracts/review-integration/v2/schemas/operation.schema.json +6 -1
  44. package/contracts/review-integration/v2/schemas/repair.schema.json +4 -2
  45. package/contracts/review-integration/v2/schemas/start.schema.json +5 -2
  46. package/contracts/review-integration/v2/schemas/status.schema.json +4 -2
  47. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +30 -0
  48. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/README.md +12 -0
  49. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/manifest.json +65 -0
  50. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/lens.schema.json +16 -0
  51. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/refuter.schema.json +1 -0
  52. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/targeted-validator.schema.json +1 -0
  53. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/lens.json +1 -0
  54. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/refuter.json +1 -0
  55. package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/targeted-validator.json +1 -0
  56. package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-capabilities.baseline.json +15 -0
  57. package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-roles.baseline.json +42 -0
  58. package/docs/native-authority-architecture.md +5 -5
  59. package/docs/review-integration.md +22 -2
  60. package/extensions/gentle-ai.ts +1595 -201
  61. package/extensions/sdd-init.ts +19 -6
  62. package/extensions/skill-registry.ts +10 -2
  63. package/extensions/startup-banner.ts +10 -4
  64. package/lib/gentle-ai-binary.ts +173 -2
  65. package/lib/git-commit-transaction.ts +77 -17
  66. package/lib/native-review-cli.ts +528 -65
  67. package/lib/provider-contract-bundle.ts +704 -0
  68. package/lib/review-candidate-view.ts +527 -18
  69. package/lib/review-compact-contract.ts +59 -248
  70. package/lib/review-host-relay.ts +436 -0
  71. package/lib/review-integration-v2.ts +537 -36
  72. package/lib/review-relay-contract.ts +16 -0
  73. package/lib/sdd-preflight.ts +53 -1
  74. package/package.json +5 -2
  75. package/runtime/gentle-ai-binary.mjs +173 -2
  76. package/runtime/git-commit-transaction.mjs +75 -15
  77. package/runtime/native-review-cli.mjs +524 -61
  78. package/runtime/review-integration-v2.mjs +536 -35
  79. package/runtime/review-relay-contract.mjs +17 -0
  80. package/scripts/build-git-commit-transaction-runner.mjs +1 -0
  81. package/scripts/check-provider-contract.mjs +138 -0
  82. package/scripts/gentle-ai-installer.mjs +23 -13
  83. package/scripts/maintainer/provider-relay-matrix.mjs +219 -0
  84. package/scripts/mirror-provider-contract.mjs +143 -0
  85. package/scripts/test-packed-runner.mjs +16 -2
  86. package/scripts/verify-package-files.mjs +110 -33
  87. package/skills/_shared/review-ledger-contract.md +4 -6
  88. package/skills/gentle-ai/SKILL.md +4 -4
  89. package/skills/issue-creation/SKILL.md +94 -168
  90. package/skills/judgment-day/SKILL.md +7 -1
  91. package/skills/judgment-day/references/prompts-and-formats.md +2 -0
  92. package/skills/rdd-defect-workflow/SKILL.md +54 -0
  93. package/tests/background-subagents.test.ts +771 -0
  94. package/tests/crosslane/cross-lane.mjs +1169 -0
  95. package/tests/delegated-key-learnings-contract.test.ts +238 -0
  96. package/tests/fixtures/devbinary/capabilities-v2.1.derived.json +331 -0
  97. package/tests/fixtures/devbinary/capabilities-v2.2.captured.json +340 -0
  98. package/tests/fixtures/devbinary/consent-v3.captured.json +37 -0
  99. package/tests/fixtures/devbinary/failure-v2-capture-evidence.captured.json +16 -0
  100. package/tests/fixtures/devbinary/result-artifact-v2-path.captured.json +12 -0
  101. package/tests/fixtures/devbinary/result-artifact-v2.captured.json +12 -0
  102. package/tests/fixtures/devbinary/start-v3-consent-declined.captured.json +19 -0
  103. package/tests/fixtures/devbinary/start-v3-consent-granted.captured.json +109 -0
  104. package/tests/fixtures/devbinary/status-v5-capture-result-submission.captured.json +184 -0
  105. package/tests/fixtures/devbinary/status-v5-repository-context.captured.json +138 -0
  106. package/tests/fixtures/devbinary/status-v5.captured.json +88 -0
  107. package/tests/fixtures/provider-contract-bundle/v1.1.0/README.md +12 -0
  108. package/tests/fixtures/provider-contract-bundle/v1.1.0/manifest.json +65 -0
  109. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/lens.schema.json +16 -0
  110. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/refuter.schema.json +1 -0
  111. package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/targeted-validator.schema.json +1 -0
  112. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/lens.json +1 -0
  113. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/refuter.json +1 -0
  114. package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/targeted-validator.json +1 -0
  115. package/tests/gentle-ai-binary.test.ts +1 -1
  116. package/tests/gentle-ai-dev-binary-surfacing.test.ts +195 -0
  117. package/tests/gentle-ai-dev-binary.test.ts +336 -0
  118. package/tests/gentle-ai-installer.test.ts +46 -46
  119. package/tests/git-commit-transaction.test.ts +229 -1
  120. package/tests/maintainer/provider-relay.maintest.ts +265 -0
  121. package/tests/native-review-capability-contract.test.ts +48 -2
  122. package/tests/native-review-cli.test.ts +56 -0
  123. package/tests/native-review-consent.test.ts +164 -3
  124. package/tests/native-review-parity-runtime.test.ts +37 -0
  125. package/tests/native-review-parity.test.ts +218 -15
  126. package/tests/native-sdd-attempt-authority.test.ts +235 -0
  127. package/tests/orchestrator-budget.test.ts +30 -5
  128. package/tests/package-manifest.test.ts +98 -72
  129. package/tests/provider-contract-bundle.test.ts +385 -0
  130. package/tests/provider-contract-mirror.test.ts +206 -0
  131. package/tests/provider-defect-handoff.test.ts +355 -0
  132. package/tests/review-actor-tool-deny.test.ts +12 -13
  133. package/tests/review-candidate-view.test.ts +489 -9
  134. package/tests/review-compact-contract.test.ts +52 -119
  135. package/tests/review-controller-native-recovery.test.ts +643 -47
  136. package/tests/review-controller-native-routing.test.ts +1667 -222
  137. package/tests/review-controller-workspace-root.test.ts +17 -2
  138. package/tests/review-corrected-finalize-binding.test.ts +175 -0
  139. package/tests/review-dispatch-hydration-gap.test.ts +197 -0
  140. package/tests/review-host-relay-routing.test.ts +317 -0
  141. package/tests/review-host-relay.test.ts +520 -0
  142. package/tests/review-integration-v2-forward.test.ts +631 -0
  143. package/tests/review-integration-v2.test.ts +114 -0
  144. package/tests/review-ledger-contract.test.ts +12 -28
  145. package/tests/review-recovered-lineage-routing.test.ts +246 -0
  146. package/tests/review-relay-transport-agent.test.ts +249 -0
  147. package/tests/runtime-harness.mjs +242 -14
  148. package/tests/sdd-agent-tools.test.ts +18 -33
  149. package/tests/skill-collision-prefixes.test.ts +1 -0
  150. package/tests/skill-registry.test.ts +50 -1
  151. package/tests/verify-package-files.test.ts +62 -0
  152. package/assets/agents/review-refuter.md +0 -40
  153. package/assets/agents/review-validator.md +0 -23
  154. package/lib/native-review-remediation.ts +0 -49
  155. package/lib/review-compact.ts +0 -947
  156. package/lib/review-refuter-adapter.ts +0 -129
  157. package/lib/review-runtime-contract.ts +0 -68
  158. package/prompts/gcl.md +0 -54
  159. package/prompts/gis.md +0 -25
  160. package/prompts/gpr.md +0 -41
  161. package/prompts/gwr.md +0 -31
  162. package/tests/fixtures/native-review-cli/v2.1.2/bind-sdd.json +0 -25
  163. package/tests/fixtures/native-review-cli/v2.1.2/finalize.json +0 -8
  164. package/tests/fixtures/native-review-cli/v2.1.2/sdd-status-engram.json +0 -139
  165. package/tests/fixtures/native-review-cli/v2.1.2/sdd-status.json +0 -200
  166. package/tests/fixtures/native-review-cli/v2.1.2/start.json +0 -12
  167. package/tests/fixtures/native-review-cli/v2.1.2/validate-allow.json +0 -24
  168. package/tests/fixtures/native-review-cli/v2.1.2/validate-deny-empty-context.json +0 -20
  169. package/tests/fixtures/native-review-cli/v2.1.2/validate-deny.json +0 -28
  170. package/tests/review-compact.test.ts +0 -243
  171. package/tests/review-refuter-adapter.test.ts +0 -89
@@ -2,123 +2,45 @@ import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
  import {
4
4
  CompactReviewContractError,
5
- deriveNativeValidationRequest,
6
5
  parseNativeCompactFinalizeInput,
7
- parseCompactStartInput,
6
+ toNativeValidatorDocument,
8
7
  } from "../lib/review-compact-contract.ts";
9
8
 
10
- const POLICY_HASH = "a".repeat(64);
9
+ const REQUEST_HASH = "a".repeat(64);
11
10
 
12
- function correctionRequiredState(overrides: Record<string, unknown> = {}): Record<string, unknown> {
13
- return {
14
- lineage_id: "correction-lineage",
15
- state: "correction_required",
16
- initial_snapshot: { candidate_tree: "c".repeat(40) },
17
- fix_finding_ids: ["R4-001", "R4-002"],
18
- findings: [
19
- { id: "R4-001", severity: "CRITICAL" },
20
- { id: "R4-002", severity: "BLOCKER" },
21
- { id: "RISK-XSS-001", severity: "CRITICAL" },
22
- ],
23
- outcomes: { "R4-001": "corroborated", "R4-002": "corroborated", "RISK-XSS-001": "info" },
24
- ...overrides,
25
- };
26
- }
27
-
28
- test("validation request derivation keeps severe pre-existing follow-ups inert (#171)", () => {
29
- const request = deriveNativeValidationRequest({
30
- lineageId: "correction-lineage",
31
- candidateTree: "d".repeat(40),
32
- state: correctionRequiredState(),
33
- });
34
- assert.deepEqual(request.blocking_finding_ids, ["R4-001", "R4-002"]);
35
- assert.deepEqual(request.fix_finding_ids, ["R4-001", "R4-002"]);
36
- });
37
-
38
- test("validation request derivation still blocks corroborated severe findings absent from the fix set", () => {
39
- assert.throws(
40
- () => deriveNativeValidationRequest({
41
- lineageId: "correction-lineage",
42
- candidateTree: "d".repeat(40),
43
- state: correctionRequiredState({
44
- fix_finding_ids: ["R4-001"],
45
- outcomes: { "R4-001": "corroborated", "R4-002": "corroborated", "RISK-XSS-001": "info" },
46
- }),
47
- }),
48
- (error: unknown) => error instanceof CompactReviewContractError && error.code === "finding-ids",
49
- );
50
- });
51
-
52
- test("validation request derivation without native outcomes keeps the severity-derived blocking set", () => {
53
- const request = deriveNativeValidationRequest({
54
- lineageId: "correction-lineage",
55
- candidateTree: "d".repeat(40),
56
- state: correctionRequiredState({
57
- fix_finding_ids: ["R4-001", "R4-002", "RISK-XSS-001"],
58
- outcomes: undefined,
59
- }),
60
- });
61
- assert.deepEqual(request.blocking_finding_ids, ["R4-001", "R4-002", "RISK-XSS-001"]);
62
- });
63
-
64
- test("compact start parser returns canonical input and rejects widened nested projection", () => {
65
- assert.deepEqual(parseCompactStartInput({
66
- cwd: "/repo",
67
- lineageId: "review-1",
68
- policyHash: POLICY_HASH,
69
- projection: { kind: "complete" },
70
- }), {
71
- cwd: "/repo",
72
- lineageId: "review-1",
73
- policyHash: POLICY_HASH,
74
- projection: { kind: "complete" },
75
- });
76
- assert.throws(
77
- () => parseCompactStartInput({ cwd: "/repo", policyHash: POLICY_HASH, projection: { kind: "complete", extra: true } }),
78
- (error: unknown) => error instanceof CompactReviewContractError && error.area === "review/start.projection" && error.code === "unknown-key",
79
- );
11
+ // gentle-pi#311 P5: the FINALIZE input contract carries only the negotiated
12
+ // collection answers. Pi-authored reviewer, refuter, and validator-proof
13
+ // payloads are retired — lens results are admitted natively, and the
14
+ // adversarial roles execute through Go-owned pi processes via
15
+ // provider-rendered self-contained vectors.
16
+ test("compact finalize parser rejects the retired Pi-authored payload fields", () => {
17
+ for (const retired of [
18
+ { review_result: { lens_results: [] } },
19
+ { refuter_batch: { schema: "gentle-ai.refuter-result-batch/v1", request_hash: REQUEST_HASH, results: [] } },
20
+ { validation_proof: { original_criteria: { passed: true, evidence: ["ok"] }, correction_regression: { passed: true, evidence: ["ok"] } } },
21
+ ]) {
22
+ assert.throws(
23
+ () => parseNativeCompactFinalizeInput({ cwd: "/repo", ...retired }),
24
+ (error: unknown) => error instanceof CompactReviewContractError && error.code === "unknown-key",
25
+ );
26
+ }
80
27
  });
81
28
 
82
- test("compact finalize parser rejects malformed nested findings and incomplete final evidence pairing", () => {
83
- const valid = {
84
- cwd: "/repo",
85
- review_result: {
86
- lens_results: [{
87
- lens: "review-risk",
88
- findings: [{
89
- id: "RISK-001",
90
- lens: "review-risk",
91
- location: "lib/a.ts:1",
92
- severity: "CRITICAL",
93
- claim: "Concrete claim",
94
- evidence_class: "deterministic",
95
- causal_disposition: "introduced",
96
- proof_refs: ["changed-hunk:lib/a.ts:1"],
97
- }],
98
- evidence: ["reviewed"],
99
- }],
100
- },
101
- };
102
- assert.equal(parseNativeCompactFinalizeInput(valid).review_result?.lens_results[0]?.findings[0]?.id, "RISK-001");
29
+ test("compact finalize parser enforces the final evidence pairing and forecast range", () => {
103
30
  assert.throws(
104
- () => parseNativeCompactFinalizeInput({ ...valid, review_result: { lens_results: [{ ...valid.review_result.lens_results[0], findings: [{ ...valid.review_result.lens_results[0].findings[0], extra: true }] }] } }),
105
- (error: unknown) => error instanceof CompactReviewContractError && error.area === "review/finalize.review_result.lens_results[0].findings[0]" && error.code === "unknown-key",
31
+ () => parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: "passed" }),
32
+ (error: unknown) => error instanceof CompactReviewContractError && error.code === "field-pair",
106
33
  );
107
34
  assert.throws(
108
- () => parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: "passed" }),
35
+ () => parseNativeCompactFinalizeInput({ cwd: "/repo", final_verification_passed: true }),
109
36
  (error: unknown) => error instanceof CompactReviewContractError && error.code === "field-pair",
110
37
  );
111
- for (const review_result of [
112
- { lens_results: [{ findings: [], evidence: [] }] },
113
- { lens_results: [{ findings: [{ ...valid.review_result.lens_results[0].findings[0], proof_refs: [] }], evidence: ["reviewed"] }] },
114
- { lens_results: [{ findings: [{ ...valid.review_result.lens_results[0].findings[0], severity: "UNKNOWN" }], evidence: ["reviewed"] }] },
115
- { lens_results: [{ findings: [{ ...valid.review_result.lens_results[0].findings[0], evidence_class: "info" }], evidence: ["reviewed"] }] },
116
- ]) assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", review_result }), CompactReviewContractError);
117
- assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", validation_proof: { original_criteria: { passed: true, evidence: [] }, correction_regression: { passed: true, evidence: ["passed"] } } }), CompactReviewContractError);
118
- assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", refuter_batch: { schema: "gentle-ai.refuter-result-batch/v1", request_hash: POLICY_HASH, results: [{ finding_id: "RISK-001", outcome: "unknown", proof_refs: ["proof"] }] } }), CompactReviewContractError);
38
+ assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", correction_line_forecast: 0 }), CompactReviewContractError);
39
+ assert.equal(parseNativeCompactFinalizeInput({ cwd: "/repo", correction_line_forecast: 3 }).correction_line_forecast, 3);
40
+ assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", lineageId: "bad lineage!" }), CompactReviewContractError);
119
41
  });
120
42
 
121
- test("native finalize preserves arbitrary non-empty evidence text and binds refuter batches", () => {
43
+ test("native finalize preserves arbitrary non-empty evidence text byte-for-byte", () => {
122
44
  const evidence = " \tleading evidence\nterminal newlines\n\n";
123
45
  assert.equal(parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: evidence, final_verification_passed: true }).final_evidence, evidence);
124
46
  for (const outcome of ["passed", "verification_failed", "procedural_tooling_failed"] as const) {
@@ -127,22 +49,33 @@ test("native finalize preserves arbitrary non-empty evidence text and binds refu
127
49
  assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: evidence, final_verification_outcome: "failed" }), CompactReviewContractError);
128
50
  assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: evidence, final_verification_passed: true, final_verification_outcome: "passed" }), CompactReviewContractError);
129
51
  assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", final_evidence: "", final_verification_passed: true }), CompactReviewContractError);
52
+ });
130
53
 
131
- const proof = "differential-test:candidate still fails";
132
- const review_result = {
133
- lens_results: [{
134
- lens: "review-risk",
135
- findings: [{ id: "RISK-001", lens: "review-risk", location: "lib/a.ts:1", severity: "CRITICAL", claim: "Candidate fails", evidence_class: "inferential", causal_disposition: "introduced", proof_refs: [proof] }],
136
- evidence: ["reviewed"],
137
- }],
138
- refuter_request_hash: POLICY_HASH,
54
+ test("targeted validation document keeps its strict provider-bound shape", () => {
55
+ const validation = {
56
+ request_hash: REQUEST_HASH,
57
+ correction_ids: ["RISK-001"],
58
+ original_criteria: { passed: true, evidence: ["acceptance passes"] },
59
+ correction_regression: { passed: true, evidence: ["regression suite passes"] },
60
+ fix_caused_findings: [],
61
+ follow_ups: [{ finding_id: "RISK-001", location: "lib/a.ts:1", summary: "Track the remaining cleanup", proof_refs: ["differential-test:covered"] }],
139
62
  };
140
- const batch = { schema: "gentle-ai.refuter-result-batch/v1", request_hash: POLICY_HASH, results: [{ finding_id: "RISK-001", outcome: "corroborated", proof_refs: [proof] }] };
141
- assert.deepEqual(parseNativeCompactFinalizeInput({ cwd: "/repo", review_result, refuter_batch: batch }).refuter_batch, batch);
142
- assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", review_result, refuter_batch: { ...batch, request_hash: "b".repeat(64) } }), CompactReviewContractError);
143
- const independent = { ...batch, results: [{ ...batch.results[0], proof_refs: ["differential-test:independent reproduction fails"] }] };
144
- assert.deepEqual(parseNativeCompactFinalizeInput({ cwd: "/repo", review_result, refuter_batch: independent }).refuter_batch, independent);
145
- for (const proof_refs of [[], [""], [" malformed"]]) {
146
- assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", review_result, refuter_batch: { ...batch, results: [{ ...batch.results[0], proof_refs }] } }), CompactReviewContractError);
63
+ const parsed = parseNativeCompactFinalizeInput({ cwd: "/repo", validation, final_evidence: "full suite passed", final_verification_passed: true });
64
+ assert.deepEqual(parsed.validation, validation);
65
+ assert.deepEqual(toNativeValidatorDocument(parsed.validation!), {
66
+ original_criteria: validation.original_criteria,
67
+ correction_regression: validation.correction_regression,
68
+ follow_ups: [{ observation: "Track the remaining cleanup", proof_refs: ["differential-test:covered"] }],
69
+ });
70
+
71
+ for (const invalid of [
72
+ { ...validation, request_hash: "not-a-digest" },
73
+ { ...validation, fix_caused_findings: [{ id: "FIX-001" }] },
74
+ { ...validation, original_criteria: { passed: true, evidence: [] } },
75
+ { ...validation, correction_regression: { passed: "yes", evidence: ["ok"] } },
76
+ { ...validation, follow_ups: [{ ...validation.follow_ups[0], proof_refs: [] }] },
77
+ { ...validation, extra_field: true },
78
+ ]) {
79
+ assert.throws(() => parseNativeCompactFinalizeInput({ cwd: "/repo", validation: invalid, final_evidence: "evidence", final_verification_passed: true }), CompactReviewContractError);
147
80
  }
148
81
  });