@arbiterforge/ca-pi 0.14.10 → 0.14.16

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 (44) hide show
  1. package/README.md +33 -9
  2. package/package.json +2 -1
  3. package/plugins/ca-pi/CHANGELOG.md +67 -0
  4. package/plugins/ca-pi/LICENSE +661 -0
  5. package/plugins/ca-pi/SKILLS.md +2 -2
  6. package/plugins/ca-pi/SPRINT.md +47 -0
  7. package/plugins/ca-pi/THIRD_PARTY_NOTICES.md +40 -0
  8. package/plugins/ca-pi/generated/command-catalog.json +2 -2
  9. package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-amd64 +0 -0
  10. package/plugins/ca-pi/helpers/artifacts/ca-artifact-darwin-arm64 +0 -0
  11. package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-amd64 +0 -0
  12. package/plugins/ca-pi/helpers/artifacts/ca-artifact-linux-arm64 +0 -0
  13. package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-amd64.exe +0 -0
  14. package/plugins/ca-pi/helpers/artifacts/ca-artifact-windows-arm64.exe +0 -0
  15. package/plugins/ca-pi/helpers/artifacts/release.json +6 -6
  16. package/plugins/ca-pi/hooks/_approvallib.py +58 -22
  17. package/plugins/ca-pi/hooks/_artifactauthoritylib.py +2135 -0
  18. package/plugins/ca-pi/hooks/_artifactlib.py +164 -7
  19. package/plugins/ca-pi/hooks/_artifactpromptlib.py +177 -0
  20. package/plugins/ca-pi/hooks/_host.py +1 -1
  21. package/plugins/ca-pi/hooks/_overrideappendlib.py +5 -1
  22. package/plugins/ca-pi/hooks/_prerequisitelib.py +44 -22
  23. package/plugins/ca-pi/hooks/_reconciliationlib.py +472 -0
  24. package/plugins/ca-pi/hooks/_releaselib.py +345 -111
  25. package/plugins/ca-pi/hooks/_sprintapprovallib.py +302 -0
  26. package/plugins/ca-pi/hooks/artifact-authority-hook.py +127 -0
  27. package/plugins/ca-pi/hooks/artifact-authority.py +102 -0
  28. package/plugins/ca-pi/hooks/artifact-reconcile.py +57 -0
  29. package/plugins/ca-pi/hooks/hostapi.py +1 -1
  30. package/plugins/ca-pi/hooks/prompt-submit.py +20 -3
  31. package/plugins/ca-pi/hooks/releasehash.py +36 -23
  32. package/plugins/ca-pi/includes/artifacts.md +120 -13
  33. package/plugins/ca-pi/includes/sprint-authority.md +69 -0
  34. package/plugins/ca-pi/package.json +1 -1
  35. package/plugins/ca-pi/routines/INDEX.md +7 -4
  36. package/plugins/ca-pi/routines/brainstorming/SKILL.md +97 -29
  37. package/plugins/ca-pi/routines/commit-gate/SKILL.md +7 -1
  38. package/plugins/ca-pi/routines/executing-plans/SKILL.md +32 -15
  39. package/plugins/ca-pi/routines/release/SKILL.md +220 -70
  40. package/plugins/ca-pi/routines/skill-author/SKILL.md +26 -5
  41. package/plugins/ca-pi/routines/writing-plans/SKILL.md +22 -10
  42. package/plugins/ca-pi/skills/ca-commit/SKILL.md +170 -16
  43. package/plugins/ca-pi/skills/ca-new-skill/SKILL.md +116 -21
  44. package/plugins/ca-pi/skills/ca-release/SKILL.md +6 -4
