@arbiterforge/ca-pi 0.17.4 → 0.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ and durable project context. You decide. codeArbiter enforces.
10
10
  <img alt="Claude Code plugin" src="https://img.shields.io/badge/Claude_Code-plugin-d97757">
11
11
  <img alt="Codex plugin" src="https://img.shields.io/badge/OpenAI_Codex-plugin-10a37f">
12
12
  <img alt="Pi Feature Forge preview" src="https://img.shields.io/badge/ca--pi-Feature_Forge_preview-d97757">
13
- <img alt="version 2.25.3" src="https://img.shields.io/badge/version-2.25.3-2b7489">
13
+ <img alt="version 2.25.4" src="https://img.shields.io/badge/version-2.25.4-2b7489">
14
14
  <img alt="core lanes" src="https://img.shields.io/badge/core_lanes-18-555">
15
15
  <img alt="skills" src="https://img.shields.io/badge/skills-22-555">
16
16
  <img alt="agents" src="https://img.shields.io/badge/agents-20-555">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbiterforge/ca-pi",
3
- "version": "0.17.4",
3
+ "version": "0.17.5",
4
4
  "license": "AGPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -4,6 +4,19 @@ All notable changes to `ca-pi` are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.17.5] - 2026-10-10
8
+
9
+ ### Fixed
10
+
11
+ - Preserve the shared adapter's bounded native completion-review context
12
+ references and complete review-result prompt contract (#921).
13
+ - Fingerprint complete completion-review workspaces up to 1 GiB independently
14
+ of the 256 MiB selected verification-input budget. Preserve full content
15
+ hashing, freshness checks, and the 32 MiB member and 50,000 entry limits.
16
+ - Preserve the shared engine's distinct fresh-verification completion profile
17
+ and historical receipt validation. Pi verification and review authority remain
18
+ unsupported; this shared payload change does not enable those host seams.
19
+
7
20
  ## [0.17.4] - 2026-10-09
8
21
 
9
22
  ### Changed
@@ -6,43 +6,43 @@
6
6
  "binaries": {
7
7
  "darwin/amd64": {
8
8
  "file": "ca-artifact-darwin-amd64",
9
- "sha256": "433780fa59913512346069f9e1891e306a8bec41ed6fcc7cd26b50748d03ae06",
9
+ "sha256": "12a8a4b23da84cd672d03abe0c748310225e8bce47c5e8c8cbb3753e5acdbe57",
10
10
  "native_tested": true
11
11
  },
12
12
  "darwin/arm64": {
13
13
  "file": "ca-artifact-darwin-arm64",
14
- "sha256": "b68192c7a1da2cd2f9031f71ab4c7e015673f060d6bfdfa3aa4b57d9f090bf34",
14
+ "sha256": "2107c247473c8a9cc7c422dd754d98fa6211cf7bec5b7ecdd85ba5d7db0676b0",
15
15
  "native_tested": true
16
16
  },
17
17
  "linux/amd64": {
18
18
  "file": "ca-artifact-linux-amd64",
19
- "sha256": "09582eabdef3f828a12de21b85ccc7b52a188651c2a4f69f3f776a2e62c86036",
19
+ "sha256": "92e27501fd18ae805c6390b17b4f2335e97d69c3645c60b3267fb7869c624727",
20
20
  "native_tested": true
21
21
  },
22
22
  "linux/arm64": {
23
23
  "file": "ca-artifact-linux-arm64",
24
- "sha256": "f7699ce8f2f07200ea8508f21a6d369506443392aa8897d84e9d5e7dd6469770",
24
+ "sha256": "1961df0bdf37fd6a7b3a6214b925cf9f3b2efe0e797c05151a43ee96d7df07b3",
25
25
  "native_tested": true
26
26
  },
27
27
  "windows/amd64": {
28
28
  "file": "ca-artifact-windows-amd64.exe",
29
- "sha256": "9a0f186e2a1bcfd92c8f9db5cb0aa2f6dfb128dd6f0dad2708a78596f0364e16",
29
+ "sha256": "63def27bda36ed03c9f7e6898eaf2110badda2419950a8dcb91666c4e4bdd438",
30
30
  "native_tested": true
31
31
  },
32
32
  "windows/arm64": {
33
33
  "file": "ca-artifact-windows-arm64.exe",
34
- "sha256": "3f1bc7d00f9488b4a4a9f21e5ca414fd5c97031ad7b1c2b52c02f5d7f2956e3a",
34
+ "sha256": "107e1a8fe971fe24ce8a274ce1188b15c9785e4f94b835dadde1918b8fed5c4b",
35
35
  "native_tested": true
36
36
  }
37
37
  },
38
38
  "context_qualification": {
39
39
  "darwin/amd64": {
40
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
40
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
41
41
  "workflow": ".github/workflows/ci.yml",
42
- "run_id": "37938394077",
43
- "binary_sha256": "433780fa59913512346069f9e1891e306a8bec41ed6fcc7cd26b50748d03ae06",
44
- "observation_sha256": "017903dc1173484279e8029e5edee028cd81d1eb71c60e706b0476d7ea1d0e42",
45
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
42
+ "run_id": "38030208537",
43
+ "binary_sha256": "12a8a4b23da84cd672d03abe0c748310225e8bce47c5e8c8cbb3753e5acdbe57",
44
+ "observation_sha256": "cbfbaf744db2c79e4c71fd23903ff06b5284e7475b3f094a90711bb62eb6a39e",
45
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
46
46
  "native_cases": [
47
47
  "TestContextBoundedRender",
48
48
  "TestContextDocumentContract",
@@ -53,12 +53,12 @@
53
53
  ]
54
54
  },
55
55
  "darwin/arm64": {
56
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
56
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
57
57
  "workflow": ".github/workflows/ci.yml",
58
- "run_id": "37938394077",
59
- "binary_sha256": "b68192c7a1da2cd2f9031f71ab4c7e015673f060d6bfdfa3aa4b57d9f090bf34",
60
- "observation_sha256": "28682b5ece3e695125587ff8578d22ce5ccd75f6643f626b64246bc7dd664716",
61
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
58
+ "run_id": "38030208537",
59
+ "binary_sha256": "2107c247473c8a9cc7c422dd754d98fa6211cf7bec5b7ecdd85ba5d7db0676b0",
60
+ "observation_sha256": "426035459f63029ddd368a2a1a9dc542aeaebd920ae0ed993c6bbe6d5ecc1aa5",
61
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
62
62
  "native_cases": [
63
63
  "TestContextBoundedRender",
64
64
  "TestContextDocumentContract",
@@ -69,12 +69,12 @@
69
69
  ]
70
70
  },
71
71
  "linux/amd64": {
72
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
72
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
73
73
  "workflow": ".github/workflows/ci.yml",
74
- "run_id": "37938394077",
75
- "binary_sha256": "09582eabdef3f828a12de21b85ccc7b52a188651c2a4f69f3f776a2e62c86036",
76
- "observation_sha256": "0782dc40b8b03584b6f048204234fbf3896e0ee33ebfb52da4b72237d18679a6",
77
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
74
+ "run_id": "38030208537",
75
+ "binary_sha256": "92e27501fd18ae805c6390b17b4f2335e97d69c3645c60b3267fb7869c624727",
76
+ "observation_sha256": "50f326cc374cd2914c907ef1367e75dc4ac49ef3526cebfc220a08e9e0d9bac8",
77
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
78
78
  "native_cases": [
79
79
  "TestContextBoundedRender",
80
80
  "TestContextDocumentContract",
@@ -85,12 +85,12 @@
85
85
  ]
86
86
  },
87
87
  "linux/arm64": {
88
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
88
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
89
89
  "workflow": ".github/workflows/ci.yml",
90
- "run_id": "37938394077",
91
- "binary_sha256": "f7699ce8f2f07200ea8508f21a6d369506443392aa8897d84e9d5e7dd6469770",
92
- "observation_sha256": "451808d71946bed78727672d0c8ed94903eb9179a3907dd86248c1885eb7b094",
93
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
90
+ "run_id": "38030208537",
91
+ "binary_sha256": "1961df0bdf37fd6a7b3a6214b925cf9f3b2efe0e797c05151a43ee96d7df07b3",
92
+ "observation_sha256": "59a46860f93ed22094e9de20f7d2753cf361411d9e5230fcaabde95275cd7092",
93
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
94
94
  "native_cases": [
95
95
  "TestContextBoundedRender",
96
96
  "TestContextDocumentContract",
@@ -101,12 +101,12 @@
101
101
  ]
102
102
  },
103
103
  "windows/amd64": {
104
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
104
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
105
105
  "workflow": ".github/workflows/ci.yml",
106
- "run_id": "37938394077",
107
- "binary_sha256": "9a0f186e2a1bcfd92c8f9db5cb0aa2f6dfb128dd6f0dad2708a78596f0364e16",
108
- "observation_sha256": "336b9ea6f4b53b2aaa98cf5ee47f7d2792e2ece09eaafef8f37b0ae51c222275",
109
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
106
+ "run_id": "38030208537",
107
+ "binary_sha256": "63def27bda36ed03c9f7e6898eaf2110badda2419950a8dcb91666c4e4bdd438",
108
+ "observation_sha256": "ff372ee0e5f5bacc316909afc37c6b9b5442143385180dd7eb235eae725f25f5",
109
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
110
110
  "native_cases": [
111
111
  "TestContextBoundedRender",
112
112
  "TestContextDocumentContract",
@@ -117,12 +117,12 @@
117
117
  ]
118
118
  },
119
119
  "windows/arm64": {
120
- "source_commit": "6a243348a0e74b0a50c37eccf4d61520129a5c1c",
120
+ "source_commit": "ee70aa8851f2b96500e1b27085e3466ab222445d",
121
121
  "workflow": ".github/workflows/ci.yml",
122
- "run_id": "37938394077",
123
- "binary_sha256": "3f1bc7d00f9488b4a4a9f21e5ca414fd5c97031ad7b1c2b52c02f5d7f2956e3a",
124
- "observation_sha256": "817414c35d85c544d9554544af86fc14aa11f866f0df0f6fe28f64adda5bfe1a",
125
- "module_sha256": "421b4db5fa1afc9a8620c5538161d8b23f193d6a1042ad1c5aa004facdd77844",
122
+ "run_id": "38030208537",
123
+ "binary_sha256": "107e1a8fe971fe24ce8a274ce1188b15c9785e4f94b835dadde1918b8fed5c4b",
124
+ "observation_sha256": "c6761f9845ea9f51281ceb31118dc526a0496a57fa606807bf6118478f2906b4",
125
+ "module_sha256": "a7600f74a743626c4569da0da7803e057ed1df33d0fab8b0581bd25e45d402ed",
126
126
  "native_cases": [
127
127
  "TestContextBoundedRender",
128
128
  "TestContextDocumentContract",
@@ -82,6 +82,16 @@ REQUEST_LOCK_WAIT_SECONDS = 5.0
82
82
  CLAUDE_JOIN_LOCK_WAIT_SECONDS = 30.0
83
83
  MAX_OUTPUT = 8 << 20
84
84
  MAX_DECISION = 65536
85
+ # Current native completion reviews retain the complete immutable context by
86
+ # exact reference instead of duplicating it in every mutable request state.
87
+ CONTEXT_STORAGE = "frozen-reference/0.1.0"
88
+ CONTEXT_REFERENCE = {"format": "codearbiter.evidence-context-reference/0.1.0"}
89
+ # The native canonical decoder already bounds each complete context at 8 MiB.
90
+ MAX_EVIDENCE_CONTEXT = 8 << 20
91
+ # ASCII canonical JSON can expand each input UTF-8 byte to at most six bytes.
92
+ # Reserve that closed decision budget plus 32 bounded 256-byte lifecycle slots
93
+ # (host identities, content-addressed locators, their keys and delimiters).
94
+ REVIEW_RESULT_RESERVE = 6 * MAX_DECISION + 32 * 256
85
95
  MAX_COMPLETION_FILES = 16
86
96
  MAX_COMPLETION_FILE_BYTES = 64 << 10
87
97
  MAX_COMPLETION_TOTAL_BYTES = 256 << 10
@@ -404,9 +414,41 @@ def _request_lock(spool: Path, relative: Path, wait: float | None = None):
404
414
  # Do not unlink: a peer may already be waiting on this same inode.
405
415
 
406
416
 
417
+ def _referenced_review_state(value: dict[str, Any]) -> dict[str, Any]:
418
+ if (value.get("context_storage") != CONTEXT_STORAGE
419
+ or value.get("codex_review_profile") != CODEX_NATIVE_V1
420
+ or value.get("host", "codex") != "codex"
421
+ or value.get("activity") not in REVIEW_ACTIVITIES
422
+ or "completion" not in value["context"] or "handback" in value):
423
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "context reference is not a native completion review")
424
+ base = dict(value, state="ARMED", launch=None, observation_ref=None,
425
+ observation_sha256=None, receipt=None, recovery=None)
426
+ for field in ("payload", "authority_source"):
427
+ base.pop(field, None)
428
+ base["integrity_sha256"] = "0" * 64
429
+ stored_base = dict(base, context=CONTEXT_REFERENCE)
430
+ context = value["context"]
431
+ # Quality review additionally copies its exact task hashes into the result.
432
+ static_payload = {"input_sha256": context["input_sha256"],
433
+ "spec_sha256": context["spec_sha256"],
434
+ "completion_sha256": context["completion_sha256"]}
435
+ if value["activity"] == "spec_review":
436
+ static_payload["task_sha256"] = context["task_sha256"]
437
+ else:
438
+ static_payload.update(base_input_sha256=context["base_input_sha256"],
439
+ task_hashes=context["task_hashes"])
440
+ if len(_canonical(stored_base)) + len(_canonical(static_payload)) + REVIEW_RESULT_RESERVE > MAX_STATE:
441
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "review result has no bounded lifecycle reserve")
442
+ return dict(value, context=CONTEXT_REFERENCE)
443
+
444
+
407
445
  def _save(root: Path, value: dict[str, Any]) -> None:
408
446
  expected = value.get("integrity_sha256")
409
447
  updated = dict(value)
448
+ if "context_storage" in updated:
449
+ if _read_context(root, updated["context_ref"], updated["context_sha256"]) != updated["context"]:
450
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "stored review context changed")
451
+ updated = _referenced_review_state(updated)
410
452
  updated["integrity_sha256"] = _integrity(updated)
411
453
  legacy_abandonment = (
412
454
  value["state"] == "ABANDONED"
@@ -468,7 +510,7 @@ def _load(
468
510
  "authority_source", "dispatch_prompt", "review_contract_sha256",
469
511
  "required_coverage", "wrapper", "command_bindings", "recovery",
470
512
  "launch_envelope", "workspace_roots", "host", "codex_review_profile",
471
- "handback",
513
+ "handback", "context_storage",
472
514
  }
473
515
  if (
474
516
  not isinstance(value, dict)
@@ -496,6 +538,16 @@ def _load(
496
538
  or value["activity"] not in REVIEW_ACTIVITIES
497
539
  ):
498
540
  raise AuthorityError("INVALID_AUTHORITY_STATE", "Codex review profile is unsupported")
541
+ if "context_storage" in value:
542
+ if value["context"] != CONTEXT_REFERENCE:
543
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "stored context reference is malformed")
544
+ value["context"] = _read_context(root, value["context_ref"], value["context_sha256"])
545
+ subject = value["context"].get("subject", {})
546
+ _validate_context(value["context"], subject.get("artifact_id"),
547
+ subject.get("record_id"), value["activity"])
548
+ _referenced_review_state(value)
549
+ elif value["context"] == CONTEXT_REFERENCE:
550
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "context reference lacks its closed storage profile")
499
551
  if len(raw) > MAX_STATE:
500
552
  if recover_armed_review and value["state"] == "ABANDONED":
501
553
  # Only an abandonment can have retained this; recovering it again is
@@ -526,13 +578,20 @@ def _validate_hash(value: Any, field: str) -> str:
526
578
  return value
527
579
 
528
580
 
529
- def _read_context(root: Path, context_ref: str, context_hash: str) -> dict[str, Any]:
581
+ def _read_context(
582
+ root: Path, context_ref: str, context_hash: str
583
+ ) -> dict[str, Any]:
530
584
  _validate_hash(context_hash, "context_sha256")
531
585
  expected_ref = f".codearbiter/.artifacts/evidence-contexts/{context_hash}.json"
532
586
  if context_ref != expected_ref:
533
587
  raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "context locator is not content addressed")
