@ccoalm/ccl-skills 0.7.0 → 0.9.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 (127) hide show
  1. package/README.md +2 -2
  2. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/SKILL.md +8 -7
  3. package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-quality-release.md +6 -1
  4. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +16 -17
  5. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +1 -1
  6. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +6 -0
  7. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +195 -7
  8. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/timeout-auth-and-capabilities.md +3 -3
  9. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +13 -5
  10. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +9 -3
  11. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +9 -3
  12. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/normalize_review_timeout.sh +22 -0
  13. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/opencode_review.sh +9 -3
  14. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +1540 -129
  15. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +8 -3
  16. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +76 -1
  17. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +1858 -3
  18. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_update_review_plan_intent.sh +789 -0
  19. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/update_review_plan_intent.py +513 -0
  20. package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +1 -0
  21. package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/SKILL.md +3 -1
  22. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/architecture-playbook.md +1 -1
  23. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/multi-tenant-isolation.md +1 -1
  24. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +4 -1
  25. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/state-machine-task-patterns.md +2 -0
  26. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +2 -1
  27. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/inference-capacity-operations.md +24 -0
  28. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/llm-client-gateway.md +1 -1
  29. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/model-prompt-evaluation.md +4 -1
  30. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +11 -10
  31. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/contracts-and-state.md +5 -0
  32. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/SKILL.md +64 -0
  33. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/agents/openai.yaml +4 -0
  34. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/async-lifecycle-and-performance.md +73 -0
  35. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/runtime-and-project-contract.md +58 -0
  36. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/source-map.md +41 -0
  37. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/verification-diagnostics-and-security.md +63 -0
  38. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +3 -2
  39. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/metrics-conventions.md +8 -1
  40. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/sli-slo-design.md +2 -2
  41. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/canary-and-rollout-strategy.md +16 -2
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/promotion-gate-and-review.md +9 -0
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +14 -16
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/code-review-checklist.md +4 -0
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +1 -1
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-routing-and-readiness.md +10 -14
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +1 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/verify-developer-experience.md +1 -1
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/SKILL.md +135 -86
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/behavioral-aesthetic-logic.md +66 -80
  51. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/delivery-contract.md +275 -0
  52. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-execution-checklist.md +88 -214
  53. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-impl-naming-and-versioning.md +2 -2
  54. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-intake-and-acceptance.md +10 -8
  55. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-system-source-of-truth.md +6 -5
  56. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/external-ui-ux-quality-benchmarks.md +112 -95
  57. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/frontend-code-evidence-map.md +30 -21
  58. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/interaction-design-patterns.md +22 -3
  59. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/layout-recipes-and-screenshot-acceptance.md +20 -17
  60. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-project-token-consistency.md +7 -9
  61. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-stack-strategy.md +14 -10
  62. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/operational-processing-workflows.md +2 -0
  63. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-mobile-patterns.md +3 -3
  64. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-lifecycle-acceptance-and-iteration.md +9 -6
  65. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-surface-patterns.md +3 -0
  66. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/source-map.md +37 -10
  67. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/tokens-and-components.md +8 -1
  68. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-audit.md +16 -5
  69. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-design-development.md +16 -5
  70. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/visual-craft.md +4 -2
  71. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/multi-tenant-isolation.md +1 -1
  72. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +4 -1
  73. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/state-machine-task-patterns.md +2 -0
  74. package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/SKILL.md +1 -1
  75. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +8 -8
  76. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/description-authoring.md +4 -0
  77. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +104 -5
  78. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +11 -9
  79. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/r0-leakage-audit.md +102 -0
  80. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +103 -0
  81. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +20 -0
  82. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +6 -6
  83. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +4 -3
  84. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +69 -2
  85. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/extraction_review_gate.sh +22 -0
  86. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +49 -4
  87. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/obligation-ledger.py +2748 -0
  88. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/register-firing-path-resolution.rb +20 -5
  89. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/shared_git_surface_gate.py +1142 -0
  90. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +17 -0
  91. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +41 -4
  92. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ci_checkout_ref_binding.sh +120 -0
  93. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_entrypoint_domain_scan_terms.sh +82 -8
  94. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_extraction_review_gate.sh +336 -0
  95. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_self_adjudication.sh +82 -10
  96. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_obligation_ledger.sh +1416 -0
  97. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_obligation_ledger_repo_audit.sh +57 -0
  98. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +141 -4
  99. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_pointer_integrity.sh +3 -1
  100. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_shared_git_surface_gate.sh +1696 -0
  101. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_delivery_contract.sh +2117 -0
  102. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_loading_budget.sh +316 -0
  103. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_extraction_review_state.sh +1176 -0
  104. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_cross_refs.sh +31 -1
  105. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +9 -4
  106. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py +980 -0
  107. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +8 -6
  108. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/classical-test-design-techniques.md +1 -1
  109. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-review-and-prioritization.md +1 -1
  110. package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/update-lifecycle.md +2 -0
  111. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +16 -15
  112. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/ci-fixtures-and-flake-control.md +5 -1
  113. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/client-runtime-test-matrices.md +10 -2
  114. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/e2e-real-flow-testing.md +2 -2
  115. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/integration-contract-testing.md +10 -0
  116. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-code-authoring-patterns.md +2 -2
  117. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-topology-and-commands.md +1 -1
  118. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md +2 -1
  119. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/annotation-driven-revision.md +9 -0
  120. package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/figure-and-table-craft.md +8 -2
  121. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +7 -5
  122. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/complex-workspace-patterns.md +1 -1
  123. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/react-architecture.md +3 -0
  124. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-quality-release.md +37 -4
  125. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-ui-quality.md +10 -1
  126. package/dist/assets/release.json +215 -105
  127. package/package.json +1 -1