@@ -0,0 +1,2135 @@
1
+ #!/usr/bin/env python3
2
+ # codeArbiter — durable closed authority producers for structured artifacts.
3
+ """Supervise verification and correlate independent Codex or Claude review evidence.
4
+
5
+ arm_request(...) -> dict
6
+ run_verification(...) -> dict
7
+ observe_codex_hook(...) -> dict
8
+ observe_claude_hook(...) -> dict
9
+ publish_request(...) -> dict
10
+
11
+ The artifact engine owns every target binding. Callers select only an activity
12
+ and record; they cannot supply an authority kind, verdict, evidence payload, or
13
+ reviewer identity. External work is journaled before launch, observations are
14
+ immutable and content-addressed, and replay never silently reruns a completed
15
+ attempt. Codex and Claude review correlation use stable hook fields and
16
+ deliberately ignore transcript bytes whose format is not a public contract.
17
+
18
+ Claude Code correlation (recorded Claude Code 2.1.281 payloads): a Bash or
19
+ Agent PreToolUse/PostToolUse pair shares session_id, prompt_id and tool_use_id;
20
+ the Agent PostToolUse tool_response carries the child's agentId; SubagentStart
21
+ and SubagentStop carry only agent_id and the parent's *current* prompt_id, so
22
+ child lifecycle events are bound by agent_id alone. One agent can emit more
23
+ than one SubagentStop; only the first is a review result.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import hashlib
29
+ import json
30
+ import os
31
+ from pathlib import Path
32
+ import re
33
+ import secrets
34
+ import shlex
35
+ import shutil
36
+ import stat
37
+ import subprocess
38
+ import tempfile
39
+ import threading
40
+ import time
41
+ from typing import Any
42
+
43
+ from _gitexec import git_executable, root_bound_git_env
44
+
45
+
46
+ OBSERVATION_DIR = Path(".codearbiter/.artifacts/observations")
47
+ SOURCE_DIR = Path(".codearbiter/.artifacts/authority-sources")
48
+ STATE_FORMAT = "codearbiter.authority-run/0.1.0"
49
+ OBSERVATION_FORMAT = "codearbiter.observation/0.2.0"
50
+ EVENT_FORMAT = "codearbiter.workflow-event/0.2.0"
51
+ DECISION_FORMAT = "codearbiter.review-decision/0.1.0"
52
+ ACTIVITIES = frozenset({"verification", "spec_review", "quality_review"})
53
+ REVIEW_ACTIVITIES = frozenset({"spec_review", "quality_review"})
54
+ STATES = frozenset({
55
+ "ARMED", "LAUNCHING", "LAUNCHED", "RUNNING", "COMPLETED", "REJECTED",
56
+ "FAILED", "ABANDONED", "CAPTURED",
57
+ })
58
+ TERMINAL_STATES = frozenset({"REJECTED", "FAILED", "ABANDONED", "CAPTURED"})
59
+ SHA256_RE = re.compile(r"[0-9a-f]{64}")
60
+ ID_RE = re.compile(r"[A-Z][A-Z0-9_-]{0,127}")
61
+ REQUEST_RE = re.compile(r"[0-9a-f]{64}")
62
+ TOKEN_RE = re.compile(r"[A-Za-z0-9_-]{12,128}")
63
+ HOST_ID_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9_.:-]{0,255}")
64
+ MAX_STATE = 1 << 20
65
+ MAX_OUTPUT = 8 << 20
66
+ MAX_DECISION = 65536
67
+ REGISTRY_PARENT = Path(tempfile.gettempdir())
68
+ HOSTS = frozenset({"codex", "claude"})
69
+ CLAUDE_REVIEWER = "ca:authority-reviewer"
70
+ CLAUDE_REVIEWER_MODELS = frozenset({"opus", "sonnet", "haiku"})
71
+ CLAUDE_REVIEW_PROFILE = "claude-review/0.1.0"
72
+ CODEX_REVIEW_PROFILE = "codex-review/0.1.0"
73
+ # None means the real ~/.claude/agents (plus CLAUDE_CONFIG_DIR/agents); tests
74
+ # point it at a fixture directory.
75
+ CLAUDE_USER_AGENT_DIR: Path | None = None
76
+ # Managed (organization policy) agent locations; their definitions outrank
77
+ # every other source.
78
+ CLAUDE_MANAGED_AGENT_DIRS: list[Path] = [
79
+ Path(os.environ.get("ProgramData", r"C:\ProgramData")) / "ClaudeCode" / "agents",
80
+ Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "ClaudeCode" / "agents",
81
+ ] if os.name == "nt" else [
82
+ Path("/Library/Application Support/ClaudeCode/agents"),
83
+ Path("/etc/claude-code/agents"),
84
+ ]
85
+
86
+
87
+ class AuthorityError(RuntimeError):
88
+ def __init__(self, code: str, message: str):
89
+ self.code = code
90
+ super().__init__(f"{code}: {message}")
91
+
92
+
93
+ def _canonical(value: Any) -> bytes:
94
+ try:
95
+ return json.dumps(
96
+ value, ensure_ascii=True, allow_nan=False, sort_keys=True,
97
+ separators=(",", ":"),
98
+ ).encode("utf-8")
99
+ except (TypeError, ValueError) as exc:
100
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "state is not finite JSON") from exc
101
+
102
+
103
+ def _digest(data: bytes) -> str:
104
+ return hashlib.sha256(data).hexdigest()
105
+
106
+
107
+ def _integrity(value: dict[str, Any]) -> str:
108
+ unsigned = dict(value)
109
+ unsigned.pop("integrity_sha256", None)
110
+ return _digest(_canonical(unsigned))
111
+
112
+
113
+ def _real_root(root: str | Path) -> Path:
114
+ try:
115
+ resolved = Path(root).resolve(strict=True)
116
+ info = resolved.lstat()
117
+ except OSError as exc:
118
+ raise AuthorityError("UNSAFE_REPOSITORY", "repository root is unavailable") from exc
119
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
120
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
121
+ raise AuthorityError("UNSAFE_REPOSITORY", "repository root must be a real directory")
122
+ return resolved
123
+
124
+
125
+ def _safe_directory(root: Path, relative: Path, *, create: bool) -> Path:
126
+ current = root
127
+ for part in relative.parts:
128
+ current = current / part
129
+ try:
130
+ info = current.lstat()
131
+ except FileNotFoundError:
132
+ if not create:
133
+ raise
134
+ current.mkdir()
135
+ info = current.lstat()
136
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
137
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
138
+ raise AuthorityError("UNSAFE_AUTHORITY_PATH", "authority directories must be real")
139
+ return current
140
+
141
+
142
+ def _atomic_replace(root: Path, relative: Path, data: bytes) -> None:
143
+ parent = _safe_directory(root, relative.parent, create=True)
144
+ temporary = parent / f".{relative.name}.{secrets.token_hex(8)}.tmp"
145
+ flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
146
+ if hasattr(os, "O_BINARY"):
147
+ flags |= os.O_BINARY
148
+ fd = os.open(temporary, flags, 0o600)
149
+ try:
150
+ view = memoryview(data)
151
+ while view:
152
+ written = os.write(fd, view)
153
+ if written <= 0:
154
+ raise OSError("short authority-state write")
155
+ view = view[written:]
156
+ os.fsync(fd)
157
+ finally:
158
+ os.close(fd)
159
+ try:
160
+ os.replace(temporary, root / relative)
161
+ finally:
162
+ try:
163
+ temporary.unlink()
164
+ except FileNotFoundError:
165
+ pass
166
+
167
+
168
+ def _publish_immutable(root: Path, relative: Path, data: bytes) -> None:
169
+ parent = _safe_directory(root, relative.parent, create=True)
170
+ target = parent / relative.name
171
+ temporary = parent / f".{relative.name}.{secrets.token_hex(8)}.tmp"
172
+ try:
173
+ flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
174
+ if hasattr(os, "O_BINARY"):
175
+ flags |= os.O_BINARY
176
+ fd = os.open(temporary, flags, 0o600)
177
+ view = memoryview(data)
178
+ while view:
179
+ written = os.write(fd, view)
180
+ if written <= 0:
181
+ raise OSError("short immutable observation write")
182
+ view = view[written:]
183
+ os.fsync(fd)
184
+ finally:
185
+ if 'fd' in locals():
186
+ os.close(fd)
187
+ try:
188
+ try:
189
+ os.link(temporary, target)
190
+ except FileExistsError:
191
+ try:
192
+ info = target.lstat()
193
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
194
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISREG(info.st_mode) or info.st_size != len(data):
195
+ raise OSError("unsafe immutable authority target")
196
+ flags = os.O_RDONLY | getattr(os, "O_BINARY", 0) | getattr(os, "O_NOFOLLOW", 0)
197
+ with os.fdopen(os.open(target, flags), "rb") as existing_file:
198
+ opened = os.fstat(existing_file.fileno())
199
+ if (
200
+ not stat.S_ISREG(opened.st_mode) or opened.st_size != len(data)
201
+ or (opened.st_dev, opened.st_ino) != (info.st_dev, info.st_ino)
202
+ ):
203
+ raise OSError("immutable authority target changed during read")
204
+ existing = existing_file.read(len(data) + 1)
205
+ after = target.lstat()
206
+ if (after.st_dev, after.st_ino) != (info.st_dev, info.st_ino):
207
+ raise OSError("immutable authority target changed during read")
208
+ except OSError as exc:
209
+ raise AuthorityError("UNSAFE_AUTHORITY_PATH", "immutable authority target is unsafe") from exc
210
+ if existing != data:
211
+ raise AuthorityError("AUTHORITY_COLLISION", "content-addressed bytes differ")
212
+ finally:
213
+ try:
214
+ temporary.unlink()
215
+ except FileNotFoundError:
216
+ pass
217
+
218
+
219
+ def _request_path(request_id: str) -> Path:
220
+ if not isinstance(request_id, str) or REQUEST_RE.fullmatch(request_id) is None:
221
+ raise AuthorityError("INVALID_REQUEST_ID", "request identity is malformed")
222
+ return Path(f"{request_id}.json")
223
+
224
+
225
+ def _spool_root(root: Path) -> Path:
226
+ try:
227
+ # Callers may supply an alias for the same repository (notably /var on
228
+ # macOS). Use the canonical root for both Git and the spool identity.
229
+ root = _real_root(root)
230
+ result = subprocess.run(
231
+ [git_executable(), "-C", str(root), "rev-parse", "--path-format=absolute", "--git-common-dir"],
232
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8",
233
+ errors="replace", timeout=5, check=False, env=root_bound_git_env(),
234
+ )
235
+ if result.returncode != 0 or not result.stdout.strip():
236
+ raise OSError("git common directory unavailable")
237
+ common = Path(result.stdout.strip()).resolve(strict=True)
238
+ info = common.lstat()
239
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
240
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
241
+ raise OSError("git common directory is unsafe")
242
+ worktree_id = _digest(_canonical(_repository_identity(root)))[:32]
243
+ spool = _safe_directory(
244
+ common, Path("codearbiter") / "authority-runs" / worktree_id, create=True
245
+ )
246
+ spool_info = spool.lstat()
247
+ spool_reparse = getattr(spool_info, "st_file_attributes", 0) & 0x400
248
+ if stat.S_ISLNK(spool_info.st_mode) or spool_reparse or not stat.S_ISDIR(spool_info.st_mode):
249
+ raise OSError("authority spool is unsafe")
250
+ return spool
251
+ except (OSError, subprocess.SubprocessError) as exc:
252
+ raise AuthorityError("AUTHORITY_BUSY", "resolved git-common authority spool is unavailable") from exc
253
+
254
+
255
+ def _save(root: Path, value: dict[str, Any]) -> None:
256
+ value = dict(value)
257
+ value["integrity_sha256"] = _integrity(value)
258
+ try:
259
+ _atomic_replace(_spool_root(root), _request_path(value["request_id"]), _canonical(value))
260
+ if value["state"] in TERMINAL_STATES:
261
+ (_registry_root() / f"{value['request_id']}.json").unlink(missing_ok=True)
262
+ except OSError as exc:
263
+ raise AuthorityError("AUTHORITY_BUSY", "request state could not be written") from exc
264
+
265
+
266
+ def _load(root: Path, request_id: str) -> dict[str, Any]:
267
+ path = _spool_root(root) / _request_path(request_id)
268
+ try:
269
+ info = path.lstat()
270
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
271
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISREG(info.st_mode):
272
+ raise OSError("not regular")
273
+ if info.st_size > MAX_STATE:
274
+ raise OSError("oversized")
275
+ value = json.loads(path.read_text(encoding="utf-8"))
276
+ except (OSError, UnicodeError, ValueError) as exc:
277
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "request state is unreadable") from exc
278
+ allowed = {
279
+ "format", "request_id", "state", "activity", "repository", "context",
280
+ "context_ref", "context_sha256", "attempt", "launch", "observation_ref",
281
+ "observation_sha256", "receipt", "integrity_sha256", "payload",
282
+ "authority_source", "dispatch_prompt", "review_contract_sha256",
283
+ "required_coverage", "wrapper", "command_bindings", "recovery",
284
+ "launch_envelope", "workspace_roots", "host",
285
+ }
286
+ if (
287
+ not isinstance(value, dict)
288
+ or set(value) - allowed
289
+ or value.get("format") != STATE_FORMAT
290
+ or value.get("request_id") != request_id
291
+ or value.get("activity") not in ACTIVITIES
292
+ or value.get("state") not in STATES
293
+ or value.get("host", "codex") not in HOSTS
294
+ or not isinstance(value.get("context"), dict)
295
+ or not isinstance(value.get("repository"), dict)
296
+ or not isinstance(value.get("command_bindings", []), list)
297
+ or not isinstance(value.get("workspace_roots", {}), dict)
298
+ or any(not isinstance(key, str) or not isinstance(path, str)
299
+ for key, path in value.get("workspace_roots", {}).items())
300
+ or value.get("integrity_sha256") != _integrity(value)
301
+ or not isinstance(value.get("context_ref"), str)
302
+ or SHA256_RE.fullmatch(value.get("context_sha256", "")) is None
303
+ ):
304
+ raise AuthorityError("INVALID_AUTHORITY_STATE", "request state failed validation")
305
+ return value
306
+
307
+
308
+ def _validate_hash(value: Any, field: str) -> str:
309
+ if not isinstance(value, str) or SHA256_RE.fullmatch(value) is None:
310
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", f"{field} is malformed")
311
+ return value
312
+
313
+
314
+ def _context(
315
+ root: Path, client: Any, artifact_id: str, record_id: str, activity: str
316
+ ) -> tuple[dict[str, Any], str, str]:
317
+ result = client.call("evidence-context", {
318
+ "artifact_id": artifact_id, "record_id": record_id, "activity": activity,
319
+ })
320
+ if not isinstance(result, dict):
321
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "engine context result is malformed")
322
+ context_hash = _validate_hash(result.get("context_sha256"), "context_sha256")
323
+ context_ref = result.get("context_ref")
324
+ expected_ref = f".codearbiter/.artifacts/evidence-contexts/{context_hash}.json"
325
+ if context_ref != expected_ref:
326
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "context locator is not content addressed")
327
+ try:
328
+ raw = (root / expected_ref).read_bytes()
329
+ context = json.loads(raw.decode("utf-8"))
330
+ except (OSError, UnicodeError, ValueError) as exc:
331
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "context bytes are unavailable") from exc
332
+ if _digest(raw) != context_hash or raw != _canonical(context):
333
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "context bytes changed or are not canonical")
334
+ subject = context.get("subject") if isinstance(context, dict) else None
335
+ if (
336
+ not isinstance(context, dict)
337
+ or context.get("format") != "codearbiter.evidence-context/0.1.0"
338
+ or not isinstance(subject, dict)
339
+ or subject.get("artifact_id") != artifact_id
340
+ or subject.get("record_id") != record_id
341
+ or context["activity"] != activity
342
+ or not ID_RE.fullmatch(artifact_id)
343
+ or not ID_RE.fullmatch(record_id)
344
+ ):
345
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "engine context changed selection")
346
+ for field in ("input_sha256", "spec_sha256", "plan_sha256"):
347
+ _validate_hash(context.get(field), field)
348
+ _validate_hash(subject.get("normative_sha256"), "normative_sha256")
349
+ if activity in {"verification", "spec_review"}:
350
+ _validate_hash(context.get("task_sha256"), "task_sha256")
351
+ if activity == "verification":
352
+ commands = context.get("commands")
353
+ if not isinstance(commands, list) or not commands:
354
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "verification has no commands")
355
+ for command in commands:
356
+ definition = command.get("definition") if isinstance(command, dict) else None
357
+ if (
358
+ not isinstance(command, dict)
359
+ or set(command) != {"definition_sha256", "definition"}
360
+ or not isinstance(definition, dict)
361
+ or not {"argv", "cwd", "expected_exit", "required_tests"} <= set(definition)
362
+ or not isinstance(definition.get("argv"), list)
363
+ or not definition.get("argv")
364
+ or any(not isinstance(item, str) or not item for item in definition.get("argv", []))
365
+ or not isinstance(definition.get("cwd"), str)
366
+ or not definition.get("cwd")
367
+ or type(definition.get("expected_exit")) is not int
368
+ or not 0 <= definition.get("expected_exit", -1) <= 255
369
+ or not isinstance(definition.get("required_tests"), list)
370
+ or any(not isinstance(item, str) or not item for item in definition.get("required_tests", []))
371
+ or len(set(definition.get("required_tests", []))) != len(definition.get("required_tests", []))
372
+ ):
373
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "command definition is malformed")
374
+ _validate_hash(command["definition_sha256"], "definition_sha256")
375
+ elif activity == "spec_review":
376
+ if not isinstance(context.get("task"), dict):
377
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "review task is absent")
378
+ else:
379
+ _validate_hash(context.get("base_input_sha256"), "base_input_sha256")
380
+ if not isinstance(context.get("task_hashes"), dict) or not isinstance(context.get("tasks"), list):
381
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "quality-review scope is incomplete")
382
+ return context, context_ref, context_hash
383
+
384
+
385
+ def _review_binding(context: dict[str, Any]) -> tuple[str, list[str]]:
386
+ contract = {
387
+ "format": DECISION_FORMAT,
388
+ "decision": ["pass", "changes_requested"],
389
+ "finding_severity": ["BLOCK", "WARN", "INFO"],
390
+ "required_fields": [
391
+ "format", "request_id", "target_sha256", "contract_sha256",
392
+ "decision", "coverage", "findings", "assessment",
393
+ ],
394
+ }
395
+ records = [context["task"]] if context["activity"] == "spec_review" else context["tasks"]
396
+ coverage = sorted({
397
+ ref for record in records for ref in record.get("criterion_refs", [])
398
+ if isinstance(ref, str) and ref
399
+ })
400
+ if not coverage:
401
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "review target has no criterion coverage")
402
+ return _digest(_canonical(contract)), coverage
403
+
404
+
405
+ def _repository_identity(root: Path) -> dict[str, str]:
406
+ info = os.stat(root)
407
+ return {
408
+ "path": str(root),
409
+ "filesystem_id": f"{int(getattr(info, 'st_dev', 0))}:{int(getattr(info, 'st_ino', 0))}",
410
+ }
411
+
412
+
413
+ def _registry_root() -> Path:
414
+ namespace = f"uid-{os.getuid()}" if hasattr(os, "getuid") else "current-user"
415
+ root = REGISTRY_PARENT.resolve(strict=True) / f"codearbiter-authority-{namespace}"
416
+ try:
417
+ root.mkdir(mode=0o700, exist_ok=True)
418
+ info = root.lstat()
419
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
420
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
421
+ raise OSError("unsafe registry")
422
+ if hasattr(os, "getuid"):
423
+ if info.st_uid != os.getuid():
424
+ raise OSError("foreign registry")
425
+ os.chmod(root, 0o700)
426
+ except OSError as exc:
427
+ raise AuthorityError("AUTHORITY_BUSY", "authority registry is unavailable") from exc
428
+ return root
429
+
430
+
431
+ def _register_request(root: Path, request: dict[str, Any]) -> None:
432
+ pointer = {
433
+ "format": "codearbiter.authority-pointer/0.1.0",
434
+ "request_id": request["request_id"],
435
+ "repository": request["repository"],
436
+ }
437
+ pointer["integrity_sha256"] = _integrity(pointer)
438
+ registry = _registry_root()
439
+ target = registry / f"{request['request_id']}.json"
440
+ data = _canonical(pointer)
441
+ try:
442
+ existing = target.read_bytes()
443
+ except FileNotFoundError:
444
+ flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
445
+ if hasattr(os, "O_BINARY"):
446
+ flags |= os.O_BINARY
447
+ fd = os.open(target, flags, 0o600)
448
+ try:
449
+ view = memoryview(data)
450
+ while view:
451
+ written = os.write(fd, view)
452
+ if written <= 0:
453
+ raise OSError("short authority-pointer write")
454
+ view = view[written:]
455
+ os.fsync(fd)
456
+ finally:
457
+ os.close(fd)
458
+ else:
459
+ if existing != data:
460
+ raise AuthorityError("AUTHORITY_COLLISION", "request registry entry differs")
461
+
462
+
463
+ def _registered_requests(strict: bool = False) -> list[tuple[Path, dict[str, Any]]]:
464
+ """Live registered requests. Strict callers refuse, rather than skip, a
465
+ request whose pointer or state exists but cannot be read."""
466
+ results = []
467
+ for path in _registry_root().glob("*.json"):
468
+ try:
469
+ raw = path.read_bytes()
470
+ if len(raw) > 16384:
471
+ continue
472
+ pointer = json.loads(raw.decode("utf-8"))
473
+ repository = pointer.get("repository") if isinstance(pointer, dict) else None
474
+ if (
475
+ not isinstance(pointer, dict)
476
+ or pointer.get("format") != "codearbiter.authority-pointer/0.1.0"
477
+ or pointer.get("request_id") != path.stem
478
+ or pointer.get("integrity_sha256") != _integrity(pointer)
479
+ or not isinstance(repository, dict)
480
+ ):
481
+ continue
482
+ root = _real_root(repository.get("path"))
483
+ if _repository_identity(root) != repository:
484
+ continue
485
+ request = _load(root, path.stem)
486
+ if request["state"] in TERMINAL_STATES:
487
+ path.unlink(missing_ok=True)
488
+ continue
489
+ results.append((root, request))
490
+ except (AuthorityError, OSError, UnicodeError, ValueError) as exc:
491
+ unreadable = (
492
+ exc.code == "INVALID_AUTHORITY_STATE"
493
+ if isinstance(exc, AuthorityError) else REQUEST_RE.fullmatch(path.stem) is not None
494
+ )
495
+ cause = exc.__cause__ if isinstance(exc, AuthorityError) else exc
496
+ if strict and unreadable and not isinstance(cause, FileNotFoundError):
497
+ raise AuthorityError(
498
+ "AUTHORITY_BUSY",
499
+ f"authority request {path} is unreadable; remove it if no review is running",
500
+ ) from exc
501
+ continue
502
+ return results
503
+
504
+
505
+ def _registered_request(request_id: str) -> tuple[Path, dict[str, Any]]:
506
+ matches = [item for item in _registered_requests() if item[1]["request_id"] == request_id]
507
+ if len(matches) != 1:
508
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "authority request routing is ambiguous")
509
+ return matches[0]
510
+
511
+
512
+ def _claude_start_marker(agent_id: str) -> Path:
513
+ key = _digest(_canonical({"host": "claude", "agent_id": agent_id}))
514
+ return _registry_root() / f"claude-start-{key}.json"
515
+
516
+
517
+ def _claude_agent_dirs(root: Path, sessions: tuple[Path, ...] = ()) -> list[Path]:
518
+ """Every agent directory whose definitions outrank a plugin agent.
519
+
520
+ A session opened outside the artifact repository loads project agents
521
+ from its own directory, so the observing session roots are scanned too.
522
+ """
523
+ directories = [root / ".claude" / "agents"]
524
+ directories.extend(Path(session) / ".claude" / "agents" for session in sessions)
525
+ try:
526
+ common = Path(_git_text(root, "rev-parse", "--path-format=absolute", "--git-common-dir"))
527
+ directories.append(common.parent / ".claude" / "agents")
528
+ except AuthorityError:
529
+ pass
530
+ if CLAUDE_USER_AGENT_DIR is not None:
531
+ directories.append(CLAUDE_USER_AGENT_DIR)
532
+ else:
533
+ directories.append(Path.home() / ".claude" / "agents")
534
+ configured = os.environ.get("CLAUDE_CONFIG_DIR")
535
+ if configured:
536
+ directories.append(Path(configured) / "agents")
537
+ directories.extend(CLAUDE_MANAGED_AGENT_DIRS)
538
+ return directories
539
+
540
+
541
+ def _raise_walk_error(exc: OSError) -> None:
542
+ raise exc
543
+
544
+
545
+ def _refuse_shadowed_reviewer(root: Path, *sessions: Path) -> None:
546
+ """Project, user and managed agents outrank plugin agents; refuse any shadow.
547
+
548
+ Fail closed rather than parse YAML: a definition shadows the reviewer when
549
+ its file name, or anything in its front matter, names the reviewer in any
550
+ case. A description merely mentioning the name is a false positive the
551
+ error message explains; a missed shadow would let a parent-authored agent
552
+ grade its own work.
553
+ """
554
+ short = CLAUDE_REVIEWER.split(":", 1)[1].casefold()
555
+ for directory in _claude_agent_dirs(root, sessions):
556
+ candidates = []
557
+ try:
558
+ if directory.is_dir():
559
+ for base, dirs, files in os.walk(directory, onerror=_raise_walk_error, followlinks=False):
560
+ for name in dirs:
561
+ # A linked subdirectory is not walked, so it cannot be cleared.
562
+ info = (Path(base) / name).lstat()
563
+ if stat.S_ISLNK(info.st_mode) or getattr(info, "st_file_attributes", 0) & 0x400:
564
+ raise AuthorityError(
565
+ "SHADOWED_REVIEWER", f"{Path(base) / name} is a link that cannot be inspected",
566
+ )
567
+ candidates.extend(Path(base) / name for name in files if name.casefold().endswith(".md"))
568
+ except OSError as exc:
569
+ raise AuthorityError("SHADOWED_REVIEWER", f"agent definitions under {directory} cannot be inspected") from exc
570
+ for candidate in candidates:
571
+ if short in candidate.stem.casefold():
572
+ raise AuthorityError("SHADOWED_REVIEWER", f"{candidate} shadows {CLAUDE_REVIEWER}")
573
+ try:
574
+ # A linked definition is followed, but only to a regular file:
575
+ # a pipe or device would hang the hook.
576
+ if not stat.S_ISREG(os.stat(candidate).st_mode):
577
+ raise AuthorityError("SHADOWED_REVIEWER", f"{candidate} is not a regular file")
578
+ with candidate.open("rb") as stream:
579
+ raw = stream.read(1 << 20)
580
+ except OSError as exc:
581
+ raise AuthorityError("SHADOWED_REVIEWER", "agent definition is unreadable") from exc
582
+ text = raw.decode("utf-8", errors="replace")
583
+ front = text
584
+ match = re.match(r"\A?\s*---[^\n]*\n(.*?)^---", text, re.S | re.M)
585
+ if match:
586
+ front = match.group(1)
587
+ if short in front.casefold():
588
+ raise AuthorityError("SHADOWED_REVIEWER", f"{candidate} shadows {CLAUDE_REVIEWER}")
589
+
590
+
591
+ def _ordinary_spawn_marker(session_id: str, turn_id: str) -> Path:
592
+ key = _digest(_canonical({"session_id": session_id, "turn_id": turn_id}))
593
+ return _registry_root() / f"ordinary-spawn-{key}.marker"
594
+
595
+
596
+ def _record_ordinary_spawn(session_id: str, turn_id: str) -> None:
597
+ marker = _ordinary_spawn_marker(session_id, turn_id)
598
+ try:
599
+ fd = os.open(marker, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
600
+ except FileExistsError:
601
+ return
602
+ try:
603
+ os.write(fd, b"ordinary spawn observed\n")
604
+ os.fsync(fd)
605
+ finally:
606
+ os.close(fd)
607
+
608
+
609
+ def _reject_overlapping_authority(session_id: str, turn_id: str) -> None:
610
+ for root, request in _registered_requests():
611
+ launch = request.get("launch") or {}
612
+ if (
613
+ request["state"] in {"LAUNCHING", "RUNNING"}
614
+ and launch.get("parent_session_id") == session_id
615
+ and launch.get("parent_turn_id") == turn_id
616
+ ):
617
+ request["state"] = "REJECTED"
618
+ request["recovery"] = {
619
+ "mode": "overlapping-subagent-launch",
620
+ "rerun_permitted": False,
621
+ }
622
+ _save(root, request)
623
+
624
+
625
+ def _git_text(directory: Path, *args: str) -> str:
626
+ try:
627
+ result = subprocess.run(
628
+ [git_executable(), "-C", str(directory), *args],
629
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False,
630
+ timeout=15, env=root_bound_git_env(),
631
+ )
632
+ except (OSError, subprocess.SubprocessError) as exc:
633
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "git workspace identity is unavailable") from exc
634
+ if result.returncode != 0:
635
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "git workspace identity is unavailable")
636
+ decoded = result.stdout.decode("utf-8", "strict")
637
+ return decoded if "-z" in args else decoded.strip()
638
+
639
+
640
+ def _path_identity(path: Path) -> str:
641
+ info = path.lstat()
642
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
643
+ if stat.S_ISLNK(info.st_mode) or reparse:
644
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace path is replaceable indirection")
645
+ return f"{int(getattr(info, 'st_dev', 0))}:{int(getattr(info, 'st_ino', 0))}"
646
+
647
+
648
+ def _file_sha256(path: Path) -> str:
649
+ digest = hashlib.sha256()
650
+ try:
651
+ with path.open("rb") as stream:
652
+ while True:
653
+ block = stream.read(1 << 20)
654
+ if not block:
655
+ break
656
+ digest.update(block)
657
+ except OSError as exc:
658
+ raise AuthorityError("UNSUPPORTED_EXECUTABLE", "declared executable is unreadable") from exc
659
+ return digest.hexdigest()
660
+
661
+
662
+ def _workspace_for(
663
+ root: Path, label: str, workspace_roots: dict[str, str]
664
+ ) -> tuple[Path, Path, Path]:
665
+ if label in workspace_roots:
666
+ cwd = _real_root(workspace_roots[label])
667
+ declared_top = _real_root(_git_text(cwd, "rev-parse", "--show-toplevel"))
668
+ if declared_top != cwd:
669
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "mapped workspace is not an exact Git worktree root")
670
+ elif label in {".", "current worktree", "candidate worktree"}:
671
+ cwd = root
672
+ else:
673
+ candidate = Path(label)
674
+ if candidate.is_absolute() or ".." in candidate.parts:
675
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "declared cwd escapes the artifact worktree")
676
+ cwd = _resolved_directory(root / candidate)
677
+ worktree = _real_root(_git_text(cwd, "rev-parse", "--show-toplevel"))
678
+ if label not in workspace_roots and worktree != root:
679
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "declared cwd is not in the artifact worktree")
680
+ common = _real_root(_git_text(worktree, "rev-parse", "--path-format=absolute", "--git-common-dir"))
681
+ artifact_common = _real_root(_git_text(root, "rev-parse", "--path-format=absolute", "--git-common-dir"))
682
+ if common != artifact_common:
683
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace does not share the artifact git-common-dir")
684
+ return cwd, worktree, common
685
+
686
+
687
+ def _resolve_executable(name: str, cwd: Path) -> Path:
688
+ candidate = Path(name)
689
+ if candidate.is_absolute() or candidate.parent != Path("."):
690
+ path = (cwd / candidate).resolve(strict=True) if not candidate.is_absolute() else candidate.resolve(strict=True)
691
+ else:
692
+ located = shutil.which(name, path=os.environ.get("PATH", ""))
693
+ if not located:
694
+ raise AuthorityError("UNSUPPORTED_EXECUTABLE", "declared executable is not resolvable")
695
+ path = Path(located).resolve(strict=True)
696
+ if not path.is_file():
697
+ raise AuthorityError("UNSUPPORTED_EXECUTABLE", "declared executable is not a regular file")
698
+ _path_identity(path)
699
+ return path
700
+
701
+
702
+ def _bind_commands(
703
+ root: Path, context: dict[str, Any], workspace_roots: dict[str, str]
704
+ ) -> list[dict[str, Any]]:
705
+ bindings = []
706
+ for command in context["commands"]:
707
+ definition = command["definition"]
708
+ cwd, worktree, common = _workspace_for(root, definition["cwd"], workspace_roots)
709
+ executable = _resolve_executable(definition["argv"][0], cwd)
710
+ bindings.append({
711
+ "definition_sha256": command["definition_sha256"],
712
+ "argv": [str(executable), *definition["argv"][1:]],
713
+ "cwd": str(cwd),
714
+ "cwd_filesystem_id": _path_identity(cwd),
715
+ "workspace_root": str(worktree),
716
+ "workspace_filesystem_id": _path_identity(worktree),
717
+ "git_common_dir": str(common),
718
+ "git_common_filesystem_id": _path_identity(common),
719
+ "executable_sha256": _file_sha256(executable),
720
+ })
721
+ return bindings
722
+
723
+
724
+ def _workspace_snapshots(bindings: list[dict[str, Any]]) -> list[dict[str, str]]:
725
+ unique: dict[str, dict[str, str]] = {}
726
+ for binding in bindings:
727
+ cwd = _resolved_directory(binding["cwd"])
728
+ root = _real_root(binding["workspace_root"])
729
+ common = _real_root(binding["git_common_dir"])
730
+ if (
731
+ _path_identity(cwd) != binding["cwd_filesystem_id"]
732
+ or _path_identity(root) != binding["workspace_filesystem_id"]
733
+ or _path_identity(common) != binding["git_common_filesystem_id"]
734
+ or _file_sha256(Path(binding["argv"][0])) != binding["executable_sha256"]
735
+ ):
736
+ raise AuthorityError("WORKSPACE_DRIFT", "workspace or executable identity changed")
737
+ status = _git_text(root, "status", "--porcelain=v2", "-z", "--untracked-files=all")
738
+ index = _git_text(root, "ls-files", "--stage", "-z")
739
+ untracked = _git_text(root, "ls-files", "--others", "--exclude-standard", "-z")
740
+ entries: dict[str, str] = {}
741
+ for record in (part for part in index.split("\0") if part):
742
+ try:
743
+ metadata, relative = record.split("\t", 1)
744
+ mode, _object_id, stage = metadata.split(" ")
745
+ except ValueError as exc:
746
+ raise AuthorityError("WORKSPACE_DRIFT", "git index entry cannot be frozen") from exc
747
+ if stage != "0" or mode not in {"100644", "100755", "120000", "160000"} or relative in entries:
748
+ raise AuthorityError("WORKSPACE_DRIFT", "git index entry cannot be frozen")
749
+ entries[relative] = mode
750
+ for relative in (part for part in untracked.split("\0") if part):
751
+ if relative in entries:
752
+ raise AuthorityError("WORKSPACE_DRIFT", "git workspace entry cannot be frozen")
753
+ entries[relative] = "untracked"
754
+ content = hashlib.sha256()
755
+ for relative in sorted(entries):
756
+ encoded = relative.encode("utf-8")
757
+ candidate = root / relative
758
+ try:
759
+ if not candidate.parent.resolve(strict=False).is_relative_to(root):
760
+ raise OSError("workspace member escapes the worktree")
761
+ mode = entries[relative]
762
+ try:
763
+ info = candidate.lstat()
764
+ except FileNotFoundError:
765
+ if mode == "untracked":
766
+ raise
767
+ kind, data = "deleted", b""
768
+ else:
769
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
770
+ if stat.S_ISLNK(info.st_mode):
771
+ if mode not in {"120000", "untracked"}:
772
+ raise OSError("regular workspace member became a symlink")
773
+ resolved = candidate.resolve(strict=False)
774
+ if not resolved.is_relative_to(root):
775
+ raise OSError("workspace symlink escapes the worktree")
776
+ target = os.fsencode(os.readlink(candidate))
777
+ resolved_path = resolved.relative_to(root).as_posix().encode("utf-8")
778
+ try:
779
+ target_info = resolved.lstat()
780
+ except FileNotFoundError:
781
+ kind, data = "dangling-symlink", target + b"\0" + resolved_path
782
+ else:
783
+ target_reparse = getattr(target_info, "st_file_attributes", 0) & 0x400
784
+ if target_reparse or not stat.S_ISREG(target_info.st_mode):
785
+ raise OSError("workspace symlink target has unsupported type")
786
+ kind, data = "symlink", target + b"\0" + resolved_path + b"\0" + resolved.read_bytes()
787
+ elif reparse:
788
+ raise OSError("workspace member is replaceable indirection")
789
+ elif stat.S_ISREG(info.st_mode) and mode != "160000":
790
+ kind = "materialized-symlink" if mode == "120000" else "file"
791
+ data = candidate.read_bytes()
792
+ elif stat.S_ISDIR(info.st_mode) and mode == "160000":
793
+ nested_top = _git_text(candidate, "rev-parse", "--show-toplevel")
794
+ if _real_root(nested_top) != candidate:
795
+ if any(candidate.iterdir()):
796
+ raise OSError("uninitialized gitlink has unexpected content")
797
+ kind, data = "uninitialized-gitlink", b""
798
+ else:
799
+ if _git_text(candidate, "status", "--porcelain", "--untracked-files=all"):
800
+ raise OSError("dirty gitlink cannot be frozen")
801
+ kind, data = "gitlink", _git_text(candidate, "rev-parse", "HEAD").encode("ascii")
802
+ else:
803
+ raise OSError("workspace member has unsupported type")
804
+ except (OSError, RuntimeError, AuthorityError) as exc:
805
+ raise AuthorityError("WORKSPACE_DRIFT", "workspace content cannot be frozen") from exc
806
+ content.update(len(encoded).to_bytes(8, "big"))
807
+ content.update(encoded)
808
+ typed = f"{mode}:{kind}".encode("ascii")
809
+ content.update(len(typed).to_bytes(8, "big"))
810
+ content.update(typed)
811
+ content.update(len(data).to_bytes(8, "big"))
812
+ content.update(data)
813
+ unique[str(root)] = {
814
+ "root": str(root),
815
+ "filesystem_id": binding["workspace_filesystem_id"],
816
+ "git_common_dir": str(common),
817
+ "git_common_filesystem_id": binding["git_common_filesystem_id"],
818
+ "head": _git_text(root, "rev-parse", "HEAD"),
819
+ "status_sha256": _digest(status.encode("utf-8")),
820
+ "content_sha256": content.hexdigest(),
821
+ }
822
+ return [unique[key] for key in sorted(unique)]
823
+
824
+
825
+ def _dispatch_prompt(request: dict[str, Any]) -> str:
826
+ context = request["context"]
827
+ return (
828
+ f"[CODEARBITER_AUTHORITY_REQUEST:{request['request_id']}]\n"
829
+ f"Target repository: {request['repository']['path']}\n"
830
+ f"Frozen context: {request['context_ref']} sha256={request['context_sha256']}\n"
831
+ "Frozen target data follows as canonical JSON:\n"
832
+ + _canonical(context).decode("ascii") + "\n"
833
+ "Act as a fresh read-only independent codeArbiter reviewer. Do not edit files or "
834
+ "delegate. Review only the frozen target and return exactly one JSON object using "
835
+ f"format {DECISION_FORMAT}. Bind request_id={request['request_id']}, "
836
+ f"target_sha256={context['input_sha256']}, "
837
+ f"contract_sha256={request['review_contract_sha256']}. Required coverage: "
838
+ + json.dumps(request["required_coverage"], ensure_ascii=True)
839
+ + ". Fields: format, request_id, target_sha256, contract_sha256, decision "
840
+ "(pass or changes_requested), coverage (unique strings), findings (objects with "
841
+ "severity, code, message), assessment (non-empty string). Reply with the JSON "
842
+ "object only: no code fence and no other text."
843
+ )
844
+
845
+
846
+ def arm_request(
847
+ root: str | Path,
848
+ client: Any,
849
+ artifact_id: str,
850
+ record_id: str,
851
+ activity: str,
852
+ *,
853
+ request_nonce: str | None = None,
854
+ workspace_roots: dict[str, str | Path] | None = None,
855
+ host: str = "codex",
856
+ reviewer_model: str = "opus",
857
+ **unexpected: Any,
858
+ ) -> dict[str, Any]:
859
+ if unexpected:
860
+ raise AuthorityError(
861
+ "INVALID_AUTHORITY_REQUEST",
862
+ "authority, verdict, payload, and observations are not caller inputs",
863
+ )
864
+ if activity not in ACTIVITIES:
865
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "activity is unsupported")
866
+ if host not in HOSTS:
867
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "host is unsupported")
868
+ if host == "claude" and reviewer_model not in CLAUDE_REVIEWER_MODELS:
869
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "reviewer model is unsupported")
870
+ root = _real_root(root)
871
+ if host == "claude" and activity in REVIEW_ACTIVITIES:
872
+ _refuse_shadowed_reviewer(root)
873
+ nonce = request_nonce or secrets.token_urlsafe(24)
874
+ if not isinstance(nonce, str) or TOKEN_RE.fullmatch(nonce) is None:
875
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "request nonce is malformed")
876
+ context, context_ref, context_sha256 = _context(
877
+ root, client, artifact_id, record_id, activity
878
+ )
879
+ frozen_workspaces: dict[str, str] = {}
880
+ if workspace_roots is not None:
881
+ if activity != "verification" or not isinstance(workspace_roots, dict):
882
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "workspace roots apply only to verification")
883
+ labels = {command["definition"]["cwd"] for command in context["commands"]}
884
+ if set(workspace_roots) != labels:
885
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace map must exactly cover declared cwd labels")
886
+ frozen_workspaces = {label: str(_real_root(path)) for label, path in workspace_roots.items()}
887
+ command_bindings = _bind_commands(root, context, frozen_workspaces) if activity == "verification" else []
888
+ seed_value = {
889
+ "repository": _repository_identity(root), "context": context, "nonce": nonce,
890
+ "command_bindings": command_bindings,
891
+ "workspace_roots": frozen_workspaces,
892
+ }
893
+ if host != "codex":
894
+ seed_value["host"] = host
895
+ seed = _canonical(seed_value)
896
+ request_id = _digest(seed)
897
+ request = {
898
+ "format": STATE_FORMAT,
899
+ "request_id": request_id,
900
+ "state": "ARMED",
901
+ "activity": activity,
902
+ "repository": _repository_identity(root),
903
+ "context": context,
904
+ "context_ref": context_ref,
905
+ "context_sha256": context_sha256,
906
+ "attempt": None,
907
+ "launch": None,
908
+ "observation_ref": None,
909
+ "observation_sha256": None,
910
+ "receipt": None,
911
+ "wrapper": None,
912
+ "recovery": None,
913
+ "command_bindings": command_bindings,
914
+ "workspace_roots": frozen_workspaces,
915
+ }
916
+ if host != "codex":
917
+ request["host"] = host
918
+ if activity in REVIEW_ACTIVITIES:
919
+ request["review_contract_sha256"], request["required_coverage"] = _review_binding(context)
920
+ request["dispatch_prompt"] = _dispatch_prompt(request)
921
+ if host == "claude":
922
+ request["launch_envelope"] = {
923
+ "description": f"codeArbiter {activity} {request_id[:12]}",
924
+ "prompt": request["dispatch_prompt"],
925
+ "subagent_type": CLAUDE_REVIEWER,
926
+ "model": reviewer_model,
927
+ }
928
+ else:
929
+ request["launch_envelope"] = {
930
+ "message": request["dispatch_prompt"],
931
+ "task_name": f"authority_{request_id[:12]}",
932
+ "fork_turns": "none",
933
+ }
934
+ _save(root, request)
935
+ _register_request(root, request)
936
+ result = {
937
+ "request_id": request_id,
938
+ "request_path": str(_spool_root(root) / _request_path(request_id)),
939
+ "activity": activity,
940
+ }
941
+ if activity in REVIEW_ACTIVITIES:
942
+ result["dispatch_prompt"] = request["dispatch_prompt"]
943
+ result["review_contract_sha256"] = request["review_contract_sha256"]
944
+ result["required_coverage"] = request["required_coverage"]
945
+ result["launch_envelope"] = request["launch_envelope"]
946
+ return result
947
+
948
+
949
+ def _bounded_output(value: Any) -> bytes:
950
+ if not isinstance(value, (bytes, bytearray)):
951
+ raise AuthorityError("INVALID_PROCESS_RESULT", "process output must be bytes")
952
+ if len(value) > MAX_OUTPUT:
953
+ raise AuthorityError("PROCESS_OUTPUT_TOO_LARGE", "process output exceeds 8 MiB")
954
+ return bytes(value)
955
+
956
+
957
+ def _unittest_collector(stdout: bytes, stderr: bytes, required: list[str]) -> list[dict[str, str]]:
958
+ text = (stdout + b"\n" + stderr).decode("utf-8", "replace")
959
+ results = []
960
+ for name in required:
961
+ pattern = re.compile(r"(?m)^" + re.escape(name) + r"(?:\s+\([^\r\n]*\))?\s+\.\.\.\s+ok\s*$")
962
+ matches = pattern.findall(text)
963
+ if not matches:
964
+ raise AuthorityError("MISSING_TEST_RESULT", f"required test did not pass: {name}")
965
+ if len(matches) != 1:
966
+ raise AuthorityError("DUPLICATE_TEST_RESULT", f"required test appeared more than once: {name}")
967
+ results.append({"name": name, "status": "pass"})
968
+ return results
969
+
970
+
971
+ def _named_line_collector(stdout: bytes, stderr: bytes, required: list[str]) -> list[dict[str, str]]:
972
+ # Intentional producer gap: current SingedTerra movement, walls, and
973
+ # fall-damage harnesses emit umbrella summaries for some plan aggregates.
974
+ # Those summaries are not semantic evidence; only exact PASS names qualify.
975
+ text = (stdout + b"\n" + stderr).decode("utf-8", "replace")
976
+ passed: dict[str, int] = {}
977
+ for line in text.splitlines():
978
+ stripped = line.strip()
979
+ if stripped.startswith("PASS: "):
980
+ name = stripped[6:].rstrip(".")
981
+ passed[name] = passed.get(name, 0) + 1
982
+ duplicates = [name for name in required if passed.get(name, 0) > 1]
983
+ if duplicates:
984
+ raise AuthorityError("DUPLICATE_TEST_RESULT", "required PASS lines are duplicated: " + ", ".join(duplicates))
985
+ missing = [name for name in required if passed.get(name, 0) != 1]
986
+ if missing:
987
+ raise AuthorityError(
988
+ "MISSING_TEST_RESULT", "required explicit PASS lines are absent: " + ", ".join(missing)
989
+ )
990
+ return [{"name": name, "status": "pass"} for name in required]
991
+
992
+
993
+ def _vitest_verbose_collector(stdout: bytes, stderr: bytes, required: list[str]) -> list[dict[str, str]]:
994
+ text = (stdout + b"\n" + stderr).decode("utf-8", "replace")
995
+ passed: dict[str, int] = {}
996
+ for line in text.splitlines():
997
+ stripped = line.strip()
998
+ if stripped.startswith(("✓ ", "√ ")):
999
+ name = stripped[2:].rsplit(" > ", 1)[-1]
1000
+ name = re.sub(r"\s+\d+(?:\.\d+)?m?s$", "", name)
1001
+ passed[name] = passed.get(name, 0) + 1
1002
+ duplicates = [name for name in required if passed.get(name, 0) > 1]
1003
+ if duplicates:
1004
+ raise AuthorityError("DUPLICATE_TEST_RESULT", "required Vitest cases are duplicated: " + ", ".join(duplicates))
1005
+ missing = [name for name in required if passed.get(name, 0) != 1]
1006
+ if missing:
1007
+ raise AuthorityError(
1008
+ "MISSING_TEST_RESULT", "required exact Vitest case names are absent: " + ", ".join(missing)
1009
+ )
1010
+ return [{"name": name, "status": "pass"} for name in required]
1011
+
1012
+
1013
+ def _exit_only_collector(_stdout: bytes, _stderr: bytes, required: list[str]) -> list[dict[str, str]]:
1014
+ if required:
1015
+ raise AuthorityError("UNSUPPORTED_COLLECTOR", "exit-only profile cannot attest named tests")
1016
+ return []
1017
+
1018
+
1019
+ COLLECTORS: dict[str, Callable[[bytes, bytes, list[str]], list[dict[str, str]]]] = {
1020
+ "python-unittest-text/0.1.0": _unittest_collector,
1021
+ "codearbiter-named-lines/0.1.0": _named_line_collector,
1022
+ "vitest-verbose/0.1.0": _vitest_verbose_collector,
1023
+ "exit-only/0.1.0": _exit_only_collector,
1024
+ }
1025
+
1026
+
1027
+ def _collector_profile(argv: list[str], required: list[str]) -> str:
1028
+ if not required:
1029
+ return "exit-only/0.1.0"
1030
+ lowered = [part.casefold() for part in argv]
1031
+ if len(lowered) >= 3 and lowered[1:3] == ["-m", "unittest"]:
1032
+ return "python-unittest-text/0.1.0"
1033
+ if "vitest" in lowered and "--reporter=verbose" in lowered:
1034
+ return "vitest-verbose/0.1.0"
1035
+ if "tsx" in lowered or lowered[:3] == ["npm", "run", "test:client"] or lowered[:3] == ["npm", "run", "check"]:
1036
+ return "codearbiter-named-lines/0.1.0"
1037
+ raise AuthorityError("UNSUPPORTED_COLLECTOR", "declared runner has no qualified collector")
1038
+
1039
+
1040
+ def _minimal_environment() -> tuple[dict[str, str], str]:
1041
+ names = (
1042
+ "PATH", "PATHEXT", "SystemRoot", "WINDIR", "COMSPEC", "TEMP", "TMP",
1043
+ "HOME", "USERPROFILE", "APPDATA", "LOCALAPPDATA", "LANG", "LC_ALL",
1044
+ )
1045
+ environment = {name: os.environ[name] for name in names if name in os.environ}
1046
+ return environment, _digest(_canonical(environment))
1047
+
1048
+
1049
+ def _resolved_directory(value: Any) -> Path:
1050
+ if not isinstance(value, (str, Path)):
1051
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace resolver returned no directory")
1052
+ try:
1053
+ path = Path(value).resolve(strict=True)
1054
+ info = path.lstat()
1055
+ except OSError as exc:
1056
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace directory is unavailable") from exc
1057
+ reparse = getattr(info, "st_file_attributes", 0) & 0x400
1058
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
1059
+ raise AuthorityError("UNSUPPORTED_WORKSPACE", "workspace must be a real directory")
1060
+ return path
1061
+
1062
+
1063
+ def _run_contained(
1064
+ argv: list[str], *, cwd: str, env: dict[str, str], timeout_seconds: float = 1800.0
1065
+ ) -> subprocess.CompletedProcess:
1066
+ """Bound output and descendants with POSIX sessions or a Windows Job Object."""
1067
+ if not isinstance(timeout_seconds, (int, float)) or timeout_seconds <= 0:
1068
+ raise AuthorityError("INVALID_PROCESS_TIMEOUT", "process timeout must be positive")
1069
+ job = None
1070
+ if os.name == "nt":
1071
+ import ctypes
1072
+ from ctypes import wintypes
1073
+
1074
+ class BasicLimits(ctypes.Structure):
1075
+ _fields_ = [
1076
+ ("PerProcessUserTimeLimit", ctypes.c_longlong),
1077
+ ("PerJobUserTimeLimit", ctypes.c_longlong),
1078
+ ("LimitFlags", wintypes.DWORD),
1079
+ ("MinimumWorkingSetSize", ctypes.c_size_t),
1080
+ ("MaximumWorkingSetSize", ctypes.c_size_t),
1081
+ ("ActiveProcessLimit", wintypes.DWORD),
1082
+ ("Affinity", ctypes.c_size_t),
1083
+ ("PriorityClass", wintypes.DWORD),
1084
+ ("SchedulingClass", wintypes.DWORD),
1085
+ ]
1086
+
1087
+ class IoCounters(ctypes.Structure):
1088
+ _fields_ = [(name, ctypes.c_ulonglong) for name in (
1089
+ "ReadOperationCount", "WriteOperationCount", "OtherOperationCount",
1090
+ "ReadTransferCount", "WriteTransferCount", "OtherTransferCount",
1091
+ )]
1092
+
1093
+ class ExtendedLimits(ctypes.Structure):
1094
+ _fields_ = [
1095
+ ("BasicLimitInformation", BasicLimits), ("IoInfo", IoCounters),
1096
+ ("ProcessMemoryLimit", ctypes.c_size_t), ("JobMemoryLimit", ctypes.c_size_t),
1097
+ ("PeakProcessMemoryUsed", ctypes.c_size_t), ("PeakJobMemoryUsed", ctypes.c_size_t),
1098
+ ]
1099
+
1100
+ kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
1101
+ ntdll = ctypes.WinDLL("ntdll")
1102
+ kernel32.CreateJobObjectW.restype = wintypes.HANDLE
1103
+ kernel32.CreateJobObjectW.argtypes = [ctypes.c_void_p, wintypes.LPCWSTR]
1104
+ kernel32.SetInformationJobObject.argtypes = [wintypes.HANDLE, ctypes.c_int, ctypes.c_void_p, wintypes.DWORD]
1105
+ kernel32.AssignProcessToJobObject.argtypes = [wintypes.HANDLE, wintypes.HANDLE]
1106
+ kernel32.TerminateJobObject.argtypes = [wintypes.HANDLE, wintypes.UINT]
1107
+ kernel32.CloseHandle.argtypes = [wintypes.HANDLE]
1108
+ ntdll.NtResumeProcess.argtypes = [wintypes.HANDLE]
1109
+ job = kernel32.CreateJobObjectW(None, None)
1110
+ if not job:
1111
+ raise AuthorityError("UNSUPPORTED_PROCESS_CONTAINMENT", "CreateJobObjectW failed")
1112
+ limits = ExtendedLimits()
1113
+ limits.BasicLimitInformation.LimitFlags = 0x00002000 # KILL_ON_JOB_CLOSE
1114
+ if not kernel32.SetInformationJobObject(job, 9, ctypes.byref(limits), ctypes.sizeof(limits)):
1115
+ kernel32.CloseHandle(job)
1116
+ raise AuthorityError("UNSUPPORTED_PROCESS_CONTAINMENT", "job limits could not be installed")
1117
+ try:
1118
+ process = subprocess.Popen(
1119
+ argv, cwd=cwd, env=env, stdin=subprocess.DEVNULL,
1120
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False,
1121
+ creationflags=0x00000200 | 0x00000004, # NEW_PROCESS_GROUP | SUSPENDED
1122
+ )
1123
+ if not kernel32.AssignProcessToJobObject(job, wintypes.HANDLE(int(process._handle))):
1124
+ process.kill()
1125
+ process.wait()
1126
+ raise AuthorityError("UNSUPPORTED_PROCESS_CONTAINMENT", "child could not enter Job Object")
1127
+ if ntdll.NtResumeProcess(wintypes.HANDLE(int(process._handle))) != 0:
1128
+ kernel32.TerminateJobObject(job, 1)
1129
+ process.wait()
1130
+ raise AuthorityError("UNSUPPORTED_PROCESS_CONTAINMENT", "suspended child could not resume")
1131
+ except Exception:
1132
+ kernel32.CloseHandle(job)
1133
+ raise
1134
+ else:
1135
+ process = subprocess.Popen(
1136
+ argv, cwd=cwd, env=env, stdin=subprocess.DEVNULL,
1137
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False,
1138
+ start_new_session=True,
1139
+ )
1140
+ buffers = {"stdout": bytearray(), "stderr": bytearray()}
1141
+ overflow = threading.Event()
1142
+
1143
+ def drain(name: str, stream: Any) -> None:
1144
+ while True:
1145
+ chunk = stream.read(65536)
1146
+ if not chunk:
1147
+ return
1148
+ if len(buffers[name]) + len(chunk) > MAX_OUTPUT:
1149
+ overflow.set()
1150
+ else:
1151
+ buffers[name].extend(chunk)
1152
+
1153
+ threads = [
1154
+ threading.Thread(target=drain, args=("stdout", process.stdout), daemon=True),
1155
+ threading.Thread(target=drain, args=("stderr", process.stderr), daemon=True),
1156
+ ]
1157
+ for thread in threads:
1158
+ thread.start()
1159
+ deadline = time.monotonic() + timeout_seconds
1160
+ try:
1161
+ while process.poll() is None:
1162
+ if overflow.is_set() or time.monotonic() >= deadline:
1163
+ if os.name == "nt":
1164
+ kernel32.TerminateJobObject(job, 1)
1165
+ else:
1166
+ import signal
1167
+ os.killpg(process.pid, signal.SIGKILL)
1168
+ process.wait(timeout=10)
1169
+ if overflow.is_set():
1170
+ raise AuthorityError("PROCESS_OUTPUT_TOO_LARGE", "process output exceeds 8 MiB")
1171
+ raise AuthorityError("VERIFICATION_PROCESS_FAILED", "verification process timed out")
1172
+ time.sleep(0.02)
1173
+ finally:
1174
+ if job is not None:
1175
+ kernel32.CloseHandle(job) # KILL_ON_JOB_CLOSE ends surviving descendants.
1176
+ job = None
1177
+ elif process.poll() is not None:
1178
+ try:
1179
+ import signal
1180
+ os.killpg(process.pid, signal.SIGKILL)
1181
+ except (OSError, ProcessLookupError):
1182
+ pass
1183
+ for thread in threads:
1184
+ thread.join(timeout=10)
1185
+ process.stdout.close()
1186
+ process.stderr.close()
1187
+ if overflow.is_set():
1188
+ raise AuthorityError("PROCESS_OUTPUT_TOO_LARGE", "process output exceeds 8 MiB")
1189
+ return subprocess.CompletedProcess(argv, process.returncode, bytes(buffers["stdout"]), bytes(buffers["stderr"]))
1190
+
1191
+
1192
+ def _observation(root: Path, request: dict[str, Any], value: dict[str, Any]) -> None:
1193
+ raw = _canonical(value)
1194
+ digest = _digest(raw)
1195
+ relative = OBSERVATION_DIR / f"{digest}.json"
1196
+ _publish_immutable(root, relative, raw)
1197
+ request["observation_ref"] = relative.as_posix()
1198
+ request["observation_sha256"] = digest
1199
+
1200
+
1201
+ def _closed_observation(
1202
+ request: dict[str, Any], payload: dict[str, Any], producer_profile: str,
1203
+ producer_run_id: str, producer_result: dict[str, Any],
1204
+ ) -> dict[str, Any]:
1205
+ return {
1206
+ "format": OBSERVATION_FORMAT,
1207
+ "kind": request["activity"],
1208
+ "subject": request["context"]["subject"],
1209
+ "context_ref": request["context_ref"],
1210
+ "context_sha256": request["context_sha256"],
1211
+ "payload_sha256": _digest(_canonical(payload)),
1212
+ "producer_profile": producer_profile,
1213
+ "producer_run_id": producer_run_id,
1214
+ "producer_result": producer_result,
1215
+ "producer_result_sha256": _digest(_canonical(producer_result)),
1216
+ }
1217
+
1218
+
1219
+ def capture_user_prompt(
1220
+ root: str | Path, client: Any, event: dict[str, Any], *, host: str, session_id: str
1221
+ ) -> dict[str, Any]:
1222
+ """Capture one exact host UserPromptSubmit event through a closed observation."""
1223
+ root = _real_root(root)
1224
+ if (
1225
+ not isinstance(event, dict)
1226
+ or event.get("kind") not in {"approval", "prerequisite", "reconciliation", "farm_authorization"}
1227
+ or event.get("authority_kind") != "user_workflow"
1228
+ or not isinstance(event.get("subject"), dict)
1229
+ or not isinstance(event.get("source_text"), str)
1230
+ or not event["source_text"]
1231
+ ):
1232
+ raise AuthorityError("INVALID_PROMPT_EVENT", "user prompt event is malformed")
1233
+ producer_run_id = f"{_host_id(host, 'host')}:{_host_id(session_id, 'session_id')}"
1234
+ prompt_sha256 = _digest(event["source_text"].encode("utf-8"))
1235
+ subject = event["subject"]
1236
+ result = client.call("evidence-context", {
1237
+ "artifact_id": subject.get("artifact_id"),
1238
+ "record_id": subject.get("record_id"),
1239
+ "activity": event["kind"],
1240
+ "prompt_sha256": prompt_sha256,
1241
+ })
1242
+ if not isinstance(result, dict):
1243
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "prompt context result is malformed")
1244
+ context_ref = result.get("context_ref")
1245
+ context_sha256 = _validate_hash(result.get("context_sha256"), "context_sha256")
1246
+ if context_ref != f".codearbiter/.artifacts/evidence-contexts/{context_sha256}.json":
1247
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "prompt context is not content addressed")
1248
+ try:
1249
+ context_raw = (root / context_ref).read_bytes()
1250
+ context = json.loads(context_raw.decode("utf-8"))
1251
+ except (OSError, UnicodeError, ValueError) as exc:
1252
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "prompt context is unavailable") from exc
1253
+ if (
1254
+ _digest(context_raw) != context_sha256
1255
+ or context_raw != _canonical(context)
1256
+ or context.get("activity") != event["kind"]
1257
+ or context.get("subject") != subject
1258
+ or context.get("prompt_sha256") != prompt_sha256
1259
+ ):
1260
+ raise AuthorityError("INVALID_EVIDENCE_CONTEXT", "prompt context changed its authority binding")
1261
+ producer_result = {"host": host, "session_id": session_id, "prompt_sha256": prompt_sha256}
1262
+ observation = {
1263
+ "format": OBSERVATION_FORMAT,
1264
+ "kind": event["kind"],
1265
+ "subject": subject,
1266
+ "context_ref": context_ref,
1267
+ "context_sha256": context_sha256,
1268
+ "payload_sha256": _digest(_canonical(event.get("payload"))),
1269
+ "producer_profile": "host-user-prompt/0.1.0",
1270
+ "producer_run_id": producer_run_id,
1271
+ "producer_result": producer_result,
1272
+ "producer_result_sha256": _digest(_canonical(producer_result)),
1273
+ }
1274
+ observation_raw = _canonical(observation)
1275
+ observation_sha256 = _digest(observation_raw)
1276
+ observation_ref = OBSERVATION_DIR / f"{observation_sha256}.json"
1277
+ _publish_immutable(root, observation_ref, observation_raw)
1278
+ current_event = dict(event)
1279
+ current_event["format"] = EVENT_FORMAT
1280
+ current_event["observation_ref"] = observation_ref.as_posix()
1281
+ current_event["observation_sha256"] = observation_sha256
1282
+ event_raw = _canonical(current_event)
1283
+ event_sha256 = _digest(event_raw)
1284
+ source_ref = SOURCE_DIR / f"{event_sha256}.json"
1285
+ _publish_immutable(root, source_ref, event_raw)
1286
+ captured = client.call("capture-observation", {
1287
+ "source_ref": source_ref.as_posix(), "source_sha256": event_sha256,
1288
+ })
1289
+ if not isinstance(captured, dict) or not isinstance(captured.get("receipt"), str):
1290
+ raise AuthorityError("INVALID_RECEIPT", "observed prompt capture returned no receipt")
1291
+ return {
1292
+ **captured, "authority_source": source_ref.as_posix(),
1293
+ "observation_ref": observation_ref.as_posix(),
1294
+ }
1295
+
1296
+
1297
+ def run_verification(
1298
+ root: str | Path,
1299
+ client: Any,
1300
+ request_id: str,
1301
+ ) -> dict[str, Any]:
1302
+ root = _real_root(root)
1303
+ request = _load(root, request_id)
1304
+ if request["activity"] != "verification":
1305
+ raise AuthorityError("INVALID_AUTHORITY_REQUEST", "request is not verification")
1306
+ if request["state"] == "COMPLETED":
1307
+ # Marked so Claude corroboration, which binds evidence to the
1308
+ # observed call, can tell a replay from the run it authorized.
1309
+ return {
1310
+ "request_id": request_id, "state": "COMPLETED",
1311
+ "commands": request["payload"]["commands"], "replayed": True,
1312
+ }
1313
+ if request["state"] != "ARMED":
1314
+ raise AuthorityError("INTERRUPTED_ATTEMPT", "verification attempt cannot be rerun")
1315
+ wrapper = request.get("wrapper")
1316
+ if not isinstance(wrapper, dict) or wrapper.get("state") != "AUTHORIZED":
1317
+ raise AuthorityError(
1318
+ "UNAUTHORIZED_VERIFIER",
1319
+ "verification requires a correlated PreToolUse authorization",
1320
+ )
1321
+ if _bind_commands(root, request["context"], request["workspace_roots"]) != request["command_bindings"]:
1322
+ raise AuthorityError("WORKSPACE_DRIFT", "effective argv or workspace changed after arm")
1323
+ fresh_context, fresh_ref, fresh_hash = _context(
1324
+ root, client, request["context"]["subject"]["artifact_id"],
1325
+ request["context"]["subject"]["record_id"], "verification",
1326
+ )
1327
+ if (fresh_context, fresh_ref, fresh_hash) != (
1328
+ request["context"], request["context_ref"], request["context_sha256"],
1329
+ ):
1330
+ raise AuthorityError("WORKSPACE_DRIFT", "repository content changed after arm")
1331
+ workspace_before = _workspace_snapshots(request["command_bindings"])
1332
+ if workspace_before != wrapper.get("workspace_before"):
1333
+ raise AuthorityError("WORKSPACE_DRIFT", "workspace changed after wrapper authorization")
1334
+
1335
+ environment, environment_sha256 = _minimal_environment()
1336
+ request["state"] = "RUNNING"
1337
+ request["attempt"] = secrets.token_hex(16)
1338
+ _save(root, request)
1339
+ commands = []
1340
+ for command, binding in zip(request["context"]["commands"], request["command_bindings"]):
1341
+ definition = command["definition"]
1342
+ collector = COLLECTORS[_collector_profile(definition["argv"], definition["required_tests"])]
1343
+ cwd = _resolved_directory(binding["cwd"])
1344
+ try:
1345
+ completed = _run_contained(list(binding["argv"]), cwd=str(cwd), env=environment)
1346
+ except (OSError, subprocess.SubprocessError) as exc:
1347
+ raise AuthorityError("VERIFICATION_PROCESS_FAILED", "verification process did not complete") from exc
1348
+ stdout = _bounded_output(completed.stdout)
1349
+ stderr = _bounded_output(completed.stderr)
1350
+ if type(completed.returncode) is not int or not 0 <= completed.returncode <= 255:
1351
+ raise AuthorityError("INVALID_PROCESS_RESULT", "process exit is invalid")
1352
+ if completed.returncode != definition["expected_exit"]:
1353
+ raise AuthorityError("FAILED_VERIFICATION", "process exit differs from approved definition")
1354
+ tests = collector(stdout, stderr, list(definition["required_tests"]))
1355
+ commands.append({
1356
+ "definition_sha256": command["definition_sha256"],
1357
+ "exit": completed.returncode,
1358
+ "tests": tests,
1359
+ "stdout_sha256": _digest(stdout),
1360
+ "stderr_sha256": _digest(stderr),
1361
+ })
1362
+ workspace_after = _workspace_snapshots(request["command_bindings"])
1363
+ if workspace_after != workspace_before:
1364
+ raise AuthorityError("WORKSPACE_DRIFT", "verification changed the frozen workspace")
1365
+ final_context, final_ref, final_hash = _context(
1366
+ root, client, request["context"]["subject"]["artifact_id"],
1367
+ request["context"]["subject"]["record_id"], "verification",
1368
+ )
1369
+ if (final_context, final_ref, final_hash) != (
1370
+ request["context"], request["context_ref"], request["context_sha256"],
1371
+ ):
1372
+ raise AuthorityError("WORKSPACE_DRIFT", "verification changed repository content")
1373
+ producer_result = {
1374
+ "environment_sha256": environment_sha256,
1375
+ "command_bindings": request["command_bindings"],
1376
+ "workspace_before": workspace_before,
1377
+ "workspace_after": workspace_after,
1378
+ "commands": commands,
1379
+ }
1380
+ payload = {
1381
+ "input_sha256": request["context"]["input_sha256"],
1382
+ "spec_sha256": request["context"]["spec_sha256"],
1383
+ "task_sha256": request["context"]["task_sha256"],
1384
+ "commands": commands,
1385
+ }
1386
+ observation = _closed_observation(
1387
+ request, payload, "declared-command/0.1.0", request["attempt"],
1388
+ producer_result,
1389
+ )
1390
+ _observation(root, request, observation)
1391
+ request["payload"] = payload
1392
+ request["state"] = "COMPLETED"
1393
+ _save(root, request)
1394
+ return {"request_id": request_id, "state": "COMPLETED", "commands": commands}
1395
+
1396
+
1397
+ def _request_id_from_prompt(message: Any) -> str:
1398
+ if not isinstance(message, str):
1399
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "spawn message is absent")
1400
+ match = re.match(r"\[CODEARBITER_AUTHORITY_REQUEST:([0-9a-f]{64})\]\n", message)
1401
+ if match is None:
1402
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "spawn message has no authority request")
1403
+ return match.group(1)
1404
+
1405
+
1406
+ def _host_id(value: Any, field: str) -> str:
1407
+ if not isinstance(value, str) or HOST_ID_RE.fullmatch(value) is None:
1408
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", f"{field} is malformed")
1409
+ return value
1410
+
1411
+
1412
+ def _verification_selector(event: dict[str, Any]) -> tuple[str, Path, str] | None:
1413
+ """Recognize only the closed wrapper selector, never caller-authored child argv."""
1414
+ if event.get("tool_name") not in {
1415
+ "Bash", "shell_command", "exec_command", "unified_exec",
1416
+ }:
1417
+ return None
1418
+ tool_input = event.get("tool_input")
1419
+ if not isinstance(tool_input, dict):
1420
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "exec input is malformed")
1421
+ command = tool_input.get("command", tool_input.get("cmd"))
1422
+ if not isinstance(command, str):
1423
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "exec command is absent")
1424
+ compound = any(marker in command for marker in ("\n", "\r", ";", "&", "|", ">", "<", "`", "$"))
1425
+ try:
1426
+ tokens = [token.strip('"') for token in shlex.split(command, posix=False)]
1427
+ except ValueError as exc:
1428
+ # An ordinary command with unbalanced quoting is not ours to deny.
1429
+ if "artifact-authority" not in command.casefold():
1430
+ return None
1431
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier wrapper command is malformed") from exc
1432
+ wrapper_start = (
1433
+ len(tokens) >= 3
1434
+ and Path(tokens[0]).name.lower() in {
1435
+ "python", "python.exe", "python3", "python3.exe", "py", "py.exe",
1436
+ }
1437
+ and Path(tokens[1]).name.lower() == "artifact-authority.py"
1438
+ and tokens[2] == "verify"
1439
+ )
1440
+ if compound:
1441
+ if wrapper_start:
1442
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier wrapper command is compound")
1443
+ return None
1444
+ if len(tokens) != 7:
1445
+ return None
1446
+ if (
1447
+ Path(tokens[0]).name.lower() not in {
1448
+ "python", "python.exe", "python3", "python3.exe", "py", "py.exe",
1449
+ }
1450
+ or Path(tokens[1]).name.lower() != "artifact-authority.py"
1451
+ or tokens[2] != "verify"
1452
+ or tokens[3] != "--root"
1453
+ or tokens[5] != "--request-id"
1454
+ or REQUEST_RE.fullmatch(tokens[6]) is None
1455
+ ):
1456
+ return None
1457
+ return tokens[6], _real_root(tokens[4]), tokens[1]
1458
+
1459
+
1460
+ def observe_verifier_hook(
1461
+ invocation_root: str | Path, event: dict[str, Any], host: str = "codex",
1462
+ ) -> dict[str, Any] | None:
1463
+ """Authorize/corroborate the wrapper; native exit/output remain result evidence."""
1464
+ if host not in HOSTS:
1465
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier host is unsupported")
1466
+ events = {"PreToolUse", "PostToolUse"} | ({"PostToolUseFailure"} if host == "claude" else set())
1467
+ if not isinstance(event, dict) or event.get("hook_event_name") not in events:
1468
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier hook event is unsupported")
1469
+ selected = _verification_selector(event)
1470
+ if selected is None:
1471
+ return None
1472
+ # Only an authority call is ever refused for an unavailable invocation root.
1473
+ _real_root(invocation_root)
1474
+ request_id, selected_root, script = selected
1475
+ root, request = _registered_request(request_id)
1476
+ if host == "claude":
1477
+ shipped = (Path(__file__).resolve().parent / "artifact-authority.py").resolve()
1478
+ try:
1479
+ named = Path(script).resolve(strict=True)
1480
+ except OSError:
1481
+ named = None
1482
+ if named != shipped:
1483
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier wrapper is not the shipped artifact-authority.py")
1484
+ if (
1485
+ root != selected_root
1486
+ or request["activity"] != "verification"
1487
+ or request.get("host", "codex") != host
1488
+ ):
1489
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier target does not match its request")
1490
+ session_id = _host_id(event.get("session_id"), "session_id")
1491
+ # Codex names the parent turn turn_id; Claude Code names it prompt_id.
1492
+ turn_field = "prompt_id" if host == "claude" else "turn_id"
1493
+ turn_id = _host_id(event.get(turn_field), turn_field)
1494
+ tool_use_id = _host_id(event.get("tool_use_id"), "tool_use_id")
1495
+ if host == "claude" and event["hook_event_name"] == "PreToolUse":
1496
+ tool_input = event["tool_input"]
1497
+ # A background run returns no stdout to corroborate; an unsandboxed
1498
+ # run escapes the host boundary the evidence assumes.
1499
+ if tool_input.get("run_in_background") or tool_input.get("dangerouslyDisableSandbox"):
1500
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier wrapper must run in the foreground and sandbox")
1501
+ if set(tool_input) - {"command", "description", "timeout"}:
1502
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier wrapper input carries unexpected options")
1503
+ if event["hook_event_name"] == "PreToolUse":
1504
+ if request["state"] != "ARMED" or request.get("wrapper") is not None:
1505
+ raise AuthorityError("INTERRUPTED_ATTEMPT", "verifier wrapper is not armable")
1506
+ current_bindings = _bind_commands(root, request["context"], request["workspace_roots"])
1507
+ if current_bindings != request["command_bindings"]:
1508
+ raise AuthorityError("WORKSPACE_DRIFT", "effective child argv or cwd changed")
1509
+ for command in request["context"]["commands"]:
1510
+ definition = command["definition"]
1511
+ _collector_profile(definition["argv"], definition["required_tests"])
1512
+ workspace_before = _workspace_snapshots(current_bindings)
1513
+ request["wrapper"] = {
1514
+ "state": "AUTHORIZED", "session_id": session_id,
1515
+ turn_field: turn_id, "tool_use_id": tool_use_id,
1516
+ "command_bindings": current_bindings,
1517
+ "workspace_before": workspace_before,
1518
+ }
1519
+ _save(root, request)
1520
+ return {
1521
+ "request_id": request_id, "state": "AUTHORIZED",
1522
+ "command_bindings": current_bindings, "workspace_before": workspace_before,
1523
+ }
1524
+ wrapper = request.get("wrapper")
1525
+ if (
1526
+ not isinstance(wrapper, dict)
1527
+ or wrapper.get("session_id") != session_id
1528
+ or wrapper.get(turn_field) != turn_id
1529
+ or wrapper.get("tool_use_id") != tool_use_id
1530
+ ):
1531
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier completion is not correlated")
1532
+ if host == "claude":
1533
+ return _claude_verifier_result(root, request, wrapper, event)
1534
+ if request["state"] != "COMPLETED":
1535
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier completion is not correlated")
1536
+ response = event.get("tool_response")
1537
+ if isinstance(response, dict):
1538
+ if response.get("exit_code") != 0:
1539
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper did not report exit 0")
1540
+ elif isinstance(response, str):
1541
+ try:
1542
+ completed = json.loads(response) if len(response.encode("utf-8")) <= MAX_OUTPUT else None
1543
+ except ValueError:
1544
+ completed = None
1545
+ if (
1546
+ not isinstance(completed, dict)
1547
+ or completed.get("request_id") != request_id
1548
+ or completed.get("state") != "COMPLETED"
1549
+ ):
1550
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper output did not corroborate completion")
1551
+ else:
1552
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper result is unavailable")
1553
+ wrapper["state"] = "CORROBORATED"
1554
+ _save(root, request)
1555
+ return {"request_id": request_id, "state": "CORROBORATED"}
1556
+
1557
+
1558
+ def _claude_verifier_result(
1559
+ root: Path, request: dict[str, Any], wrapper: dict[str, Any], event: dict[str, Any]
1560
+ ) -> dict[str, Any]:
1561
+ """Claude reports no exit code: success and failure are distinct events."""
1562
+ request_id = request["request_id"]
1563
+ if wrapper.get("state") != "AUTHORIZED":
1564
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "verifier completion was already observed")
1565
+ if event["hook_event_name"] == "PostToolUseFailure":
1566
+ wrapper["state"] = "FAILED"
1567
+ _save(root, request)
1568
+ return {"request_id": request_id, "state": "FAILED"}
1569
+ response = event.get("tool_response")
1570
+ if request["state"] != "COMPLETED":
1571
+ raise AuthorityError("FAILED_VERIFICATION", "verifier request did not complete")
1572
+ if not isinstance(response, dict) or response.get("interrupted") is not False:
1573
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper was interrupted or has no result")
1574
+ stdout = response.get("stdout")
1575
+ if not isinstance(stdout, str) or len(stdout.encode("utf-8")) > MAX_OUTPUT:
1576
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper output is unavailable")
1577
+ try:
1578
+ completed = json.loads(stdout.strip())
1579
+ except ValueError:
1580
+ completed = None
1581
+ if (
1582
+ not isinstance(completed, dict)
1583
+ or set(completed) != {"request_id", "state", "commands"}
1584
+ or completed.get("request_id") != request_id
1585
+ or completed.get("state") != "COMPLETED"
1586
+ ):
1587
+ raise AuthorityError("FAILED_VERIFICATION", "verifier wrapper output did not corroborate completion")
1588
+ wrapper["state"] = "CORROBORATED"
1589
+ _save(root, request)
1590
+ return {"request_id": request_id, "state": "CORROBORATED"}
1591
+
1592
+
1593
+ def _parse_decision(raw: Any, request: dict[str, Any]) -> dict[str, Any]:
1594
+ if not isinstance(raw, str) or len(raw.encode("utf-8")) > MAX_DECISION:
1595
+ raise AuthorityError("INVALID_REVIEW_DECISION", "review decision is absent or oversized")
1596
+ try:
1597
+ value = json.loads(raw)
1598
+ except ValueError as exc:
1599
+ raise AuthorityError("INVALID_REVIEW_DECISION", "review decision is not JSON") from exc
1600
+ expected = {
1601
+ "format", "request_id", "target_sha256", "contract_sha256", "decision",
1602
+ "coverage", "findings", "assessment",
1603
+ }
1604
+ context = request["context"]
1605
+ if (
1606
+ not isinstance(value, dict)
1607
+ or set(value) != expected
1608
+ or value.get("format") != DECISION_FORMAT
1609
+ or value.get("request_id") != request["request_id"]
1610
+ or value.get("target_sha256") != context["input_sha256"]
1611
+ or value.get("contract_sha256") != request["review_contract_sha256"]
1612
+ or value.get("decision") not in {"pass", "changes_requested"}
1613
+ or not isinstance(value.get("assessment"), str)
1614
+ or not value["assessment"].strip()
1615
+ or not isinstance(value.get("coverage"), list)
1616
+ or len(set(value["coverage"])) != len(value["coverage"])
1617
+ or not isinstance(value.get("findings"), list)
1618
+ ):
1619
+ raise AuthorityError("INVALID_REVIEW_DECISION", "review decision failed its closed schema")
1620
+ if set(value["coverage"]) != set(request["required_coverage"]):
1621
+ raise AuthorityError("INCOMPLETE_REVIEW", "review coverage is incomplete")
1622
+ for finding in value["findings"]:
1623
+ if (
1624
+ not isinstance(finding, dict)
1625
+ or set(finding) != {"severity", "code", "message"}
1626
+ or finding["severity"] not in {"BLOCK", "WARN", "INFO"}
1627
+ or not all(isinstance(finding[key], str) and finding[key] for key in ("code", "message"))
1628
+ ):
1629
+ raise AuthorityError("INVALID_REVIEW_DECISION", "review finding is malformed")
1630
+ if value["decision"] != "pass" or any(
1631
+ finding["severity"] == "BLOCK" for finding in value["findings"]
1632
+ ):
1633
+ raise AuthorityError("REVIEW_REJECTED", "independent reviewer did not pass the target")
1634
+ return value
1635
+
1636
+
1637
+ def observe_codex_hook(root: str | Path, event: dict[str, Any]) -> dict[str, Any]:
1638
+ _real_root(root) # Invocation repository is observed but cannot select authority.
1639
+ if not isinstance(event, dict):
1640
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "hook event is malformed")
1641
+ name = event.get("hook_event_name")
1642
+ session_id = _host_id(event.get("session_id"), "session_id")
1643
+
1644
+ if name == "PreToolUse":
1645
+ if event.get("tool_name") != "spawn_agent":
1646
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "only spawn_agent can launch a reviewer")
1647
+ tool_use_id = _host_id(event.get("tool_use_id"), "tool_use_id")
1648
+ turn_id = _host_id(event.get("turn_id"), "turn_id")
1649
+ tool_input = event.get("tool_input")
1650
+ if not isinstance(tool_input, dict):
1651
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "spawn input is malformed")
1652
+ message = tool_input.get("message")
1653
+ if not isinstance(message, str) or not message.startswith("[CODEARBITER_AUTHORITY_REQUEST:"):
1654
+ _record_ordinary_spawn(session_id, turn_id)
1655
+ _reject_overlapping_authority(session_id, turn_id)
1656
+ return None
1657
+ request_id = _request_id_from_prompt(message)
1658
+ root, request = _registered_request(request_id)
1659
+ if (
1660
+ request.get("host", "codex") != "codex"
1661
+ or request["activity"] not in REVIEW_ACTIVITIES
1662
+ or request["state"] != "ARMED"
1663
+ ):
1664
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review request is not launchable")
1665
+ if tool_input != request.get("launch_envelope"):
1666
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review launch envelope was changed")
1667
+ if _ordinary_spawn_marker(session_id, turn_id).exists():
1668
+ request["state"] = "REJECTED"
1669
+ request["recovery"] = {
1670
+ "mode": "overlapping-subagent-launch",
1671
+ "rerun_permitted": False,
1672
+ }
1673
+ _save(root, request)
1674
+ raise AuthorityError(
1675
+ "UNSUPPORTED_HOST_SEAM",
1676
+ "authority review cannot share a parent turn with another subagent launch",
1677
+ )
1678
+ request["launch"] = {
1679
+ "parent_session_id": session_id, "parent_turn_id": turn_id,
1680
+ "tool_use_id": tool_use_id, "post_confirmed": False,
1681
+ "agent_id": None, "agent_type": None,
1682
+ "task_name": tool_input["task_name"],
1683
+ "fork_turns": tool_input["fork_turns"],
1684
+ }
1685
+ request["state"] = "LAUNCHING"
1686
+ _save(root, request)
1687
+ return {"request_id": request_id, "state": "LAUNCHING"}
1688
+
1689
+ if name == "PostToolUse":
1690
+ if event.get("tool_name") != "spawn_agent":
1691
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "post-tool event is not reviewer launch")
1692
+ tool_use_id = _host_id(event.get("tool_use_id"), "tool_use_id")
1693
+ turn_id = _host_id(event.get("turn_id"), "turn_id")
1694
+ response = event.get("tool_response")
1695
+ if not isinstance(response, dict):
1696
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "spawn result is malformed")
1697
+ task_name = _host_id(response.get("task_name"), "task_name")
1698
+ matches = []
1699
+ for candidate_root, candidate in _registered_requests():
1700
+ launch = candidate.get("launch") or {}
1701
+ if (
1702
+ candidate["state"] in {"LAUNCHING", "RUNNING"}
1703
+ and launch.get("parent_session_id") == session_id
1704
+ and launch.get("parent_turn_id") == turn_id
1705
+ and launch.get("tool_use_id") == tool_use_id
1706
+ ):
1707
+ matches.append((candidate_root, candidate))
1708
+ if not matches:
1709
+ return None
1710
+ if len(matches) != 1:
1711
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review launch correlation is ambiguous")
1712
+ root, request = matches[0]
1713
+ if task_name != request["launch"].get("task_name"):
1714
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "spawn result task_name differs")
1715
+ request["launch"]["post_confirmed"] = True
1716
+ _save(root, request)
1717
+ return {"request_id": request["request_id"], "state": request["state"]}
1718
+
1719
+ if name in {"SubagentStart", "SubagentStop"}:
1720
+ agent_id = _host_id(event.get("agent_id"), "agent_id")
1721
+ turn_id = _host_id(event.get("turn_id"), "turn_id")
1722
+ matches = []
1723
+ same_turn = []
1724
+ for candidate_root, candidate in _registered_requests():
1725
+ launch = candidate.get("launch") or {}
1726
+ if (
1727
+ launch.get("parent_session_id") == session_id
1728
+ and launch.get("parent_turn_id") == turn_id
1729
+ and candidate["state"] in {"LAUNCHING", "RUNNING"}
1730
+ ):
1731
+ same_turn.append((candidate_root, candidate))
1732
+ if name == "SubagentStart" and (
1733
+ candidate["state"] == "LAUNCHING"
1734
+ and launch.get("parent_session_id") == session_id
1735
+ and launch.get("parent_turn_id") == turn_id
1736
+ ):
1737
+ matches.append((candidate_root, candidate))
1738
+ elif name == "SubagentStop" and (
1739
+ launch.get("parent_session_id") == session_id
1740
+ and launch.get("parent_turn_id") == turn_id
1741
+ and launch.get("agent_id") == agent_id
1742
+ ):
1743
+ matches.append((candidate_root, candidate))
1744
+ if not matches and not same_turn:
1745
+ return None
1746
+ if not matches and same_turn:
1747
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent does not match the active authority launch")
1748
+ if len(matches) != 1:
1749
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent correlation is ambiguous")
1750
+ root, request = matches[0]
1751
+ agent_type = _host_id(event.get("agent_type"), "agent_type")
1752
+ if name == "SubagentStart":
1753
+ request["launch"]["agent_id"] = agent_id
1754
+ request["launch"]["agent_type"] = agent_type
1755
+ request["state"] = "RUNNING"
1756
+ _save(root, request)
1757
+ return {"request_id": request["request_id"], "state": "RUNNING"}
1758
+ if (
1759
+ request["state"] != "RUNNING"
1760
+ or request["launch"].get("agent_type") != agent_type
1761
+ or request["launch"].get("post_confirmed") is not True
1762
+ ):
1763
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent stop is out of order")
1764
+ try:
1765
+ decision = _parse_decision(event.get("last_assistant_message"), request)
1766
+ except AuthorityError:
1767
+ request["state"] = "REJECTED"
1768
+ _save(root, request)
1769
+ raise
1770
+ payload = {
1771
+ "input_sha256": request["context"]["input_sha256"],
1772
+ "spec_sha256": request["context"]["spec_sha256"],
1773
+ "assessment": decision["assessment"],
1774
+ }
1775
+ if request["activity"] == "spec_review":
1776
+ payload["task_sha256"] = request["context"]["task_sha256"]
1777
+ else:
1778
+ payload["base_input_sha256"] = request["context"]["base_input_sha256"]
1779
+ payload["task_hashes"] = request["context"]["task_hashes"]
1780
+ producer_result = {"launch": request["launch"], "decision": decision}
1781
+ observation = _closed_observation(
1782
+ request, payload, CODEX_REVIEW_PROFILE, agent_id,
1783
+ producer_result,
1784
+ )
1785
+ _observation(root, request, observation)
1786
+ request["payload"] = payload
1787
+ request["state"] = "COMPLETED"
1788
+ _save(root, request)
1789
+ return {"request_id": request["request_id"], "state": "COMPLETED"}
1790
+
1791
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "hook event is not supported")
1792
+
1793
+
1794
+ def _claude_requests(state: set[str], strict: bool = False) -> list[tuple[Path, dict[str, Any]]]:
1795
+ return [
1796
+ (root, request) for root, request in _registered_requests(strict)
1797
+ if request.get("host") == "claude" and request["activity"] in REVIEW_ACTIVITIES
1798
+ and request["state"] in state
1799
+ ]
1800
+
1801
+
1802
+ def _reject(root: Path, request: dict[str, Any], mode: str) -> None:
1803
+ request["state"] = "REJECTED"
1804
+ request["recovery"] = {"mode": mode, "rerun_permitted": False}
1805
+ _save(root, request)
1806
+
1807
+
1808
+ def _claude_bind_child(root: Path, request: dict[str, Any]) -> dict[str, Any]:
1809
+ """Complete the order-independent launch/child join when both sides exist."""
1810
+ launch = request["launch"]
1811
+ marker = _claude_start_marker(launch["agent_id"])
1812
+ try:
1813
+ started = json.loads(marker.read_text(encoding="utf-8"))
1814
+ except FileNotFoundError:
1815
+ _save(root, request)
1816
+ return {"request_id": request["request_id"], "state": request["state"]}
1817
+ except (OSError, UnicodeError, ValueError) as exc:
1818
+ _reject(root, request, "unreadable-subagent-start")
1819
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent start record is unreadable") from exc
1820
+ if not isinstance(started, dict) or started.get("agent_type") != CLAUDE_REVIEWER:
1821
+ _reject(root, request, "unpinned-reviewer-agent")
1822
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent is not the pinned reviewer")
1823
+ launch["agent_type"] = CLAUDE_REVIEWER
1824
+ request["state"] = "RUNNING"
1825
+ _save(root, request)
1826
+ marker.unlink(missing_ok=True)
1827
+ return {"request_id": request["request_id"], "state": "RUNNING"}
1828
+
1829
+
1830
+ def observe_claude_hook(root: str | Path, event: dict[str, Any]) -> dict[str, Any] | None:
1831
+ """Correlate a Claude Code reviewer launch, child lifecycle, and first result.
1832
+
1833
+ The invocation repository is observed but never selects authority, and an
1834
+ ordinary (non-authority) event is never refused.
1835
+ """
1836
+ if not isinstance(event, dict):
1837
+ return None
1838
+ name = event.get("hook_event_name")
1839
+ tool = event.get("tool_name")
1840
+
1841
+ if name == "PreToolUse" and tool == "SendMessage":
1842
+ # The message shape is not a recorded contract, so fail closed: any
1843
+ # message from the reviewer's parent session while it runs could steer it.
1844
+ session = event.get("session_id")
1845
+ rejected = None
1846
+ for candidate_root, candidate in _claude_requests({"LAUNCHING", "RUNNING"}, strict=True):
1847
+ if session is not None and session == (candidate.get("launch") or {}).get("parent_session_id"):
1848
+ _reject(candidate_root, candidate, "reviewer-steered-by-message")
1849
+ rejected = {"request_id": candidate["request_id"], "state": "REJECTED"}
1850
+ return rejected
1851
+
1852
+ if name == "PreToolUse" and tool == "Agent":
1853
+ tool_input = event.get("tool_input")
1854
+ prompt = tool_input.get("prompt") if isinstance(tool_input, dict) else None
1855
+ if not isinstance(prompt, str) or not prompt.startswith("[CODEARBITER_AUTHORITY_REQUEST:"):
1856
+ return None
1857
+ session_root = _real_root(root)
1858
+ session_id = _host_id(event.get("session_id"), "session_id")
1859
+ prompt_id = _host_id(event.get("prompt_id"), "prompt_id")
1860
+ tool_use_id = _host_id(event.get("tool_use_id"), "tool_use_id")
1861
+ root, request = _registered_request(_request_id_from_prompt(prompt))
1862
+ if (
1863
+ request.get("host") != "claude"
1864
+ or request["activity"] not in REVIEW_ACTIVITIES
1865
+ or request["state"] != "ARMED"
1866
+ ):
1867
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review request is not launchable")
1868
+ if tool_input != request.get("launch_envelope"):
1869
+ _reject(root, request, "changed-launch-envelope")
1870
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review launch envelope was changed")
1871
+ try:
1872
+ _refuse_shadowed_reviewer(root, session_root)
1873
+ except AuthorityError:
1874
+ _reject(root, request, "shadowed-reviewer")
1875
+ raise
1876
+ request["launch"] = {
1877
+ "parent_session_id": session_id, "parent_prompt_id": prompt_id,
1878
+ "tool_use_id": tool_use_id, "post_confirmed": False,
1879
+ "agent_id": None, "agent_type": None,
1880
+ "subagent_type": tool_input["subagent_type"], "model": tool_input["model"],
1881
+ "resolved_model": None, "first_stop": False,
1882
+ }
1883
+ request["state"] = "LAUNCHING"
1884
+ _save(root, request)
1885
+ return {"request_id": request["request_id"], "state": "LAUNCHING"}
1886
+
1887
+ if name == "PostToolUse" and tool == "Agent":
1888
+ session_id = event.get("session_id")
1889
+ tool_use_id = event.get("tool_use_id")
1890
+ matches = [
1891
+ (candidate_root, candidate)
1892
+ for candidate_root, candidate in _claude_requests({"LAUNCHING"})
1893
+ if (candidate.get("launch") or {}).get("tool_use_id") == tool_use_id
1894
+ and candidate["launch"].get("parent_session_id") == session_id
1895
+ ]
1896
+ if not matches:
1897
+ return None
1898
+ if len(matches) != 1:
1899
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review launch correlation is ambiguous")
1900
+ root, request = matches[0]
1901
+ response = event.get("tool_response")
1902
+ try:
1903
+ prompt_id = _host_id(event.get("prompt_id"), "prompt_id")
1904
+ if request["launch"].get("parent_prompt_id") != prompt_id or request["launch"]["post_confirmed"]:
1905
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "review launch result is out of order")
1906
+ if not isinstance(response, dict):
1907
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "agent result is malformed")
1908
+ agent_id = _host_id(response.get("agentId"), "agentId")
1909
+ resolved = _host_id(response.get("resolvedModel"), "resolvedModel")
1910
+ except AuthorityError:
1911
+ _reject(root, request, "uncorrelated-launch-result")
1912
+ raise
1913
+ request["launch"].update(post_confirmed=True, agent_id=agent_id, resolved_model=resolved)
1914
+ return _claude_bind_child(root, request)
1915
+
1916
+ if name == "SubagentStart":
1917
+ if not _claude_requests({"LAUNCHING"}):
1918
+ return None
1919
+ agent_id = _host_id(event.get("agent_id"), "agent_id")
1920
+ agent_type = _host_id(event.get("agent_type"), "agent_type")
1921
+ for candidate_root, candidate in _claude_requests({"LAUNCHING"}):
1922
+ launch = candidate.get("launch") or {}
1923
+ if launch.get("agent_id") == agent_id:
1924
+ if agent_type != CLAUDE_REVIEWER:
1925
+ _reject(candidate_root, candidate, "unpinned-reviewer-agent")
1926
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent is not the pinned reviewer")
1927
+ launch["agent_type"] = agent_type
1928
+ candidate["state"] = "RUNNING"
1929
+ _save(candidate_root, candidate)
1930
+ return {"request_id": candidate["request_id"], "state": "RUNNING"}
1931
+ if any(
1932
+ (candidate.get("launch") or {}).get("post_confirmed") is False
1933
+ for _root, candidate in _claude_requests({"LAUNCHING"})
1934
+ ):
1935
+ # The launch result may not have arrived yet; remember this start.
1936
+ marker = _claude_start_marker(agent_id)
1937
+ data = _canonical({"agent_id": agent_id, "agent_type": agent_type})
1938
+ # Written aside and linked into place: a concurrent launch result
1939
+ # joining this agent must never read an empty or partial marker.
1940
+ temporary = marker.with_name(f".{marker.name}.{secrets.token_hex(8)}.tmp")
1941
+ fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
1942
+ try:
1943
+ os.write(fd, data)
1944
+ os.fsync(fd)
1945
+ finally:
1946
+ os.close(fd)
1947
+ try:
1948
+ os.link(temporary, marker)
1949
+ except FileExistsError:
1950
+ return None
1951
+ finally:
1952
+ temporary.unlink(missing_ok=True)
1953
+ # The launch result may have bound this agent while the marker was
1954
+ # being written; finish the join now rather than strand it.
1955
+ for candidate_root, candidate in _claude_requests({"LAUNCHING"}):
1956
+ if (candidate.get("launch") or {}).get("agent_id") == agent_id:
1957
+ return _claude_bind_child(candidate_root, candidate)
1958
+ return None
1959
+
1960
+ if name == "SubagentStop":
1961
+ agent_id = event.get("agent_id")
1962
+ matches = [
1963
+ (candidate_root, candidate)
1964
+ for candidate_root, candidate in _claude_requests({"LAUNCHING", "RUNNING"})
1965
+ if (candidate.get("launch") or {}).get("agent_id") == agent_id
1966
+ ]
1967
+ if not matches:
1968
+ # Includes every later Stop for an already-completed reviewer.
1969
+ return None
1970
+ if len(matches) != 1:
1971
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "subagent correlation is ambiguous")
1972
+ session_root = root
1973
+ root, request = matches[0]
1974
+ launch = request["launch"]
1975
+ if request["state"] == "LAUNCHING" and launch.get("post_confirmed") is True:
1976
+ # A start marker written late in the launch/start race.
1977
+ _claude_bind_child(root, request)
1978
+ request = _load(root, request["request_id"])
1979
+ launch = request["launch"]
1980
+ try:
1981
+ # background_tasks is the parent session's list and includes this
1982
+ # reviewer itself while it runs; it can only corroborate identity.
1983
+ tasks = event.get("background_tasks")
1984
+ own = [
1985
+ task for task in tasks if isinstance(task, dict) and task.get("id") == agent_id
1986
+ ] if isinstance(tasks, list) else None
1987
+ if (
1988
+ request["state"] != "RUNNING"
1989
+ or launch.get("post_confirmed") is not True
1990
+ or event.get("agent_type") != CLAUDE_REVIEWER
1991
+ or event.get("stop_hook_active") is not False
1992
+ or own is None
1993
+ or len(own) != 1
1994
+ or own[0].get("agent_type") != CLAUDE_REVIEWER
1995
+ ):
1996
+ raise AuthorityError("UNSUPPORTED_HOST_SEAM", "reviewer stop is not a first clean stop")
1997
+ _refuse_shadowed_reviewer(root, _real_root(session_root))
1998
+ decision = _parse_decision(event.get("last_assistant_message"), request)
1999
+ except AuthorityError:
2000
+ _reject(root, request, "rejected-first-stop")
2001
+ raise
2002
+ launch["first_stop"] = True
2003
+ payload = {
2004
+ "input_sha256": request["context"]["input_sha256"],
2005
+ "spec_sha256": request["context"]["spec_sha256"],
2006
+ "assessment": decision["assessment"],
2007
+ }
2008
+ if request["activity"] == "spec_review":
2009
+ payload["task_sha256"] = request["context"]["task_sha256"]
2010
+ else:
2011
+ payload["base_input_sha256"] = request["context"]["base_input_sha256"]
2012
+ payload["task_hashes"] = request["context"]["task_hashes"]
2013
+ observation = _closed_observation(
2014
+ request, payload, CLAUDE_REVIEW_PROFILE, agent_id,
2015
+ {"launch": launch, "decision": decision},
2016
+ )
2017
+ _observation(root, request, observation)
2018
+ request["payload"] = payload
2019
+ request["state"] = "COMPLETED"
2020
+ _save(root, request)
2021
+ return {"request_id": request["request_id"], "state": "COMPLETED"}
2022
+
2023
+ return None
2024
+
2025
+
2026
+ def _event(request: dict[str, Any]) -> dict[str, Any]:
2027
+ context = request["context"]
2028
+ activity = request["activity"]
2029
+ host = request.get("host", "codex")
2030
+ host_label = "Claude" if host == "claude" else "Codex"
2031
+ if activity == "verification":
2032
+ authority_kind = "verification_runner"
2033
+ actor = "codeArbiter supervised verifier"
2034
+ origin = f"{host}:verification-run:{request['request_id']}"
2035
+ source_text = "Observed exact declared-command completion and qualified named-test results."
2036
+ else:
2037
+ authority_kind = "review_workflow"
2038
+ actor = f"independent {host} reviewer"
2039
+ origin = f"{host}:subagent:{request['launch']['agent_id']}"
2040
+ source_text = f"Observed a correlated fresh {host_label} reviewer completion with a closed passing decision."
2041
+ return {
2042
+ "format": EVENT_FORMAT,
2043
+ "kind": activity,
2044
+ "authority_kind": authority_kind,
2045
+ "subject": context["subject"],
2046
+ "actor": actor,
2047
+ "origin": origin,
2048
+ "verdict": "passed",
2049
+ "payload": request["payload"],
2050
+ "source_text": source_text,
2051
+ "observation_ref": request["observation_ref"],
2052
+ "observation_sha256": request["observation_sha256"],
2053
+ }
2054
+
2055
+
2056
+ def publish_request(
2057
+ root: str | Path, client: Any, request_id: str
2058
+ ) -> dict[str, Any]:
2059
+ root = _real_root(root)
2060
+ request = _load(root, request_id)
2061
+ if request["state"] == "CAPTURED":
2062
+ return {
2063
+ "request_id": request_id, "receipt": request["receipt"],
2064
+ "authority_source": request["authority_source"],
2065
+ }
2066
+ if request["state"] != "COMPLETED":
2067
+ raise AuthorityError("AUTHORITY_NOT_COMPLETE", "successful observation is absent")
2068
+ if request["activity"] == "verification":
2069
+ wrapper = request.get("wrapper")
2070
+ if not isinstance(wrapper, dict) or wrapper.get("state") != "CORROBORATED":
2071
+ raise AuthorityError("AUTHORITY_NOT_COMPLETE", "verifier wrapper completion is uncorroborated")
2072
+ current, current_ref, current_hash = _context(
2073
+ root, client, request["context"]["subject"]["artifact_id"],
2074
+ request["context"]["subject"]["record_id"],
2075
+ request["activity"],
2076
+ )
2077
+ if (
2078
+ current != request["context"]
2079
+ or current_ref != request["context_ref"]
2080
+ or current_hash != request["context_sha256"]
2081
+ ):
2082
+ raise AuthorityError("STALE_AUTHORITY_REQUEST", "engine evidence context changed")
2083
+ observation_path = root / request["observation_ref"]
2084
+ try:
2085
+ observation = observation_path.read_bytes()
2086
+ except OSError as exc:
2087
+ raise AuthorityError("INVALID_OBSERVATION", "observation is unavailable") from exc
2088
+ if _digest(observation) != request["observation_sha256"]:
2089
+ raise AuthorityError("INVALID_OBSERVATION", "observation digest differs")
2090
+ event = _event(request)
2091
+ raw = _canonical(event)
2092
+ digest = _digest(raw)
2093
+ relative = SOURCE_DIR / f"{digest}.json"
2094
+ _publish_immutable(root, relative, raw)
2095
+ captured = client.call("capture-observation", {
2096
+ "source_ref": relative.as_posix(), "source_sha256": digest,
2097
+ })
2098
+ receipt = captured.get("receipt")
2099
+ if not isinstance(receipt, str) or not receipt:
2100
+ raise AuthorityError("INVALID_RECEIPT", "capture returned no receipt")
2101
+ request["state"] = "CAPTURED"
2102
+ request["receipt"] = receipt
2103
+ request["authority_source"] = relative.as_posix()
2104
+ _save(root, request)
2105
+ return {"request_id": request_id, "receipt": receipt, "authority_source": relative.as_posix()}
2106
+
2107
+
2108
+ def recover_request(root: str | Path, request_id: str, disposition: str) -> dict[str, Any]:
2109
+ """Retain an uncertain attempt and close it without ever rerunning commands."""
2110
+ root = _real_root(root)
2111
+ if disposition not in {"failed", "abandoned"}:
2112
+ raise AuthorityError("INVALID_RECOVERY", "recovery disposition must be failed or abandoned")
2113
+ request = _load(root, request_id)
2114
+ recoverable_completed = (
2115
+ request["state"] == "COMPLETED"
2116
+ and request["activity"] == "verification"
2117
+ and isinstance(request.get("wrapper"), dict)
2118
+ and request["wrapper"].get("state") != "CORROBORATED"
2119
+ )
2120
+ recoverable_authorized = (
2121
+ request["state"] == "ARMED"
2122
+ and request["activity"] == "verification"
2123
+ and isinstance(request.get("wrapper"), dict)
2124
+ and request["wrapper"].get("state") in {"AUTHORIZED", "FAILED"}
2125
+ )
2126
+ if request["state"] not in {"RUNNING", "LAUNCHING"} and not recoverable_completed and not recoverable_authorized:
2127
+ raise AuthorityError("INVALID_RECOVERY", "only an interrupted active attempt can be recovered")
2128
+ request["state"] = disposition.upper()
2129
+ request["recovery"] = {
2130
+ "disposition": disposition,
2131
+ "previous_attempt": request.get("attempt"),
2132
+ "rerun_permitted": False,
2133
+ }
2134
+ _save(root, request)
2135
+ return {"request_id": request_id, "state": request["state"], "rerun_permitted": False}