534
588
  try:
535
- raw = (root / expected_ref).read_bytes()
589
+ path = root / expected_ref
590
+ _path_identity(path)
591
+ with path.open("rb") as stream:
592
+ raw = stream.read(MAX_EVIDENCE_CONTEXT + 1)
593
+ if len(raw) > MAX_EVIDENCE_CONTEXT:
594
+ raise ValueError("context exceeds the native canonical budget")
536
595
  context = json.loads(raw.decode("utf-8"))
537
596
  except (OSError, UnicodeError, ValueError) as exc:
538
597
  raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "context bytes are unavailable") from exc
@@ -1341,6 +1400,7 @@ def _dispatch_prompt(request: dict[str, Any], *, legacy_inline: bool = False) ->
1341
1400
  if request.get("codex_review_profile") == CODEX_NATIVE_V1 else ""
1342
1401
  )
1343
1402
  completion = ""
1403
+ completion_fields = ""
1344
1404
  if "completion" in context:
1345
1405
  completion = (
1346
1406
  "This explicit completion review assesses performed work against every selected task's "
@@ -1370,7 +1430,10 @@ def _dispatch_prompt(request: dict[str, Any], *, legacy_inline: bool = False) ->
1370
1430
  "that support each conclusion. Missing or unreadable facts require status=missing and "
1371
1431
  "decision=changes_requested. A passing decision requires every completion obligation "
1372
1432
  "substantiated; a claimed coverage list is insufficient.\n"
1433
+ "Separate required task/obligation pairs: "
1434
+ + json.dumps(sorted(_completion_obligations(context)), ensure_ascii=True) + ".\n"
1373
1435
  )