@@ -0,0 +1,1176 @@
1
+ #!/usr/bin/env bash
2
+ # Regression for receipt-bound extraction review terminal-state validation.
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
6
+ VALIDATOR="$SCRIPT_DIR/validate_extraction_review_state.py"
7
+ [ -f "$VALIDATOR" ] || { echo "FAIL: validator not found: $VALIDATOR" >&2; exit 1; }
8
+
9
+ TMP="$(mktemp -d "${TMPDIR:-/tmp}/extraction-review-state.XXXXXX")"
10
+ trap 'rm -rf "$TMP"' EXIT
11
+
12
+ python3 - "$VALIDATOR" "$TMP" <<'PY'
13
+ import copy
14
+ import hashlib
15
+ import json
16
+ import os
17
+ import subprocess
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ validator = Path(sys.argv[1])
22
+ root = Path(sys.argv[2])
23
+ A, B, C = (character * 40 for character in "abc")
24
+ CANDIDATE = "d" * 64
25
+ OTHER_CANDIDATE = "e" * 64
26
+ CLOSED_DISPOSITIONS = {
27
+ "fixed",
28
+ "source_refuted",
29
+ "accepted_tradeoff",
30
+ "pre_existing_out_of_scope",
31
+ }
32
+
33
+
34
+ def canonical_hash(value):
35
+ encoded = json.dumps(
36
+ value, ensure_ascii=False, sort_keys=True, separators=(",", ":")
37
+ ).encode()
38
+ return hashlib.sha256(encoded).hexdigest()
39
+
40
+
41
+ def write_json(name, payload):
42
+ encoded = (json.dumps(payload, ensure_ascii=False, indent=2) + "\n").encode()
43
+ (root / name).write_bytes(encoded)
44
+ return hashlib.sha256(encoded).hexdigest()
45
+
46
+
47
+ def encode_duplicate_key(payload, field, first_value):
48
+ pairs = []
49
+ for key, value in payload.items():
50
+ if key == field:
51
+ pairs.append((key, first_value))
52
+ pairs.append((key, value))
53
+ return (
54
+ "{"
55
+ + ",".join(
56
+ f"{json.dumps(key)}:{json.dumps(value, ensure_ascii=False)}"
57
+ for key, value in pairs
58
+ )
59
+ + "}\n"
60
+ ).encode()
61
+
62
+
63
+ def write_duplicate_json(name, payload, field, first_value):
64
+ encoded = encode_duplicate_key(payload, field, first_value)
65
+ (root / name).write_bytes(encoded)
66
+ return hashlib.sha256(encoded).hexdigest()
67
+
68
+
69
+ def write_base_evidence(name, base_sha, ref="refs/heads/dev"):
70
+ encoded = f"{base_sha}\t{ref}\n".encode()
71
+ (root / name).write_bytes(encoded)
72
+ return hashlib.sha256(encoded).hexdigest()
73
+
74
+
75
+ def occurrence_ref(occurrence):
76
+ return {
77
+ "receipt_sha256": occurrence["receipt_sha256"],
78
+ "finding_sha256": occurrence["finding_sha256"],
79
+ }
80
+
81
+
82
+ def bind_disposition_evidence(name, occurrence, *, resolves=None, evidence=None):
83
+ if resolves is None:
84
+ resolves = [occurrence_ref(occurrence)]
85
+ if evidence is None:
86
+ evidence = [
87
+ f"synthetic {occurrence['disposition']} evidence for the current candidate"
88
+ ]
89
+ payload = {
90
+ "schema_version": 1,
91
+ "candidate_sha256": CANDIDATE,
92
+ "receipt_sha256": occurrence["receipt_sha256"],
93
+ "finding_sha256": occurrence["finding_sha256"],
94
+ "disposition": occurrence["disposition"],
95
+ "resolves_occurrences": copy.deepcopy(resolves),
96
+ "evidence": list(evidence),
97
+ }
98
+ evidence_hash = write_json(name, payload)
99
+ occurrence.update(
100
+ disposition_evidence_file=name,
101
+ disposition_evidence_sha256=evidence_hash,
102
+ )
103
+ return payload
104
+
105
+
106
+ def clear_disposition_evidence(occurrence):
107
+ occurrence.pop("disposition_evidence_file", None)
108
+ occurrence.pop("disposition_evidence_sha256", None)
109
+
110
+
111
+ def mutate_disposition_evidence(occurrence, mutator):
112
+ evidence_path = root / occurrence["disposition_evidence_file"]
113
+ payload = json.loads(evidence_path.read_text(encoding="utf-8"))
114
+ mutator(payload)
115
+ occurrence["disposition_evidence_sha256"] = write_json(
116
+ occurrence["disposition_evidence_file"], payload
117
+ )
118
+
119
+
120
+ def duplicate_disposition_evidence_key(occurrence, field, first_value):
121
+ evidence_path = root / occurrence["disposition_evidence_file"]
122
+ payload = json.loads(evidence_path.read_text(encoding="utf-8"))
123
+ encoded = encode_duplicate_key(payload, field, first_value)
124
+ evidence_path.write_bytes(encoded)
125
+ occurrence["disposition_evidence_sha256"] = hashlib.sha256(encoded).hexdigest()
126
+
127
+
128
+ def finding(number):
129
+ return {
130
+ "severity": "P1",
131
+ "title": f"receipt-bound finding {number}",
132
+ "body": f"failure path {number}",
133
+ }
134
+
135
+
136
+ def make_fixture(
137
+ name,
138
+ *,
139
+ receipt_findings=None,
140
+ receipt_mutators=None,
141
+ completion=True,
142
+ completion_mutator=None,
143
+ budget=2,
144
+ base_shas=None,
145
+ closeout=None,
146
+ unmatched=0,
147
+ open_last=False,
148
+ ):
149
+ if receipt_findings is None:
150
+ receipt_findings = [[finding(1)], []]
151
+ receipt_mutators = receipt_mutators or {}
152
+ rounds = len(receipt_findings)
153
+ scope = {
154
+ "schema_version": 3,
155
+ "intent_sha256": "1" * 64,
156
+ "acceptance_sha256": "2" * 64,
157
+ "stage": "release",
158
+ "review_depth": "release",
159
+ "risk_tags": ["shared-gate"],
160
+ "challenge_budget": budget,
161
+ "wording_only_proof_sha256": None,
162
+ "wording_only_scope_sha256": None,
163
+ }
164
+ scope_sha = canonical_hash(scope)
165
+ receipts = []
166
+ receipt_hashes = []
167
+ receipt_refs = []
168
+ for index, findings in enumerate(receipt_findings, start=1):
169
+ mode = "review" if index == 1 else "challenge"
170
+ status = "findings" if findings else "passed"
171
+ remaining = 3 - index
172
+ if status == "findings":
173
+ state = "post_review_budget" if index == 3 else "findings_pending"
174
+ else:
175
+ state = "reviewed"
176
+ receipt = {
177
+ "schema_version": 3,
178
+ "mode": mode,
179
+ "status": status,
180
+ "findings": copy.deepcopy(findings),
181
+ "review_chain_tracked": True,
182
+ "review_chain_id": "extraction-chain",
183
+ "autonomous_review_index": index,
184
+ "autonomous_review_budget": 3,
185
+ "autonomous_reviews_remaining": remaining,
186
+ "autonomous_review_allowed": remaining > 0,
187
+ "challenge_index": 0 if index == 1 else index - 1,
188
+ "challenge_budget": budget,
189
+ "prior_review_result_sha256": list(receipt_hashes),
190
+ "candidate_sha256": CANDIDATE,
191
+ "packet_sha256": CANDIDATE,
192
+ "review_scope": copy.deepcopy(scope),
193
+ "review_scope_sha256": scope_sha,
194
+ "wording_only_proof_sha256": None,
195
+ "wording_only_scope": None,
196
+ "stage": "release",
197
+ "review_depth": "release",
198
+ "risk_tags": ["shared-gate"],
199
+ "review_state": state,
200
+ "human_decision_required": state == "post_review_budget",
201
+ }
202
+ mutator = receipt_mutators.get(index)
203
+ if mutator is not None:
204
+ mutator(receipt)
205
+ receipt_name = f"{name}-round-{index}.json"
206
+ receipt_hash = write_json(receipt_name, receipt)
207
+ receipts.append(receipt)
208
+ receipt_hashes.append(receipt_hash)
209
+ receipt_refs.append(
210
+ {"sequence": index, "file": receipt_name, "sha256": receipt_hash}
211
+ )
212
+
213
+ completion_ref = None
214
+ if completion:
215
+ final = receipts[-1]
216
+ complete = {
217
+ "schema_version": 3,
218
+ "mode": "complete",
219
+ "status": "passed",
220
+ "findings": [],
221
+ "review_chain_tracked": True,
222
+ "review_chain_id": final["review_chain_id"],
223
+ "autonomous_review_index": final["autonomous_review_index"],
224
+ "autonomous_review_budget": 3,
225
+ "autonomous_reviews_remaining": final["autonomous_reviews_remaining"],
226
+ "autonomous_review_allowed": False,
227
+ "challenge_budget": budget,
228
+ "prior_review_result_sha256": copy.deepcopy(
229
+ final["prior_review_result_sha256"]
230
+ ),
231
+ "candidate_sha256": final["candidate_sha256"],
232
+ "packet_sha256": final["packet_sha256"],
233
+ "review_scope": copy.deepcopy(final["review_scope"]),
234
+ "review_scope_sha256": final["review_scope_sha256"],
235
+ "wording_only_proof_sha256": None,
236
+ "wording_only_scope": None,
237
+ "stage": final["stage"],
238
+ "review_depth": final["review_depth"],
239
+ "risk_tags": copy.deepcopy(final["risk_tags"]),
240
+ "review_state": "self_reviewed",
241
+ "completion_gated": False,
242
+ "completion_review_result_sha256": receipt_hashes[-1],
243
+ "next_action": "complete",
244
+ }
245
+ if completion_mutator is not None:
246
+ completion_mutator(complete)
247
+ complete_name = f"{name}-complete.json"
248
+ complete_hash = write_json(complete_name, complete)
249
+ completion_ref = {"file": complete_name, "sha256": complete_hash}
250
+
251
+ if base_shas is None:
252
+ base_shas = [A] * rounds
253
+ attestations = []
254
+ for sequence, base_sha in enumerate(base_shas, start=1):
255
+ evidence_name = f"{name}-base-{sequence}.txt"
256
+ evidence_hash = write_base_evidence(evidence_name, base_sha)
257
+ attestations.append(
258
+ {
259
+ "sequence": sequence,
260
+ "remote": "origin",
261
+ "ref": "refs/heads/dev",
262
+ "sha": base_sha,
263
+ "confirmed_at": f"2026-08-29T12:{sequence:02d}:00Z",
264
+ "controller_receipt_sha256": (
265
+ receipt_hashes[sequence - 1] if sequence <= rounds else None
266
+ ),
267
+ "evidence_file": evidence_name,
268
+ "evidence_sha256": evidence_hash,
269
+ }
270
+ )
271
+
272
+ occurrences = []
273
+ for receipt, receipt_hash in zip(receipts, receipt_hashes):
274
+ for item in receipt["findings"]:
275
+ occurrences.append(
276
+ {
277
+ "receipt_sha256": receipt_hash,
278
+ "finding_sha256": canonical_hash(item),
279
+ "disposition": "fixed",
280
+ }
281
+ )
282
+ if open_last and occurrences:
283
+ occurrences[-1]["disposition"] = "open"
284
+ for occurrence_index, occurrence in enumerate(occurrences, start=1):
285
+ if occurrence["disposition"] in CLOSED_DISPOSITIONS:
286
+ bind_disposition_evidence(
287
+ f"{name}-disposition-{occurrence_index}.json",
288
+ occurrence,
289
+ )
290
+
291
+ classes = []
292
+ if occurrences:
293
+ sweep = None
294
+ if len(occurrences) >= 3:
295
+ searched_set = [
296
+ "skills/code-review",
297
+ "skills/skill-extraction-workflow",
298
+ ]
299
+ unmatched_items = [f"unmatched-{index}" for index in range(unmatched)]
300
+ manifest = {
301
+ "schema_version": 1,
302
+ "candidate_sha256": CANDIDATE,
303
+ "searched_set": searched_set,
304
+ "unmatched_instances": unmatched_items,
305
+ }
306
+ manifest_name = f"{name}-sweep.json"
307
+ manifest_hash = write_json(manifest_name, manifest)
308
+ sweep = {
309
+ "candidate_sha256": CANDIDATE,
310
+ "manifest_file": manifest_name,
311
+ "manifest_sha256": manifest_hash,
312
+ "searched_set": searched_set,
313
+ "unmatched_instances": unmatched,
314
+ }
315
+ classes.append(
316
+ {
317
+ "key": "receipt-binding",
318
+ "root_cause_predicate": "A closeout field is accepted without controller evidence.",
319
+ "affected_surface": "extraction closeout ledger",
320
+ "occurrences": occurrences,
321
+ "authoritative_sweep": sweep,
322
+ }
323
+ )
324
+
325
+ if closeout is None:
326
+ closeout = (
327
+ "ready_for_human_decision"
328
+ if completion
329
+ else "continuation_authorization_required"
330
+ )
331
+ controller_state = (
332
+ "self_reviewed" if completion else receipts[-1]["review_state"]
333
+ )
334
+ ledger = {
335
+ "schema_version": 3,
336
+ "candidate_sha256": CANDIDATE,
337
+ "controller_receipts": receipt_refs,
338
+ "completion_receipt": completion_ref,
339
+ "base_attestations": attestations,
340
+ "autonomous_round": rounds,
341
+ "controller_review_state": controller_state,
342
+ "finding_classes": classes,
343
+ "unreviewed_delta": [],
344
+ "closeout_state": closeout,
345
+ }
346
+ return {
347
+ "ledger": ledger,
348
+ "receipts": receipts,
349
+ "receipt_hashes": receipt_hashes,
350
+ }
351
+
352
+
353
+ def invoke_encoded(name, encoded):
354
+ path = root / f"{name}-ledger.json"
355
+ path.write_bytes(encoded)
356
+ try:
357
+ return subprocess.run(
358
+ [sys.executable, str(validator), str(path)],
359
+ stdout=subprocess.PIPE,
360
+ stderr=subprocess.STDOUT,
361
+ text=True,
362
+ check=False,
363
+ timeout=5,
364
+ )
365
+ except subprocess.TimeoutExpired as exc:
366
+ raise AssertionError((name, "validator blocked", exc)) from exc
367
+
368
+
369
+ def invoke(name, payload):
370
+ encoded = (json.dumps(payload, indent=2) + "\n").encode()
371
+ return invoke_encoded(name, encoded)
372
+
373
+
374
+ def run(name, payload, expected_rc, token):
375
+ result = invoke(name, payload)
376
+ assert result.returncode == expected_rc, (name, result.returncode, result.stdout)
377
+ assert token in result.stdout, (name, token, result.stdout)
378
+ assert "Traceback" not in result.stdout, (name, result.stdout)
379
+
380
+
381
+ ready = make_fixture("ready")
382
+ run("ready", ready["ledger"], 0, "closeout_state=ready_for_human_decision")
383
+
384
+ schema_v3 = make_fixture("schema-v3")
385
+ schema_v3["ledger"]["schema_version"] = 3
386
+ legacy_v2 = make_fixture("legacy-v2")
387
+ legacy_v2["ledger"]["schema_version"] = 2
388
+ schema_results = [
389
+ ("schema-v3", invoke("schema-v3", schema_v3["ledger"])),
390
+ ("legacy-v2", invoke("legacy-v2", legacy_v2["ledger"])),
391
+ ]
392
+ assert [
393
+ (result.returncode, expected_token in result.stdout, "Traceback" in result.stdout)
394
+ for (name, result), expected_token in zip(
395
+ schema_results,
396
+ ("closeout_state=ready_for_human_decision", "schema_version must be 3"),
397
+ strict=True,
398
+ )
399
+ ] == [(0, True, False), (1, True, False)], [
400
+ (name, result.returncode, result.stdout) for name, result in schema_results
401
+ ]
402
+
403
+ bad_digest = make_fixture("bad-digest")
404
+ bad_digest["ledger"]["controller_receipts"][0]["sha256"] = "f" * 64
405
+ run("bad-digest", bad_digest["ledger"], 1, "digest does not match")
406
+
407
+ # JSON floats equal to the expected integers must not satisfy integer guards.
408
+ float_schema = make_fixture("float-schema")
409
+ float_schema["ledger"]["schema_version"] = 3.0
410
+ run("float-schema", float_schema["ledger"], 1, "schema_version must be 3")
411
+
412
+ float_budget = make_fixture(
413
+ "float-budget",
414
+ receipt_mutators={2: lambda row: row.update(challenge_budget=2.0)},
415
+ )
416
+ run("float-budget", float_budget["ledger"], 1, "challenge_budget must be 2")
417
+
418
+ nan_schema = make_fixture("nan-schema")
419
+ nan_schema["ledger"]["schema_version"] = float("nan")
420
+ run("nan-schema", nan_schema["ledger"], 1, "non-standard JSON constant")
421
+
422
+ control_chain = make_fixture(
423
+ "control-chain",
424
+ receipt_mutators={
425
+ 2: lambda row: row.update(review_chain_id="chain\x1b[31mred")
426
+ },
427
+ )
428
+ run("control-chain", control_chain["ledger"], 1, "must not contain control characters")
429
+
430
+ # C1 controls and Unicode line/paragraph separators forge diagnostic line
431
+ # breaks just like C0 escapes; each must be rejected, not echoed.
432
+ for label, hostile in (
433
+ ("c1-csi", "chain\x9bred"),
434
+ ("c1-nel", "chain\x85red"),
435
+ ("line-sep", "chain\u2028red"),
436
+ ("para-sep", "chain\u2029red"),
437
+ ):
438
+ hostile_chain = make_fixture(
439
+ f"hostile-{label}",
440
+ receipt_mutators={2: lambda row, value=hostile: row.update(review_chain_id=value)},
441
+ )
442
+ run(
443
+ f"hostile-{label}",
444
+ hostile_chain["ledger"],
445
+ 1,
446
+ "must not contain control characters",
447
+ )
448
+
449
+ # A float completion schema_version must not satisfy the completion guard.
450
+ float_completion = make_fixture(
451
+ "float-completion",
452
+ completion_mutator=lambda row: row.update(schema_version=3.0),
453
+ )
454
+ run(
455
+ "float-completion",
456
+ float_completion["ledger"],
457
+ 1,
458
+ "completion receipt must be a passed self_reviewed complete result",
459
+ )
460
+
461
+ wrong_chain = make_fixture(
462
+ "wrong-chain",
463
+ receipt_mutators={2: lambda row: row.update(review_chain_id="other-chain")},
464
+ )
465
+ run("wrong-chain", wrong_chain["ledger"], 1, "review_chain_id")
466
+
467
+ wrong_mode = make_fixture(
468
+ "wrong-mode", receipt_mutators={2: lambda row: row.update(mode="review")}
469
+ )
470
+ run("wrong-mode", wrong_mode["ledger"], 1, "mode challenge")
471
+
472
+ wrong_prior = make_fixture(
473
+ "wrong-prior",
474
+ receipt_mutators={
475
+ 2: lambda row: row.update(prior_review_result_sha256=["f" * 64])
476
+ },
477
+ )
478
+ run("wrong-prior", wrong_prior["ledger"], 1, "prior_review_result_sha256")
479
+
480
+ packet_mismatch = make_fixture(
481
+ "packet-mismatch",
482
+ receipt_mutators={2: lambda row: row.update(packet_sha256=OTHER_CANDIDATE)},
483
+ )
484
+ run("packet-mismatch", packet_mismatch["ledger"], 1, "packet_sha256 must equal candidate_sha256")
485
+
486
+ def drift_scope(row):
487
+ row["review_scope"]["stage"] = "build"
488
+ row["review_scope_sha256"] = canonical_hash(row["review_scope"])
489
+ row["stage"] = "build"
490
+
491
+
492
+ scope_mismatch = make_fixture("scope-mismatch", receipt_mutators={2: drift_scope})
493
+ run("scope-mismatch", scope_mismatch["ledger"], 1, "review scope changed")
494
+
495
+ budget_four = make_fixture("budget-four", budget=4)
496
+ run("budget-four", budget_four["ledger"], 1, "challenge_budget must be 2")
497
+
498
+ review_only = make_fixture("review-only", receipt_findings=[[]])
499
+ run("review-only", review_only["ledger"], 1, "ready requires at least one tracked challenge")
500
+
501
+ missing_complete = make_fixture("missing-complete")
502
+ missing_complete["ledger"]["completion_receipt"] = None
503
+ run("missing-complete", missing_complete["ledger"], 1, "requires a completion receipt")
504
+
505
+ bad_complete_state = make_fixture(
506
+ "bad-complete-state",
507
+ completion_mutator=lambda row: row.update(review_state="reviewed"),
508
+ )
509
+ run("bad-complete-state", bad_complete_state["ledger"], 1, "passed self_reviewed")
510
+
511
+ bad_complete_hash = make_fixture(
512
+ "bad-complete-hash",
513
+ completion_mutator=lambda row: row.update(
514
+ completion_review_result_sha256="f" * 64
515
+ ),
516
+ )
517
+ run("bad-complete-hash", bad_complete_hash["ledger"], 1, "completion_review_result_sha256")
518
+
519
+ bad_complete_candidate = make_fixture(
520
+ "bad-complete-candidate",
521
+ completion_mutator=lambda row: row.update(
522
+ candidate_sha256=OTHER_CANDIDATE, packet_sha256=OTHER_CANDIDATE
523
+ ),
524
+ )
525
+ run("bad-complete-candidate", bad_complete_candidate["ledger"], 1, "exact final candidate")
526
+
527
+ bad_complete_remaining = make_fixture(
528
+ "bad-complete-remaining",
529
+ completion_mutator=lambda row: row.update(autonomous_reviews_remaining=2),
530
+ )
531
+ run(
532
+ "bad-complete-remaining",
533
+ bad_complete_remaining["ledger"],
534
+ 1,
535
+ "autonomous_reviews_remaining",
536
+ )
537
+
538
+ continuation = make_fixture(
539
+ "continuation",
540
+ receipt_findings=[[finding(1)], [], [finding(2)]],
541
+ completion=False,
542
+ open_last=True,
543
+ )
544
+ run(
545
+ "continuation",
546
+ continuation["ledger"],
547
+ 0,
548
+ "closeout_state=continuation_authorization_required",
549
+ )
550
+
551
+ continuation_unconsumed_first_drift = make_fixture(
552
+ "continuation-unconsumed-first-drift",
553
+ receipt_findings=[[finding(1)], [], [finding(2)]],
554
+ completion=False,
555
+ open_last=True,
556
+ base_shas=[A, A, A, B],
557
+ )
558
+ run(
559
+ "continuation-unconsumed-first-drift",
560
+ continuation_unconsumed_first_drift["ledger"],
561
+ 1,
562
+ "final controller receipt does not consume the latest attested base",
563
+ )
564
+
565
+ continuation_candidate = make_fixture(
566
+ "continuation-candidate",
567
+ receipt_findings=[[finding(1)], [], [finding(2)]],
568
+ completion=False,
569
+ open_last=True,
570
+ )
571
+ continuation_candidate["ledger"]["candidate_sha256"] = OTHER_CANDIDATE
572
+ run(
573
+ "continuation-candidate",
574
+ continuation_candidate["ledger"],
575
+ 1,
576
+ "controller receipt 1 does not bind the ledger candidate",
577
+ )
578
+
579
+ # A chain whose FIRST round reviewed a different candidate must not close out
580
+ # a ledger for the final candidate, even when the final round binds it.
581
+ drifted_round = make_fixture(
582
+ "drifted-round-candidate",
583
+ receipt_mutators={
584
+ 1: lambda row: row.update(
585
+ candidate_sha256=OTHER_CANDIDATE, packet_sha256=OTHER_CANDIDATE
586
+ )
587
+ },
588
+ )
589
+ run(
590
+ "drifted-round-candidate",
591
+ drifted_round["ledger"],
592
+ 1,
593
+ "controller receipt 1 does not bind the ledger candidate",
594
+ )
595
+
596
+ unknown_state = make_fixture(
597
+ "unknown-state",
598
+ receipt_findings=[[finding(1)], [], [finding(2)]],
599
+ receipt_mutators={3: lambda row: row.update(review_state="potato")},
600
+ completion=False,
601
+ open_last=True,
602
+ )
603
+ unknown_state["ledger"]["controller_review_state"] = "potato"
604
+ run("unknown-state", unknown_state["ledger"], 1, "unknown controller review_state")
605
+
606
+ passed_continuation = make_fixture(
607
+ "passed-continuation",
608
+ receipt_findings=[[finding(1)], [], []],
609
+ completion=False,
610
+ )
611
+ run("passed-continuation", passed_continuation["ledger"], 1, "round 3 findings in post_review_budget")
612
+
613
+ bad_finding_hash = make_fixture("bad-finding-hash")
614
+ bad_finding_hash["ledger"]["finding_classes"][0]["occurrences"][0][
615
+ "finding_sha256"
616
+ ] = "f" * 64
617
+ run("bad-finding-hash", bad_finding_hash["ledger"], 1, "does not identify a finding")
618
+
619
+ omitted_finding = make_fixture("omitted-finding")
620
+ omitted_finding["ledger"]["finding_classes"] = []
621
+ run("omitted-finding", omitted_finding["ledger"], 1, "omits controller findings")
622
+
623
+ reordered_findings = make_fixture(
624
+ "reordered-findings", receipt_findings=[[finding(1), finding(2)], []]
625
+ )
626
+ reordered_findings["ledger"]["finding_classes"][0]["occurrences"].reverse()
627
+ run("reordered-findings", reordered_findings["ledger"], 1, "not in controller receipt order")
628
+
629
+ fixed_without_evidence = make_fixture("fixed-without-evidence")
630
+ clear_disposition_evidence(
631
+ fixed_without_evidence["ledger"]["finding_classes"][0]["occurrences"][-1]
632
+ )
633
+ run(
634
+ "fixed-without-evidence",
635
+ fixed_without_evidence["ledger"],
636
+ 1,
637
+ "disposition_evidence_file",
638
+ )
639
+
640
+ for disposition in ("accepted_tradeoff", "pre_existing_out_of_scope"):
641
+ case_name = f"{disposition.replace('_', '-')}-without-evidence"
642
+ without_evidence = make_fixture(case_name)
643
+ without_evidence_occurrence = without_evidence["ledger"]["finding_classes"][0][
644
+ "occurrences"
645
+ ][-1]
646
+ without_evidence_occurrence["disposition"] = disposition
647
+ clear_disposition_evidence(without_evidence_occurrence)
648
+ run(case_name, without_evidence["ledger"], 1, "disposition_evidence_file")
649
+
650
+ bound_case_name = f"{disposition.replace('_', '-')}-bound"
651
+ bound = make_fixture(bound_case_name)
652
+ bound_occurrence = bound["ledger"]["finding_classes"][0]["occurrences"][-1]
653
+ bound_occurrence["disposition"] = disposition
654
+ bind_disposition_evidence(
655
+ f"{bound_case_name}-disposition.json",
656
+ bound_occurrence,
657
+ )
658
+ run(bound_case_name, bound["ledger"], 0, "ready_for_human_decision")
659
+
660
+ stale_disposition_evidence = make_fixture("stale-disposition-evidence")
661
+ stale_disposition_evidence_occurrence = stale_disposition_evidence["ledger"][
662
+ "finding_classes"
663
+ ][0]["occurrences"][-1]
664
+ mutate_disposition_evidence(
665
+ stale_disposition_evidence_occurrence,
666
+ lambda evidence: evidence.update(candidate_sha256=OTHER_CANDIDATE),
667
+ )
668
+ run(
669
+ "stale-disposition-evidence",
670
+ stale_disposition_evidence["ledger"],
671
+ 1,
672
+ "stale for the current candidate",
673
+ )
674
+
675
+ wrong_disposition_evidence = make_fixture("wrong-disposition-evidence")
676
+ wrong_disposition_evidence_occurrence = wrong_disposition_evidence["ledger"][
677
+ "finding_classes"
678
+ ][0]["occurrences"][-1]
679
+ mutate_disposition_evidence(
680
+ wrong_disposition_evidence_occurrence,
681
+ lambda evidence: evidence.update(disposition="accepted_tradeoff"),
682
+ )
683
+ run(
684
+ "wrong-disposition-evidence",
685
+ wrong_disposition_evidence["ledger"],
686
+ 1,
687
+ "does not bind its disposition",
688
+ )
689
+
690
+ duplicate_key_cases = []
691
+ for case_name, field, first_value in (
692
+ ("duplicate-candidate-evidence", "candidate_sha256", OTHER_CANDIDATE),
693
+ ("duplicate-disposition-evidence", "disposition", "accepted_tradeoff"),
694
+ ):
695
+ duplicate_case = make_fixture(case_name)
696
+ duplicate_occurrence = duplicate_case["ledger"]["finding_classes"][0][
697
+ "occurrences"
698
+ ][-1]
699
+ duplicate_disposition_evidence_key(duplicate_occurrence, field, first_value)
700
+ duplicate_result = invoke(case_name, duplicate_case["ledger"])
701
+ duplicate_key_cases.append(
702
+ (
703
+ case_name,
704
+ duplicate_result.returncode,
705
+ f"duplicate object key: {field}" in duplicate_result.stdout,
706
+ "Traceback" in duplicate_result.stdout,
707
+ duplicate_result.stdout,
708
+ )
709
+ )
710
+ assert [item[1:4] for item in duplicate_key_cases] == [
711
+ (1, True, False),
712
+ (1, True, False),
713
+ ], duplicate_key_cases
714
+
715
+ wrong_receipt_evidence = make_fixture("wrong-receipt-evidence")
716
+ wrong_receipt_evidence_occurrence = wrong_receipt_evidence["ledger"][
717
+ "finding_classes"
718
+ ][0]["occurrences"][-1]
719
+ mutate_disposition_evidence(
720
+ wrong_receipt_evidence_occurrence,
721
+ lambda evidence: evidence.update(receipt_sha256="f" * 64),
722
+ )
723
+ run(
724
+ "wrong-receipt-evidence",
725
+ wrong_receipt_evidence["ledger"],
726
+ 1,
727
+ "does not bind its controller receipt",
728
+ )
729
+
730
+ wrong_finding_evidence = make_fixture("wrong-finding-evidence")
731
+ wrong_finding_evidence_occurrence = wrong_finding_evidence["ledger"][
732
+ "finding_classes"
733
+ ][0]["occurrences"][-1]
734
+ mutate_disposition_evidence(
735
+ wrong_finding_evidence_occurrence,
736
+ lambda evidence: evidence.update(finding_sha256="f" * 64),
737
+ )
738
+ run(
739
+ "wrong-finding-evidence",
740
+ wrong_finding_evidence["ledger"],
741
+ 1,
742
+ "does not bind its controller finding",
743
+ )
744
+
745
+ historical_open = make_fixture(
746
+ "historical-open",
747
+ receipt_findings=[[finding(1)], [finding(2)], []],
748
+ )
749
+ historical_open["ledger"]["finding_classes"][0]["occurrences"][0][
750
+ "disposition"
751
+ ] = "open"
752
+ clear_disposition_evidence(
753
+ historical_open["ledger"]["finding_classes"][0]["occurrences"][0]
754
+ )
755
+ run("historical-open", historical_open["ledger"], 1, "unresolved finding occurrence")
756
+
757
+ historical_open_linked = make_fixture(
758
+ "historical-open-linked",
759
+ receipt_findings=[[finding(1)], [finding(2)], []],
760
+ )
761
+ historical_open_linked_occurrences = historical_open_linked["ledger"][
762
+ "finding_classes"
763
+ ][0]["occurrences"]
764
+ historical_open_linked_occurrences[0]["disposition"] = "open"
765
+ clear_disposition_evidence(historical_open_linked_occurrences[0])
766
+ bind_disposition_evidence(
767
+ "historical-open-linked-disposition.json",
768
+ historical_open_linked_occurrences[1],
769
+ resolves=[
770
+ occurrence_ref(historical_open_linked_occurrences[0]),
771
+ occurrence_ref(historical_open_linked_occurrences[1]),
772
+ ],
773
+ )
774
+ run(
775
+ "historical-open-linked",
776
+ historical_open_linked["ledger"],
777
+ 0,
778
+ "ready_for_human_decision",
779
+ )
780
+
781
+ source_refuted_without_evidence = make_fixture("source-refuted-without-evidence")
782
+ source_refuted_without_evidence_occurrence = source_refuted_without_evidence["ledger"][
783
+ "finding_classes"
784
+ ][0]["occurrences"][-1]
785
+ source_refuted_without_evidence_occurrence["disposition"] = "source_refuted"
786
+ clear_disposition_evidence(source_refuted_without_evidence_occurrence)
787
+ run(
788
+ "source-refuted-without-evidence",
789
+ source_refuted_without_evidence["ledger"],
790
+ 1,
791
+ "disposition_evidence_file",
792
+ )
793
+
794
+ source_refuted = make_fixture("source-refuted")
795
+ source_refuted_occurrence = source_refuted["ledger"]["finding_classes"][0][
796
+ "occurrences"
797
+ ][-1]
798
+ source_refuted_occurrence["disposition"] = "source_refuted"
799
+ bind_disposition_evidence(
800
+ "source-refuted-evidence.json",
801
+ source_refuted_occurrence,
802
+ evidence=["synthetic first-hand source evidence"],
803
+ )
804
+ run("source-refuted", source_refuted["ledger"], 0, "ready_for_human_decision")
805
+
806
+ source_refuted_bad_hash = copy.deepcopy(source_refuted["ledger"])
807
+ source_refuted_bad_hash["finding_classes"][0]["occurrences"][-1][
808
+ "disposition_evidence_sha256"
809
+ ] = "f" * 64
810
+ run(
811
+ "source-refuted-bad-hash",
812
+ source_refuted_bad_hash,
813
+ 1,
814
+ "digest does not match",
815
+ )
816
+
817
+ needs_human = make_fixture("needs-human")
818
+ needs_human["ledger"]["finding_classes"][0]["occurrences"][-1][
819
+ "disposition"
820
+ ] = "needs_human_decision"
821
+ clear_disposition_evidence(
822
+ needs_human["ledger"]["finding_classes"][0]["occurrences"][-1]
823
+ )
824
+ run("needs-human", needs_human["ledger"], 1, "unresolved finding occurrence")
825
+
826
+ third_occurrence = make_fixture(
827
+ "third-occurrence",
828
+ receipt_findings=[[finding(1)], [finding(2)], [finding(3)]],
829
+ completion=False,
830
+ unmatched=1,
831
+ open_last=True,
832
+ )
833
+ run("third-occurrence", third_occurrence["ledger"], 0, "continuation_authorization_required")
834
+
835
+ split_predicate = copy.deepcopy(third_occurrence["ledger"])
836
+ original_class = split_predicate["finding_classes"][0]
837
+ predicate_variants = [
838
+ "A closeout field is accepted without controller evidence.",
839
+ "a closeout field is accepted without controller evidence.",
840
+ "A closeout field is accepted without controller evidence.",
841
+ ]
842
+ split_predicate["finding_classes"] = [
843
+ {
844
+ "key": f"receipt-binding-{index}",
845
+ "root_cause_predicate": predicate_variants[index - 1],
846
+ "affected_surface": original_class["affected_surface"],
847
+ "occurrences": [copy.deepcopy(occurrence)],
848
+ "authoritative_sweep": None,
849
+ }
850
+ for index, occurrence in enumerate(original_class["occurrences"], start=1)
851
+ ]
852
+ run(
853
+ "split-predicate",
854
+ split_predicate,
855
+ 1,
856
+ "duplicate normalized root_cause_predicate",
857
+ )
858
+
859
+ distinct_predicates = copy.deepcopy(split_predicate)
860
+ for index, row in enumerate(distinct_predicates["finding_classes"], start=1):
861
+ row["root_cause_predicate"] = (
862
+ f"Distinct controller-evidence failure predicate {index}."
863
+ )
864
+ run(
865
+ "distinct-predicates",
866
+ distinct_predicates,
867
+ 0,
868
+ "closeout_state=continuation_authorization_required",
869
+ )
870
+
871
+ missing_sweep = copy.deepcopy(third_occurrence["ledger"])
872
+ missing_sweep["finding_classes"][0]["authoritative_sweep"] = None
873
+ run("missing-sweep", missing_sweep, 1, "authoritative_sweep")
874
+
875
+ bad_sweep_set = copy.deepcopy(third_occurrence["ledger"])
876
+ bad_sweep_set["finding_classes"][0]["authoritative_sweep"]["searched_set"] = [
877
+ "skills/code-review"
878
+ ]
879
+ run("bad-sweep-set", bad_sweep_set, 1, "searched_set does not match")
880
+
881
+ ready_unmatched = make_fixture(
882
+ "ready-unmatched",
883
+ receipt_findings=[[finding(1), finding(2), finding(3)], []],
884
+ unmatched=1,
885
+ )
886
+ run("ready-unmatched", ready_unmatched["ledger"], 1, "ready sweep must report zero unmatched")
887
+
888
+ wrong_remote = make_fixture("wrong-remote")
889
+ wrong_remote["ledger"]["base_attestations"][1]["remote"] = "upstream"
890
+ run("wrong-remote", wrong_remote["ledger"], 1, "same remote and ref")
891
+
892
+ bad_sequence = make_fixture("bad-sequence")
893
+ bad_sequence["ledger"]["base_attestations"][1]["sequence"] = 3
894
+ run("bad-sequence", bad_sequence["ledger"], 1, "sequence must be contiguous")
895
+
896
+ bad_time = make_fixture("bad-time")
897
+ bad_time["ledger"]["base_attestations"][1]["confirmed_at"] = "2026-08-29T12:01:00Z"
898
+ run("bad-time", bad_time["ledger"], 1, "strictly increase")
899
+
900
+ invalid_time = make_fixture("invalid-time")
901
+ invalid_time["ledger"]["base_attestations"][0]["confirmed_at"] = "2026-08-29 12:00:00"
902
+ run("invalid-time", invalid_time["ledger"], 1, "strict RFC3339")
903
+
904
+ missing_mapping = make_fixture("missing-mapping")
905
+ missing_mapping["ledger"]["base_attestations"][1]["controller_receipt_sha256"] = None
906
+ run("missing-mapping", missing_mapping["ledger"], 1, "map every controller receipt")
907
+
908
+ consumed_first_drift = make_fixture("consumed-first-drift", base_shas=[A, B])
909
+ run(
910
+ "consumed-first-drift",
911
+ consumed_first_drift["ledger"],
912
+ 0,
913
+ "closeout_state=ready_for_human_decision",
914
+ )
915
+
916
+ stable_trailing_recheck = make_fixture(
917
+ "stable-trailing-recheck", base_shas=[A, A, A]
918
+ )
919
+ run(
920
+ "stable-trailing-recheck",
921
+ stable_trailing_recheck["ledger"],
922
+ 0,
923
+ "closeout_state=ready_for_human_decision",
924
+ )
925
+
926
+ unconsumed_first_drift = make_fixture(
927
+ "unconsumed-first-drift", base_shas=[A, A, B]
928
+ )
929
+ run(
930
+ "unconsumed-first-drift",
931
+ unconsumed_first_drift["ledger"],
932
+ 1,
933
+ "final controller receipt does not consume the latest attested base",
934
+ )
935
+
936
+ bad_evidence = make_fixture("bad-evidence")
937
+ bad_evidence["ledger"]["base_attestations"][0]["evidence_sha256"] = "f" * 64
938
+ run("bad-evidence", bad_evidence["ledger"], 1, "digest does not match")
939
+
940
+ bad_evidence_content = make_fixture("bad-evidence-content")
941
+ bad_evidence_row = bad_evidence_content["ledger"]["base_attestations"][0]
942
+ bad_evidence_path = root / bad_evidence_row["evidence_file"]
943
+ bad_evidence_path.write_text(f"{A}\trefs/heads/other\n", encoding="utf-8")
944
+ bad_evidence_row["evidence_sha256"] = hashlib.sha256(
945
+ bad_evidence_path.read_bytes()
946
+ ).hexdigest()
947
+ run(
948
+ "bad-evidence-content",
949
+ bad_evidence_content["ledger"],
950
+ 1,
951
+ "canonical ls-remote output",
952
+ )
953
+
954
+ surrogate = make_fixture("surrogate")
955
+ surrogate["ledger"]["controller_review_state"] = "\ud800"
956
+ run("surrogate", surrogate["ledger"], 1, "valid UTF-8 text")
957
+
958
+ fifo = make_fixture("fifo")
959
+ fifo_name = "controller-receipt.fifo"
960
+ os.mkfifo(root / fifo_name)
961
+ fifo["ledger"]["controller_receipts"][0]["file"] = fifo_name
962
+ fifo["ledger"]["controller_receipts"][0]["sha256"] = "f" * 64
963
+ run("fifo", fifo["ledger"], 1, "singly linked regular file")
964
+
965
+ second_drift_wrong = make_fixture("second-drift-wrong", base_shas=[A, B, A])
966
+ run("second-drift-wrong", second_drift_wrong["ledger"], 1, "second base drift")
967
+
968
+ flip_flop = make_fixture(
969
+ "flip-flop",
970
+ completion=False,
971
+ base_shas=[A, B, A],
972
+ closeout="baseline_race",
973
+ )
974
+ flip_flop["ledger"]["unreviewed_delta"] = ["target returned to its first SHA"]
975
+ run("flip-flop", flip_flop["ledger"], 0, "base_changes=2")
976
+
977
+ one_round_race = make_fixture(
978
+ "one-round-race",
979
+ receipt_findings=[[]],
980
+ completion=False,
981
+ base_shas=[A, B, C],
982
+ closeout="baseline_race",
983
+ )
984
+ one_round_race["ledger"]["unreviewed_delta"] = ["second target drift after round 1"]
985
+ run("one-round-race", one_round_race["ledger"], 0, "base_changes=2")
986
+
987
+ post_race_round = make_fixture(
988
+ "post-race-round",
989
+ completion=False,
990
+ base_shas=[A, B, C],
991
+ closeout="baseline_race",
992
+ )
993
+ post_race_round["ledger"]["base_attestations"][1][
994
+ "controller_receipt_sha256"
995
+ ] = None
996
+ post_race_round["ledger"]["base_attestations"][2][
997
+ "controller_receipt_sha256"
998
+ ] = post_race_round["receipt_hashes"][1]
999
+ post_race_round["ledger"]["unreviewed_delta"] = [
1000
+ "round 2 was started after the second target drift"
1001
+ ]
1002
+ run(
1003
+ "post-race-round",
1004
+ post_race_round["ledger"],
1005
+ 1,
1006
+ "controller receipt is mapped at or after the second base drift",
1007
+ )
1008
+
1009
+ race_with_complete = make_fixture(
1010
+ "race-with-complete", base_shas=[A, B, C], closeout="baseline_race"
1011
+ )
1012
+ race_with_complete["ledger"]["unreviewed_delta"] = ["second target drift"]
1013
+ run("race-with-complete", race_with_complete["ledger"], 1, "cannot carry a completion receipt")
1014
+
1015
+ race_without_delta = make_fixture(
1016
+ "race-without-delta",
1017
+ completion=False,
1018
+ base_shas=[A, B, C],
1019
+ closeout="baseline_race",
1020
+ )
1021
+ run("race-without-delta", race_without_delta["ledger"], 1, "non-empty unreviewed_delta")
1022
+
1023
+ race_candidate = make_fixture(
1024
+ "race-candidate",
1025
+ completion=False,
1026
+ base_shas=[A, B, C],
1027
+ closeout="baseline_race",
1028
+ )
1029
+ race_candidate["ledger"]["candidate_sha256"] = OTHER_CANDIDATE
1030
+ race_candidate["ledger"]["unreviewed_delta"] = ["second target drift"]
1031
+ run(
1032
+ "race-candidate",
1033
+ race_candidate["ledger"],
1034
+ 1,
1035
+ "controller receipt 1 does not bind the ledger candidate",
1036
+ )
1037
+
1038
+ false_race = make_fixture(
1039
+ "false-race", completion=False, closeout="baseline_race"
1040
+ )
1041
+ run("false-race", false_race["ledger"], 1, "baseline_race requires two ordered base changes")
1042
+
1043
+ needs_human_resolution_results = []
1044
+ for closing_disposition in sorted(CLOSED_DISPOSITIONS):
1045
+ case_name = f"historical-needs-human-{closing_disposition.replace('_', '-')}"
1046
+ historical_needs_human_linked = make_fixture(
1047
+ case_name,
1048
+ receipt_findings=[[finding(1)], [finding(2)], []],
1049
+ )
1050
+ historical_needs_human_occurrences = historical_needs_human_linked["ledger"][
1051
+ "finding_classes"
1052
+ ][0]["occurrences"]
1053
+ historical_needs_human_occurrences[0]["disposition"] = "needs_human_decision"
1054
+ clear_disposition_evidence(historical_needs_human_occurrences[0])
1055
+ historical_needs_human_occurrences[1]["disposition"] = closing_disposition
1056
+ bind_disposition_evidence(
1057
+ f"{case_name}-disposition.json",
1058
+ historical_needs_human_occurrences[1],
1059
+ resolves=[
1060
+ occurrence_ref(historical_needs_human_occurrences[0]),
1061
+ occurrence_ref(historical_needs_human_occurrences[1]),
1062
+ ],
1063
+ )
1064
+ needs_human_resolution_results.append(
1065
+ (case_name, invoke(case_name, historical_needs_human_linked["ledger"]))
1066
+ )
1067
+
1068
+ duplicate_ledger = make_fixture("duplicate-ledger")
1069
+ duplicate_ledger_result = invoke_encoded(
1070
+ "duplicate-ledger",
1071
+ encode_duplicate_key(duplicate_ledger["ledger"], "schema_version", 2),
1072
+ )
1073
+
1074
+ duplicate_controller = make_fixture("duplicate-controller")
1075
+ duplicate_controller_ledger = duplicate_controller["ledger"]
1076
+ duplicate_controller_name = duplicate_controller_ledger["controller_receipts"][-1][
1077
+ "file"
1078
+ ]
1079
+ duplicate_controller_payload = json.loads(
1080
+ (root / duplicate_controller_name).read_text(encoding="utf-8")
1081
+ )
1082
+ duplicate_controller_hash = write_duplicate_json(
1083
+ duplicate_controller_name,
1084
+ duplicate_controller_payload,
1085
+ "status",
1086
+ "findings",
1087
+ )
1088
+ duplicate_controller_ledger["controller_receipts"][-1][
1089
+ "sha256"
1090
+ ] = duplicate_controller_hash
1091
+ duplicate_controller_ledger["base_attestations"][-1][
1092
+ "controller_receipt_sha256"
1093
+ ] = duplicate_controller_hash
1094
+ duplicate_controller_complete_name = duplicate_controller_ledger[
1095
+ "completion_receipt"
1096
+ ]["file"]
1097
+ duplicate_controller_complete = json.loads(
1098
+ (root / duplicate_controller_complete_name).read_text(encoding="utf-8")
1099
+ )
1100
+ duplicate_controller_complete[
1101
+ "completion_review_result_sha256"
1102
+ ] = duplicate_controller_hash
1103
+ duplicate_controller_ledger["completion_receipt"]["sha256"] = write_json(
1104
+ duplicate_controller_complete_name,
1105
+ duplicate_controller_complete,
1106
+ )
1107
+ duplicate_controller_result = invoke(
1108
+ "duplicate-controller",
1109
+ duplicate_controller_ledger,
1110
+ )
1111
+
1112
+ duplicate_completion = make_fixture("duplicate-completion")
1113
+ duplicate_completion_ledger = duplicate_completion["ledger"]
1114
+ duplicate_completion_name = duplicate_completion_ledger["completion_receipt"]["file"]
1115
+ duplicate_completion_payload = json.loads(
1116
+ (root / duplicate_completion_name).read_text(encoding="utf-8")
1117
+ )
1118
+ duplicate_completion_ledger["completion_receipt"]["sha256"] = write_duplicate_json(
1119
+ duplicate_completion_name,
1120
+ duplicate_completion_payload,
1121
+ "review_state",
1122
+ "reviewed",
1123
+ )
1124
+ duplicate_completion_result = invoke(
1125
+ "duplicate-completion",
1126
+ duplicate_completion_ledger,
1127
+ )
1128
+
1129
+ duplicate_sweep = make_fixture(
1130
+ "duplicate-sweep",
1131
+ receipt_findings=[[finding(1)], [finding(2)], [finding(3)]],
1132
+ completion=False,
1133
+ open_last=True,
1134
+ )
1135
+ duplicate_sweep_ledger = duplicate_sweep["ledger"]
1136
+ duplicate_sweep_row = duplicate_sweep_ledger["finding_classes"][0][
1137
+ "authoritative_sweep"
1138
+ ]
1139
+ duplicate_sweep_payload = json.loads(
1140
+ (root / duplicate_sweep_row["manifest_file"]).read_text(encoding="utf-8")
1141
+ )
1142
+ duplicate_sweep_row["manifest_sha256"] = write_duplicate_json(
1143
+ duplicate_sweep_row["manifest_file"],
1144
+ duplicate_sweep_payload,
1145
+ "candidate_sha256",
1146
+ OTHER_CANDIDATE,
1147
+ )
1148
+ duplicate_sweep_result = invoke("duplicate-sweep", duplicate_sweep_ledger)
1149
+
1150
+ new_regressions = [
1151
+ *[
1152
+ (
1153
+ case_name,
1154
+ result,
1155
+ "cannot resolve a needs_human_decision occurrence",
1156
+ )
1157
+ for case_name, result in needs_human_resolution_results
1158
+ ],
1159
+ ("duplicate-ledger", duplicate_ledger_result, "duplicate object key: schema_version"),
1160
+ ("duplicate-controller", duplicate_controller_result, "duplicate object key: status"),
1161
+ (
1162
+ "duplicate-completion",
1163
+ duplicate_completion_result,
1164
+ "duplicate object key: review_state",
1165
+ ),
1166
+ ("duplicate-sweep", duplicate_sweep_result, "duplicate object key: candidate_sha256"),
1167
+ ]
1168
+ assert [
1169
+ (name, result.returncode, token in result.stdout, "Traceback" in result.stdout)
1170
+ for name, result, token in new_regressions
1171
+ ] == [(name, 1, True, False) for name, _result, _token in new_regressions], [
1172
+ (name, result.returncode, result.stdout) for name, result, _token in new_regressions
1173
+ ]
1174
+
1175
+ print("test_validate_extraction_review_state: ok")
1176
+ PY