@ccoalm/ccl-skills 0.7.0 → 0.8.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 (91) 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 +1 -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/staged-review-contract.md +195 -7
  7. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/timeout-auth-and-capabilities.md +3 -3
  8. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +13 -5
  9. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +9 -3
  10. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +9 -3
  11. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/normalize_review_timeout.sh +22 -0
  12. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/opencode_review.sh +9 -3
  13. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +1540 -129
  14. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +8 -3
  15. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +76 -1
  16. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +1858 -3
  17. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_update_review_plan_intent.sh +789 -0
  18. package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/update_review_plan_intent.py +513 -0
  19. package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +4 -1
  20. package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +2 -1
  21. package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +11 -10
  22. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/SKILL.md +64 -0
  23. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/agents/openai.yaml +4 -0
  24. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/async-lifecycle-and-performance.md +72 -0
  25. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/runtime-and-project-contract.md +58 -0
  26. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/source-map.md +41 -0
  27. package/dist/assets/marketplace/plugins/ccl-skills/skills/nodejs-service-dev/references/verification-diagnostics-and-security.md +63 -0
  28. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +8 -10
  29. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-routing-and-readiness.md +10 -14
  30. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/verify-developer-experience.md +1 -1
  31. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/SKILL.md +135 -86
  32. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/behavioral-aesthetic-logic.md +66 -80
  33. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/delivery-contract.md +275 -0
  34. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-execution-checklist.md +88 -214
  35. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-impl-naming-and-versioning.md +2 -2
  36. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-intake-and-acceptance.md +10 -8
  37. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-system-source-of-truth.md +4 -5
  38. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/external-ui-ux-quality-benchmarks.md +112 -95
  39. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/frontend-code-evidence-map.md +30 -21
  40. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/interaction-design-patterns.md +22 -3
  41. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/layout-recipes-and-screenshot-acceptance.md +20 -17
  42. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-project-token-consistency.md +7 -9
  43. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-stack-strategy.md +14 -10
  44. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/operational-processing-workflows.md +2 -0
  45. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-mobile-patterns.md +1 -1
  46. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-lifecycle-acceptance-and-iteration.md +9 -6
  47. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-surface-patterns.md +3 -0
  48. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/source-map.md +37 -10
  49. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/tokens-and-components.md +7 -1
  50. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-audit.md +8 -5
  51. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-design-development.md +16 -5
  52. package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/visual-craft.md +4 -2
  53. package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +4 -1
  54. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +4 -4
  55. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +95 -5
  56. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +11 -9
  57. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/r0-leakage-audit.md +102 -0
  58. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +54 -0
  59. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +8 -0
  60. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +6 -6
  61. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +4 -3
  62. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +69 -2
  63. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/extraction_review_gate.sh +22 -0
  64. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +49 -4
  65. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/obligation-ledger.py +2748 -0
  66. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/register-firing-path-resolution.rb +20 -5
  67. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/shared_git_surface_gate.py +1142 -0
  68. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +17 -0
  69. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +41 -4
  70. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ci_checkout_ref_binding.sh +120 -0
  71. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_entrypoint_domain_scan_terms.sh +82 -8
  72. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_extraction_review_gate.sh +336 -0
  73. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_self_adjudication.sh +82 -10
  74. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_obligation_ledger.sh +1416 -0
  75. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_obligation_ledger_repo_audit.sh +57 -0
  76. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +141 -4
  77. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_pointer_integrity.sh +3 -1
  78. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_shared_git_surface_gate.sh +1696 -0
  79. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_delivery_contract.sh +2117 -0
  80. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_uiux_loading_budget.sh +316 -0
  81. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_extraction_review_state.sh +1176 -0
  82. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_cross_refs.sh +31 -1
  83. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +9 -4
  84. package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py +980 -0
  85. package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +8 -6
  86. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +8 -7
  87. package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/client-runtime-test-matrices.md +10 -2
  88. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +6 -5
  89. package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/complex-workspace-patterns.md +1 -1
  90. package/dist/assets/release.json +175 -70
  91. 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