1436
+ completion_fields = ", completion_sha256 (exact selected packet hash), completion_assessment (separate obligation rows)"
1374
1437
  return (
1375
1438
  f"[CODEARBITER_AUTHORITY_REQUEST:{request['request_id']}]\n"
1376
1439
  f"Target repository: {request['repository']['path']}\n"
@@ -1384,7 +1447,8 @@ def _dispatch_prompt(request: dict[str, Any], *, legacy_inline: bool = False) ->
1384
1447
  + json.dumps(request["required_coverage"], ensure_ascii=True)
1385
1448
  + ". Fields: format, request_id, target_sha256, contract_sha256, decision "
1386
1449
  "(pass or changes_requested), coverage (unique strings), findings (objects with "
1387
- "severity, code, message), assessment (non-empty string). Reply with the JSON "
1450
+ "severity, code, message), assessment (non-empty string)"
1451
+ + completion_fields + ". Reply with the JSON "
1388
1452
  "object only: no code fence and no other text."
1389
1453
  )
1390
1454
 
@@ -1468,6 +1532,8 @@ def arm_request(
1468
1532
  seed_value["host"] = host
1469
1533
  if codex_review_profile is not None:
1470
1534
  seed_value["codex_review_profile"] = CODEX_NATIVE_V1
1535
+ if completion_selection is not None:
1536
+ seed_value["context_storage"] = CONTEXT_STORAGE
1471
1537
  seed = _canonical(seed_value)
1472
1538
  request_id = _digest(seed)
1473
1539
  request = {
@@ -1493,6 +1559,8 @@ def arm_request(
1493
1559
  request["host"] = host
1494
1560
  if codex_review_profile is not None:
1495
1561
  request["codex_review_profile"] = CODEX_NATIVE_V1
1562
+ if completion_selection is not None:
1563
+ request["context_storage"] = CONTEXT_STORAGE
1496
1564
  if activity in REVIEW_ACTIVITIES:
1497
1565
  request["review_contract_sha256"], request["required_coverage"] = _review_binding(context)
1498
1566
  request["dispatch_prompt"] = _dispatch_prompt(request)
@@ -2388,6 +2456,24 @@ def run_verification(
2388
2456
  request["context"], request["context_ref"], request["context_sha256"],
2389
2457
  ):
2390
2458
  raise AuthorityError("WORKSPACE_DRIFT", "repository content changed after arm")
2459
+ def normalized_workspace():
2460
+ result = client.call("evidence-context", {
2461
+ "artifact_id": request["context"]["subject"]["artifact_id"],
2462
+ "record_id": request["context"]["subject"]["record_id"],
2463
+ "activity": "verification",
2464
+ "verification_command_bindings": request["command_bindings"],
2465
+ })
2466
+ if (not isinstance(result, dict)
2467
+ or result.get("context_ref") != request["context_ref"]
2468
+ or result.get("context_sha256") != request["context_sha256"]
2469
+ or not isinstance(result.get("completion_workspace_after"), list)
2470
+ or not result["completion_workspace_after"]):
2471
+ raise AuthorityError("WORKSPACE_DRIFT", "engine completion closure is absent or changed context")
2472
+ return result["completion_workspace_after"]
2473
+
2474
+ # The engine alone normalizes validated native bookkeeping. Raw snapshots
2475
+ # still freeze every byte across the actual command execution interval.
2476
+ completion_workspace_before = normalized_workspace()
2391
2477
  workspace_before = _workspace_snapshots(request["command_bindings"])
2392
2478
  if workspace_before != wrapper.get("workspace_before"):
2393
2479
  raise AuthorityError("WORKSPACE_DRIFT", "workspace changed after wrapper authorization")
@@ -2422,6 +2508,9 @@ def run_verification(
2422
2508
  workspace_after = _workspace_snapshots(request["command_bindings"])
2423
2509
  if workspace_after != workspace_before:
2424
2510
  raise AuthorityError("WORKSPACE_DRIFT", "verification changed the frozen workspace")
2511
+ completion_workspace_after = normalized_workspace()
2512
+ if completion_workspace_after != completion_workspace_before:
2513
+ raise AuthorityError("WORKSPACE_DRIFT", "verification changed the normalized completion workspace")
2425
2514
  final_context, final_ref, final_hash = _context(
2426
2515
  root, client, request["context"]["subject"]["artifact_id"],
2427
2516
  request["context"]["subject"]["record_id"], "verification",
@@ -2435,6 +2524,7 @@ def run_verification(
2435
2524
  "command_bindings": request["command_bindings"],
2436
2525
  "workspace_before": workspace_before,
2437
2526
  "workspace_after": workspace_after,
2527
+ "completion_workspace_after": completion_workspace_after,
2438
2528
  "commands": commands,
2439
2529
  }
2440
2530
  payload = {
@@ -2444,7 +2534,7 @@ def run_verification(
2444
2534
  "commands": commands,
2445
2535
  }
2446
2536
  observation = _closed_observation(
2447
- request, payload, "declared-command/0.2.0", request["attempt"],
2537
+ request, payload, "declared-command/0.3.0", request["attempt"],
2448
2538
  producer_result,
2449
2539
  )
2450
2540
  _observation(root, request, observation)
@@ -11,7 +11,7 @@ import hostapi # noqa: E402
11
11
  class PiHost(hostapi.Host):
12
12
  name = "pi"
13
13
  adapter_name = "@arbiterforge/ca-pi"
14
- adapter_version = "0.17.4"
14
+ adapter_version = "0.17.5"
15
15
  update_target = "ca-pi"
16
16
  update_tag_prefix = "ca-pi-v"
17
17
  update_command = "pi update npm:@arbiterforge/ca-pi"
@@ -313,7 +313,7 @@ class Host:
313
313
 
314
314
  name = "claude"
315
315
  adapter_name = "ca"
316
- adapter_version = "2.25.3"
316
+ adapter_version = "2.25.4"
317
317
 
318
318
  # Update-notifier descriptor. Each independently versioned host overrides
319
319
  # these three values in its per-plugin _host.py. Keeping the target,
@@ -287,9 +287,11 @@ options. Local executables shadowing nested npm are rejected.
287
287
  Direct Node script entrypoints are also pinned. These launch-file bindings do
288
288
  not establish transitive dependency closure for deliberately excluded inputs.
289
289
 
290
- New observations use the closed `declared-command/0.2.0` producer profile to
291
- retain collector and launch-file identities. Historical `0.1.0` bindings remain
292
- separate and cannot be relabelled as qualified launch evidence.
290
+ New observations use the closed `declared-command/0.3.0` producer profile to
291
+ retain collector and launch-file identities plus an engine-produced normalized
292
+ completion closure. Raw workspace fingerprints must still match before and
293
+ after command execution. Historical `0.1.0` and `0.2.0` bindings retain their
294
+ original contracts and cannot be relabelled as newer evidence.
293
295
 
294
296
  For `spec_review` or `quality_review`, arm the corresponding activity without
295
297
  workspace mappings and dispatch the returned `launch_envelope` unchanged to one
@@ -332,10 +334,13 @@ acceptance. Scope review uses validated task completion bindings. If verificatio
332
334
  is rerun, obtain and record its completed task review before selecting that run
333
335
  for scope review; do not infer equivalence between receipts.
334
336
 
335
- Creating the first completion context recomputes the current raw worktree
336
- fingerprint and requires it to match the selected verifier's recorded fingerprint.
337
- Later freshness checks allow native task-status and execution bookkeeping updates
338
- in validated canonical artifacts while retaining their normative content hashes.
337
+ Creating a completion context for a `0.3.0` verification recomputes the normalized
338
+ worktree closure bound during that verification. Only validated native outputs
339
+ and execution bookkeeping are normalized; their publication must not invalidate
340
+ unchanged source. Historical `0.2.0` verification retains its initial exact raw
341
+ fingerprint comparison. Later freshness checks allow native task-status and
342
+ execution bookkeeping updates in validated canonical artifacts while retaining
343
+ their normative content hashes.
339
344
  Changes to task definitions, other HTML or other governance files still affect
340
345
  freshness under the normal snapshot policy. The closure covers
341
346
  tracked working-tree bytes and non-ignored untracked files, not ignored
@@ -349,6 +354,16 @@ the scope reaches `REVIEW`, reverify against one current source snapshot, run th
349
354
  combined quality review, and use `accept-scope` once. Do not accept tasks
350
355
  individually.
351
356
 
357
+ Current Codex native V1 completion reviews retain the full frozen context in
358
+ its immutable, content-addressed file and keep only its closed reference in
359
+ mutable request state. Loading validates the exact context locator, hash,
360
+ canonical bytes and review kind. The native context budget remains 8 MiB;
361
+ mutable request state remains bounded at 1 MiB. Before dispatch, the adapter
362
+ reserves the exact fixed result identities, six times the 64 KiB decision
363
+ budget for canonical JSON escaping, and 32 bounded 256-byte lifecycle slots.
364
+ A request without that capacity is refused before child launch. Historical
365
+ inline requests retain their existing limits and abandonment-only recovery.
366
+
352
367
  An ARMED review that never launched can be abandoned through the adapter:
353
368
 
354
369
  ```sh
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arbiterforge/ca-pi",
3
- "version": "0.17.4",
3
+ "version": "0.17.5",
4
4
  "private": true,
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",