@arbiterforge/ca-pi 0.10.13 → 0.14.6

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 (57) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/plugins/ca-pi/CHANGELOG.md +159 -0
  4. package/plugins/ca-pi/SKILLS.md +1 -1
  5. package/plugins/ca-pi/SPRINT.md +40 -10
  6. package/plugins/ca-pi/agents/backend-author.md +1 -1
  7. package/plugins/ca-pi/agents/frontend-author.md +1 -1
  8. package/plugins/ca-pi/generated/command-catalog.json +1 -1
  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 +38 -0
  16. package/plugins/ca-pi/hooks/_approvallib.py +355 -0
  17. package/plugins/ca-pi/hooks/_artifactlib.py +855 -0
  18. package/plugins/ca-pi/hooks/_cleanuplib.py +1553 -0
  19. package/plugins/ca-pi/hooks/_hooklib.py +37 -13
  20. package/plugins/ca-pi/hooks/_host.py +1 -1
  21. package/plugins/ca-pi/hooks/_intentlib.py +31 -0
  22. package/plugins/ca-pi/hooks/_planfilelib.py +34 -1
  23. package/plugins/ca-pi/hooks/_protectedstatelib.py +11 -1
  24. package/plugins/ca-pi/hooks/_readinjectlib.py +120 -0
  25. package/plugins/ca-pi/hooks/_releaselib.py +933 -85
  26. package/plugins/ca-pi/hooks/_standuplib.py +38 -10
  27. package/plugins/ca-pi/hooks/doctor.py +103 -0
  28. package/plugins/ca-pi/hooks/hostapi.py +1 -1
  29. package/plugins/ca-pi/hooks/pi-bridge.py +5 -1
  30. package/plugins/ca-pi/hooks/prompt-submit.py +33 -10
  31. package/plugins/ca-pi/hooks/releasehash.py +46 -32
  32. package/plugins/ca-pi/includes/artifacts.md +166 -0
  33. package/plugins/ca-pi/includes/author-tdd-workflow.md +2 -1
  34. package/plugins/ca-pi/includes/farm.md +27 -4
  35. package/plugins/ca-pi/includes/routing-table.md +2 -2
  36. package/plugins/ca-pi/includes/verification-boundary.md +27 -0
  37. package/plugins/ca-pi/package.json +18 -0
  38. package/plugins/ca-pi/routines/INDEX.md +4 -4
  39. package/plugins/ca-pi/routines/brainstorming/SKILL.md +23 -4
  40. package/plugins/ca-pi/routines/commit-gate/SKILL.md +30 -5
  41. package/plugins/ca-pi/routines/executing-plans/SKILL.md +52 -7
  42. package/plugins/ca-pi/routines/finishing-a-development-branch/SKILL.md +25 -3
  43. package/plugins/ca-pi/routines/refactor/SKILL.md +3 -2
  44. package/plugins/ca-pi/routines/release/SKILL.md +150 -44
  45. package/plugins/ca-pi/routines/subagent-driven-development/SKILL.md +53 -9
  46. package/plugins/ca-pi/routines/subagent-driven-development/references/farm-dispatch.md +20 -3
  47. package/plugins/ca-pi/routines/tdd/SKILL.md +27 -5
  48. package/plugins/ca-pi/routines/using-git-worktrees/SKILL.md +11 -2
  49. package/plugins/ca-pi/routines/writing-plans/SKILL.md +39 -10
  50. package/plugins/ca-pi/routines/writing-plans/references/farm-plan.md +34 -13
  51. package/plugins/ca-pi/skills/ca-chore/SKILL.md +7 -3
  52. package/plugins/ca-pi/skills/ca-commit/SKILL.md +3 -2
  53. package/plugins/ca-pi/skills/ca-doctor/SKILL.md +14 -0
  54. package/plugins/ca-pi/skills/ca-feature/SKILL.md +42 -8
  55. package/plugins/ca-pi/skills/ca-refactor/SKILL.md +4 -2
  56. package/plugins/ca-pi/skills/ca-release/SKILL.md +7 -6
  57. package/plugins/ca-pi/skills/ca-standup/SKILL.md +36 -8
@@ -0,0 +1,855 @@
1
+ #!/usr/bin/env python3
2
+ """Bounded stdlib bridge to an installation-pinned ca-artifact executable.
3
+
4
+ No imports perform I/O. No PATH search, environment-selected executable, schema
5
+ parser duplication, command execution from a document, or new host registration.
6
+ The caller supplies a trusted installation directory, never a repository setting.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import json
12
+ import os
13
+ from pathlib import Path
14
+ import platform
15
+ import re
16
+ import stat
17
+ import subprocess
18
+ import tempfile
19
+ import threading
20
+ from typing import Any
21
+
22
+ PROTOCOL = "codearbiter.artifact-api/0.1.0"
23
+ SCHEMA_VERSION = "0.3.1"
24
+ MAX_REQUEST = 8 << 20
25
+ MAX_RESPONSE = 65536
26
+ READ_OPERATIONS = frozenset({"capabilities", "schema", "read", "outline", "identity", "validate", "index", "snapshot", "diff", "repair-preview", "eligible", "farm-verify", "migration-preview"})
27
+
28
+
29
+ class ArtifactError(RuntimeError):
30
+ def __init__(self, code: str, message: str):
31
+ self.code = code
32
+ super().__init__(f"{code}: {message}")
33
+
34
+
35
+ def _object(pairs):
36
+ value = {}
37
+ for key, item in pairs:
38
+ if key in value:
39
+ raise ArtifactError("INVALID_RESPONSE", "duplicate JSON key")
40
+ value[key] = item
41
+ return value
42
+
43
+
44
+ def _decode(raw: bytes) -> Any:
45
+ if len(raw) > MAX_RESPONSE:
46
+ raise ArtifactError("INVALID_RESPONSE", "oversized JSON envelope")
47
+ # Bound nesting independently of the interpreter's recursion-limit setting.
48
+ depth = 0
49
+ quoted = escaped = False
50
+ for byte in raw:
51
+ if quoted:
52
+ if escaped:
53
+ escaped = False
54
+ elif byte == 92:
55
+ escaped = True
56
+ elif byte == 34:
57
+ quoted = False
58
+ elif byte == 34:
59
+ quoted = True
60
+ elif byte in (91, 123):
61
+ depth += 1
62
+ if depth > 128:
63
+ raise ArtifactError("INVALID_RESPONSE", "JSON nesting exceeds 128 levels")
64
+ elif byte in (93, 125):
65
+ depth -= 1
66
+ try:
67
+ return json.loads(raw.decode("utf-8", "strict"), object_pairs_hook=_object,
68
+ parse_constant=lambda _: (_ for _ in ()).throw(ValueError("nonfinite")))
69
+ except (ValueError, UnicodeError, RecursionError) as exc:
70
+ raise ArtifactError("INVALID_RESPONSE", "invalid bounded JSON") from exc
71
+
72
+
73
+ def helper_installation(helper_file: str) -> Path:
74
+ """Shipped helpers live in <plugin>/hooks; the trusted payload is a sibling.
75
+
76
+ Source-checkout callers use an explicit installation instead of guessing a
77
+ binary under the repository being governed.
78
+ """
79
+ return Path(helper_file).resolve().parent.parent / "helpers" / "artifacts"
80
+
81
+
82
+ def _open_pinned_regular(path: Path) -> int:
83
+ """Open without following the final link and pin Windows replacement.
84
+
85
+ The Windows handle shares reads only, so a verified executable cannot be
86
+ replaced or opened for writing before CreateProcess consumes its path.
87
+ """
88
+ if os.name != "nt":
89
+ flags = os.O_RDONLY | os.O_NOFOLLOW | os.O_CLOEXEC | os.O_NONBLOCK
90
+ return os.open(path, flags)
91
+ import ctypes
92
+ import msvcrt
93
+ create_file = ctypes.WinDLL("kernel32", use_last_error=True).CreateFileW
94
+ create_file.argtypes = [ctypes.c_wchar_p, ctypes.c_uint32, ctypes.c_uint32,
95
+ ctypes.c_void_p, ctypes.c_uint32, ctypes.c_uint32,
96
+ ctypes.c_void_p]
97
+ create_file.restype = ctypes.c_void_p
98
+ handle = create_file(str(path), 0x80000000, 0x00000001, None, 3,
99
+ 0x00200000, None)
100
+ if handle == ctypes.c_void_p(-1).value:
101
+ raise OSError(ctypes.get_last_error(), "CreateFileW failed", str(path))
102
+ try:
103
+ return msvcrt.open_osfhandle(handle, os.O_RDONLY)
104
+ except BaseException:
105
+ ctypes.WinDLL("kernel32", use_last_error=True).CloseHandle(handle)
106
+ raise
107
+
108
+
109
+ def _stage_darwin_executable(fd: int, directory: Path) -> Path:
110
+ """Materialize verified descriptor bytes for macOS executable launch.
111
+
112
+ macOS exposes inherited descriptors below /dev/fd but does not permit
113
+ executing a native binary through that path. The caller supplies a fresh,
114
+ private temporary directory; no installation or repository pathname is
115
+ reopened while producing the executable image.
116
+ """
117
+ target = directory / "ca-artifact"
118
+ output = os.open(
119
+ target,
120
+ os.O_WRONLY
121
+ | os.O_CREAT
122
+ | os.O_EXCL
123
+ | getattr(os, "O_CLOEXEC", 0)
124
+ | getattr(os, "O_NOFOLLOW", 0),
125
+ stat.S_IRUSR | stat.S_IWUSR,
126
+ )
127
+ try:
128
+ os.lseek(fd, 0, os.SEEK_SET)
129
+ while chunk := os.read(fd, 1 << 20):
130
+ remaining = memoryview(chunk)
131
+ while remaining:
132
+ written = os.write(output, remaining)
133
+ if written <= 0:
134
+ raise OSError("short write while staging verified executable")
135
+ remaining = remaining[written:]
136
+ os.fsync(output)
137
+ os.fchmod(output, stat.S_IRUSR | stat.S_IXUSR)
138
+ finally:
139
+ os.close(output)
140
+ return target
141
+
142
+
143
+ def _trusted_directory(path: str | Path, code: str) -> Path:
144
+ requested = Path(path).absolute()
145
+ try:
146
+ if os.name == "nt":
147
+ import ctypes
148
+ attributes = ctypes.WinDLL("kernel32", use_last_error=True).GetFileAttributesW
149
+ attributes.argtypes = [ctypes.c_wchar_p]
150
+ attributes.restype = ctypes.c_uint32
151
+ current = requested
152
+ while current != current.parent:
153
+ value = attributes(str(current))
154
+ if value == 0xffffffff or value & 0x400:
155
+ raise OSError("reparse point or unreadable component")
156
+ current = current.parent
157
+ elif Path(os.path.realpath(requested)) != requested:
158
+ raise OSError("symlink component")
159
+ resolved = requested.resolve(strict=True)
160
+ if not resolved.is_dir():
161
+ raise OSError("not a directory")
162
+ return resolved
163
+ except OSError as exc:
164
+ raise ArtifactError(code, "directory must be an existing real path without links or reparse points") from exc
165
+
166
+
167
+ def _workflow_path_exists(root: Path, path: Path) -> bool:
168
+ """Inspect one canonical artifact path without following links or writing."""
169
+ for parent in (root / ".codearbiter", path.parent):
170
+ try:
171
+ info = parent.lstat()
172
+ except FileNotFoundError:
173
+ return False
174
+ except OSError as exc:
175
+ raise ArtifactError(
176
+ "UNSAFE_ARTIFACT_PATH", "canonical artifact directory is unreadable"
177
+ ) from exc
178
+ reparse = getattr(info, "st_file_attributes", 0) & getattr(
179
+ stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0
180
+ )
181
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISDIR(info.st_mode):
182
+ raise ArtifactError(
183
+ "UNSAFE_ARTIFACT_PATH",
184
+ "canonical artifact directory must be a real directory",
185
+ )
186
+ try:
187
+ info = path.lstat()
188
+ except FileNotFoundError:
189
+ return False
190
+ except OSError as exc:
191
+ raise ArtifactError(
192
+ "UNSAFE_ARTIFACT_PATH", "canonical artifact path is unreadable"
193
+ ) from exc
194
+ reparse = getattr(info, "st_file_attributes", 0) & getattr(
195
+ stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0
196
+ )
197
+ if stat.S_ISLNK(info.st_mode) or reparse or not stat.S_ISREG(info.st_mode):
198
+ raise ArtifactError(
199
+ "UNSAFE_ARTIFACT_PATH", "canonical artifact path must be a regular file"
200
+ )
201
+ return True
202
+
203
+
204
+ def _resolve_workflow_pair(root: str | Path, slug: str) -> dict[str, object]:
205
+ """Select an exact-format spec/plan authority without parsing or writing it."""
206
+ trusted_root = _trusted_directory(root, "UNSAFE_ROOT")
207
+ if not isinstance(slug, str) or not re.fullmatch(r"[a-z][a-z0-9-]{0,99}", slug):
208
+ raise ArtifactError("INVALID_SLUG", "slug must match the canonical artifact slug grammar")
209
+
210
+ candidates = {
211
+ kind: {
212
+ extension: trusted_root / ".codearbiter" / f"{kind}s" / f"{slug}.{extension}"
213
+ for extension in ("md", "html")
214
+ }
215
+ for kind in ("spec", "plan")
216
+ }
217
+ present = {
218
+ kind: [
219
+ extension
220
+ for extension, path in paths.items()
221
+ if _workflow_path_exists(trusted_root, path)
222
+ ]
223
+ for kind, paths in candidates.items()
224
+ }
225
+ if len(present["spec"]) > 1 or len(present["plan"]) > 1:
226
+ raise ArtifactError(
227
+ "AMBIGUOUS_ARTIFACT", "multiple canonical files claim the workflow slug"
228
+ )
229
+ if present["plan"] and not present["spec"]:
230
+ raise ArtifactError("ORPHAN_PLAN", "canonical plan has no matching spec")
231
+ if present["spec"] and present["plan"] and present["spec"] != present["plan"]:
232
+ raise ArtifactError(
233
+ "AMBIGUOUS_ARTIFACT", "spec and plan use different authority formats"
234
+ )
235
+
236
+ extension = present["spec"][0] if present["spec"] else "html"
237
+ state = "pair" if present["plan"] else "spec" if present["spec"] else "absent"
238
+ return {
239
+ "slug": slug,
240
+ "format": extension,
241
+ "state": state,
242
+ "spec_path": candidates["spec"][extension],
243
+ "plan_path": candidates["plan"][extension],
244
+ }
245
+
246
+
247
+ def _require_authoring_capability(client: "ArtifactClient") -> None:
248
+ """Fail one default-HTML route with a bounded repair diagnostic."""
249
+ try:
250
+ capabilities = client.call("capabilities")
251
+ except ArtifactError as exc:
252
+ raise ArtifactError(
253
+ "CAPABILITY_MISSING",
254
+ f"repair or reinstall the pinned artifact payload ({exc.code}); "
255
+ "new HTML work cannot fall back to Markdown",
256
+ ) from exc
257
+ if (
258
+ not isinstance(capabilities, dict)
259
+ or capabilities.get("repository_operations_available") is not True
260
+ or capabilities.get("host_default_enabled") is not True
261
+ ):
262
+ raise ArtifactError(
263
+ "CAPABILITY_MISSING",
264
+ "repair or reinstall the qualified default-on artifact payload; "
265
+ "new HTML work cannot fall back to Markdown",
266
+ )
267
+
268
+
269
+ def _select_authoring_route(
270
+ root: str | Path,
271
+ slug: str,
272
+ *,
273
+ workflow: str,
274
+ lane: str,
275
+ client: object | None = None,
276
+ html_requested: bool = False,
277
+ ) -> dict[str, object]:
278
+ """Select inline or exact-format authoring without creating artifacts."""
279
+ if workflow not in {"feature", "sprint"}:
280
+ raise ArtifactError("INVALID_WORKFLOW", "workflow must be feature or sprint")
281
+ if lane not in {"small", "full"}:
282
+ raise ArtifactError("INVALID_LANE", "lane must be small or full")
283
+ if type(html_requested) is not bool:
284
+ raise ArtifactError(
285
+ "INVALID_ROUTE", "html_requested must be an explicit boolean"
286
+ )
287
+ # Retain the rollout-era keyword for internal caller compatibility. It no
288
+ # longer opts an absent full-lane slug back into Markdown authority.
289
+ if lane == "small":
290
+ return {
291
+ "workflow": workflow,
292
+ "lane": lane,
293
+ "mode": "inline",
294
+ "slug": slug,
295
+ "spec_path": None,
296
+ "plan_path": None,
297
+ }
298
+
299
+ selected = _resolve_workflow_pair(root, slug)
300
+ if selected["format"] == "html":
301
+ trusted_root = Path(selected["spec_path"]).parent.parent.parent
302
+ if type(client) is not ArtifactClient or client.root != trusted_root:
303
+ raise ArtifactError(
304
+ "CAPABILITY_MISSING",
305
+ "an installation-pinned artifact client bound to this repository is required",
306
+ )
307
+ _require_authoring_capability(client)
308
+ if _resolve_workflow_pair(root, slug) != selected:
309
+ raise ArtifactError(
310
+ "STALE_ROUTE",
311
+ "artifact namespace changed during the capability probe",
312
+ )
313
+ return {"workflow": workflow, "lane": lane, "mode": "artifact", **selected}
314
+
315
+
316
+ def _preflight_plan_authoring(
317
+ selected: dict[str, object],
318
+ client: object,
319
+ *,
320
+ spec_artifact_id: str,
321
+ spec_normative_sha256: str,
322
+ ) -> Path:
323
+ """Verify one approved HTML spec and return its unwritten plan target."""
324
+ if not isinstance(selected, dict):
325
+ raise ArtifactError("INVALID_ROUTE", "plan authoring requires a selected route")
326
+ slug = selected.get("slug")
327
+ spec_path = selected.get("spec_path")
328
+ plan_path = selected.get("plan_path")
329
+ if (
330
+ selected.get("mode") != "artifact"
331
+ or selected.get("format") != "html"
332
+ or selected.get("state") != "spec"
333
+ or not isinstance(slug, str)
334
+ or not isinstance(spec_path, Path)
335
+ or not isinstance(plan_path, Path)
336
+ ):
337
+ raise ArtifactError(
338
+ "INVALID_ROUTE",
339
+ "plan authoring requires one existing HTML spec and no plan",
340
+ )
341
+ root = spec_path.parent.parent.parent
342
+ current = _resolve_workflow_pair(root, slug)
343
+ if any(
344
+ current.get(field) != selected.get(field)
345
+ for field in ("slug", "format", "state", "spec_path", "plan_path")
346
+ ):
347
+ raise ArtifactError("STALE_ROUTE", "selected artifact route is no longer current")
348
+ if (
349
+ spec_path != root / ".codearbiter" / "specs" / f"{slug}.html"
350
+ or plan_path != root / ".codearbiter" / "plans" / f"{slug}.html"
351
+ ):
352
+ raise ArtifactError("INVALID_ROUTE", "plan target must match the HTML spec slug")
353
+ if type(client) is not ArtifactClient or client.root != root:
354
+ raise ArtifactError(
355
+ "CAPABILITY_MISSING",
356
+ "an installation-pinned artifact client must be bound to the selected repository",
357
+ )
358
+ if not isinstance(spec_artifact_id, str) or not spec_artifact_id:
359
+ raise ArtifactError("AUTHORITY_MISMATCH", "spec artifact identity is required")
360
+ if not isinstance(spec_normative_sha256, str) or not re.fullmatch(
361
+ r"[0-9a-f]{64}", spec_normative_sha256
362
+ ):
363
+ raise ArtifactError("AUTHORITY_MISMATCH", "spec normative digest is invalid")
364
+
365
+ identity = client.call("identity", {"artifact_id": spec_artifact_id})
366
+ expected_path = f".codearbiter/specs/{slug}.html"
367
+ if (
368
+ identity.get("artifact_id") != spec_artifact_id
369
+ or identity.get("kind") != "spec"
370
+ or identity.get("path") != expected_path
371
+ or identity.get("normative_sha256") != spec_normative_sha256
372
+ ):
373
+ raise ArtifactError(
374
+ "AUTHORITY_MISMATCH",
375
+ "caller spec identity does not match the selected current HTML spec",
376
+ )
377
+ approved = client.call(
378
+ "validate",
379
+ {"artifact_id": spec_artifact_id, "gate": "approved"},
380
+ permit_invalid=True,
381
+ )
382
+ authority = approved.get("authority")
383
+ if (
384
+ approved.get("valid") is not True
385
+ or approved.get("artifact_id") != spec_artifact_id
386
+ or approved.get("normative_sha256") != spec_normative_sha256
387
+ or not isinstance(authority, dict)
388
+ or authority.get("state") != "approved"
389
+ or authority.get("authority_verified") is not True
390
+ ):
391
+ raise ArtifactError(
392
+ "AUTHORITY_UNVERIFIED",
393
+ "plan authoring requires the exact current ready and approved spec",
394
+ )
395
+ if _resolve_workflow_pair(root, slug) != current:
396
+ raise ArtifactError(
397
+ "STALE_ROUTE",
398
+ "artifact namespace changed during plan-authoring preflight",
399
+ )
400
+ return plan_path
401
+
402
+
403
+ def _preflight_current_acceptance(
404
+ selected: dict[str, object],
405
+ client: object,
406
+ *,
407
+ spec_artifact_id: str,
408
+ plan_artifact_id: str,
409
+ ) -> dict[str, object]:
410
+ """Return engine-bound proof that one exact HTML pair is currently accepted.
411
+
412
+ This is a private workflow boundary, not a public command. Caller-provided
413
+ labels, hashes, state, or receipts are deliberately outside its input shape.
414
+ """
415
+ route_fields = {"slug", "format", "state", "spec_path", "plan_path"}
416
+ if not isinstance(selected, dict) or set(selected) != route_fields:
417
+ raise ArtifactError(
418
+ "INVALID_ROUTE",
419
+ "current acceptance requires an exact resolver-produced route",
420
+ )
421
+ slug = selected.get("slug")
422
+ spec_path = selected.get("spec_path")
423
+ plan_path = selected.get("plan_path")
424
+ if (
425
+ selected.get("format") != "html"
426
+ or selected.get("state") != "pair"
427
+ or not isinstance(slug, str)
428
+ or not isinstance(spec_path, Path)
429
+ or not isinstance(plan_path, Path)
430
+ ):
431
+ raise ArtifactError(
432
+ "INVALID_ROUTE", "current acceptance requires one complete HTML pair"
433
+ )
434
+ root = spec_path.parent.parent.parent
435
+ if (
436
+ spec_path != root / ".codearbiter" / "specs" / f"{slug}.html"
437
+ or plan_path != root / ".codearbiter" / "plans" / f"{slug}.html"
438
+ ):
439
+ raise ArtifactError(
440
+ "INVALID_ROUTE", "selected paths must be the canonical same-slug HTML pair"
441
+ )
442
+ current = _resolve_workflow_pair(root, slug)
443
+ if any(current.get(field) != selected.get(field) for field in route_fields):
444
+ raise ArtifactError(
445
+ "STALE_ROUTE", "selected HTML pair is no longer the sole current authority"
446
+ )
447
+ if type(client) is not ArtifactClient or client.root != root:
448
+ raise ArtifactError(
449
+ "CAPABILITY_MISSING",
450
+ "an installation-pinned artifact client must be bound to the selected repository",
451
+ )
452
+ if not all(
453
+ isinstance(value, str) and re.fullmatch(r"[A-Z][A-Z0-9_-]{0,127}", value)
454
+ for value in (spec_artifact_id, plan_artifact_id)
455
+ ):
456
+ raise ArtifactError(
457
+ "AUTHORITY_MISMATCH", "exact spec and plan artifact identities are required"
458
+ )
459
+
460
+ expected = {
461
+ "spec": f".codearbiter/specs/{slug}.html",
462
+ "plan": f".codearbiter/plans/{slug}.html",
463
+ }
464
+ entries = {}
465
+ for kind, artifact_id in (
466
+ ("spec", spec_artifact_id),
467
+ ("plan", plan_artifact_id),
468
+ ):
469
+ matches = [entry for entry in client.index(kind) if entry.get("path") == expected[kind]]
470
+ if len(matches) != 1 or matches[0].get("artifact_id") != artifact_id:
471
+ raise ArtifactError(
472
+ "AUTHORITY_MISMATCH",
473
+ f"caller {kind} identity does not match the selected HTML pair",
474
+ )
475
+ entries[kind] = matches[0]
476
+
477
+ identities = {}
478
+ for kind, artifact_id in (
479
+ ("spec", spec_artifact_id),
480
+ ("plan", plan_artifact_id),
481
+ ):
482
+ identity = client.call("identity", {"artifact_id": artifact_id})
483
+ authority = identity.get("authority")
484
+ if (
485
+ identity.get("artifact_id") != artifact_id
486
+ or identity.get("kind") != kind
487
+ or identity.get("path") != expected[kind]
488
+ or identity.get("model_sha256") != entries[kind].get("model_sha256")
489
+ or identity.get("normative_sha256")
490
+ != entries[kind].get("normative_sha256")
491
+ or not isinstance(authority, dict)
492
+ or authority.get("state") != "approved"
493
+ or authority.get("authority_verified") is not True
494
+ ):
495
+ raise ArtifactError(
496
+ "AUTHORITY_UNVERIFIED",
497
+ f"selected {kind} lacks exact current workflow approval",
498
+ )
499
+ identities[kind] = identity
500
+
501
+ eligible = client.call("eligible", {"artifact_id": plan_artifact_id})
502
+ if (
503
+ eligible.get("artifact_id") != plan_artifact_id
504
+ or eligible.get("model_sha256") != identities["plan"].get("model_sha256")
505
+ or eligible.get("all_accepted_and_current") is not True
506
+ or not isinstance(eligible.get("tasks"), list)
507
+ or not eligible["tasks"]
508
+ or any(
509
+ not isinstance(task, dict)
510
+ or task.get("state") != "ACCEPTED"
511
+ or task.get("current_evidence") is not True
512
+ for task in eligible["tasks"]
513
+ )
514
+ ):
515
+ raise ArtifactError(
516
+ "ACCEPTANCE_REQUIRED",
517
+ "the exact selected HTML plan is not fully accepted with current evidence",
518
+ )
519
+
520
+ task_ids = [
521
+ record.get("id")
522
+ for record in client.outline(plan_artifact_id)
523
+ if record.get("kind") == "tasks" and record.get("retired") is False
524
+ ]
525
+ if not task_ids or any(not isinstance(task_id, str) for task_id in task_ids):
526
+ raise ArtifactError("INVALID_RESPONSE", "accepted plan has no live task identity")
527
+ pages = list(client.contextual_pages(plan_artifact_id, task_ids[0], 65536))
528
+ if not pages:
529
+ raise ArtifactError("INVALID_RESPONSE", "engine returned no acceptance context")
530
+ records = {
531
+ item.get("key"): item.get("record")
532
+ for page in pages
533
+ for item in page.get("items", [])
534
+ if isinstance(item, dict)
535
+ }
536
+ plan_context = records.get(f"{plan_artifact_id}#@context")
537
+ spec_context = records.get(f"{spec_artifact_id}#@context")
538
+ spec_ref = plan_context.get("spec_ref") if isinstance(plan_context, dict) else None
539
+ if (
540
+ not isinstance(spec_context, dict)
541
+ or not isinstance(spec_ref, dict)
542
+ or spec_ref.get("artifact_id") != spec_artifact_id
543
+ or spec_ref.get("normative_sha256")
544
+ != identities["spec"].get("normative_sha256")
545
+ or spec_ref.get("binding_mode") != "approved_source"
546
+ ):
547
+ raise ArtifactError(
548
+ "AUTHORITY_MISMATCH",
549
+ "selected plan is not bound to the exact approved HTML spec",
550
+ )
551
+ final_page = pages[-1]
552
+ receipts = {
553
+ "context_ticket": final_page.get("context_ticket"),
554
+ "vector_sha256": final_page.get("vector_sha256"),
555
+ "manifest_sha256": final_page.get("manifest_sha256"),
556
+ "input_sha256": eligible.get("input_sha256"),
557
+ }
558
+ if any(
559
+ not isinstance(value, str) or not re.fullmatch(r"[0-9a-f]{64}", value)
560
+ for value in receipts.values()
561
+ ):
562
+ raise ArtifactError(
563
+ "INVALID_RESPONSE", "engine acceptance proof lacks bounded receipt identities"
564
+ )
565
+
566
+ final_spec = client.call("identity", {"artifact_id": spec_artifact_id})
567
+ final_plan = client.call("identity", {"artifact_id": plan_artifact_id})
568
+ final_eligible = client.call("eligible", {"artifact_id": plan_artifact_id})
569
+ if (
570
+ final_spec.get("model_sha256") != identities["spec"].get("model_sha256")
571
+ or final_plan.get("model_sha256") != identities["plan"].get("model_sha256")
572
+ or final_eligible != eligible
573
+ ):
574
+ raise ArtifactError(
575
+ "STALE_ROUTE", "artifact identity or acceptance changed during preflight"
576
+ )
577
+ final_route = _resolve_workflow_pair(root, slug)
578
+ if final_route != selected:
579
+ raise ArtifactError(
580
+ "STALE_ROUTE", "selected HTML pair changed during acceptance preflight"
581
+ )
582
+ return {
583
+ "spec_identity": identities["spec"],
584
+ "plan_identity": identities["plan"],
585
+ "eligible": eligible,
586
+ "receipts": receipts,
587
+ }
588
+
589
+
590
+ def _bounded_child(argv: list[str], request: bytes, fd: int, timeout: float) -> tuple[int, bytes, bytes]:
591
+ options = dict(stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
592
+ close_fds=True, start_new_session=True, env={})
593
+ if os.name != "nt":
594
+ options["pass_fds"] = (fd,)
595
+ process = subprocess.Popen(argv, **options)
596
+ buffers = [bytearray(), bytearray()]
597
+ overflow = threading.Event()
598
+
599
+ def drain(pipe, slot, limit):
600
+ try:
601
+ while True:
602
+ chunk = pipe.read(4096)
603
+ if not chunk:
604
+ return
605
+ if len(buffers[slot]) + len(chunk) > limit:
606
+ overflow.set()
607
+ process.kill()
608
+ return
609
+ buffers[slot].extend(chunk)
610
+ finally:
611
+ pipe.close()
612
+
613
+ def write():
614
+ try:
615
+ process.stdin.write(request)
616
+ process.stdin.close()
617
+ except (BrokenPipeError, OSError):
618
+ pass
619
+
620
+ threads = [threading.Thread(target=drain, args=(process.stdout, 0, MAX_RESPONSE), daemon=True),
621
+ threading.Thread(target=drain, args=(process.stderr, 1, 8192), daemon=True),
622
+ threading.Thread(target=write, daemon=True)]
623
+ for thread in threads:
624
+ thread.start()
625
+ timed_out = False
626
+ try:
627
+ process.wait(timeout=timeout)
628
+ except subprocess.TimeoutExpired:
629
+ timed_out = True
630
+ process.kill()
631
+ process.wait()
632
+ for thread in threads:
633
+ thread.join(timeout=2)
634
+ if timed_out:
635
+ raise ArtifactError("TIMEOUT", "subprocess interrupted; reconcile mutation operation_id before retry")
636
+ if overflow.is_set() or any(t.is_alive() for t in threads):
637
+ raise ArtifactError("RESPONSE_TOO_LARGE", "subprocess output exceeded its contract")
638
+ return process.returncode, bytes(buffers[0]), bytes(buffers[1])
639
+
640
+
641
+ class ArtifactClient:
642
+ def __init__(self, root: str | Path, installation: str | Path, *, timeout: float = 30):
643
+ self.root = _trusted_directory(root, "UNSAFE_ROOT")
644
+ self.installation = _trusted_directory(installation, "CAPABILITY_MISSING")
645
+ self.timeout = timeout
646
+
647
+ def _open_binary(self) -> int:
648
+ system = {"Linux":"linux", "Darwin":"darwin", "Windows":"windows"}.get(platform.system())
649
+ arch = {"x86_64":"amd64", "amd64":"amd64", "aarch64":"arm64", "arm64":"arm64"}.get(platform.machine().lower())
650
+ if system is None or arch is None:
651
+ raise ArtifactError("UNSUPPORTED_PLATFORM", "unsupported architecture")
652
+ manifest_path = self.installation / "release.json"
653
+ try:
654
+ mf = _open_pinned_regular(manifest_path)
655
+ try:
656
+ info = os.fstat(mf)
657
+ if not stat.S_ISREG(info.st_mode) or info.st_size > 65536:
658
+ raise ArtifactError("INVALID_INSTALLATION", "release manifest must be a bounded regular file")
659
+ raw = os.read(mf, 65537)
660
+ if len(raw) > 65536:
661
+ raise ArtifactError("INVALID_INSTALLATION", "oversized release manifest")
662
+ finally:
663
+ os.close(mf)
664
+ try:
665
+ manifest = _decode(raw)
666
+ except ArtifactError as exc:
667
+ raise ArtifactError("INVALID_INSTALLATION", "invalid release manifest JSON") from exc
668
+ if not isinstance(manifest, dict) or set(manifest) != {"format", "version", "protocol", "schema_version", "binaries"}:
669
+ raise ArtifactError("INVALID_INSTALLATION", "unexpected release manifest")
670
+ if manifest["format"] != "codearbiter.artifact-release/0.1.0" or manifest["protocol"] != PROTOCOL or manifest["schema_version"] != SCHEMA_VERSION:
671
+ raise ArtifactError("UNSUPPORTED_VERSION", "installed binary/adapter version mismatch")
672
+ if not isinstance(manifest["binaries"], dict) or not isinstance(manifest["version"], str):
673
+ raise ArtifactError("INVALID_INSTALLATION", "malformed release manifest fields")
674
+ entry = manifest["binaries"].get(f"{system}/{arch}")
675
+ if not isinstance(entry, dict) or set(entry) != {"file", "sha256", "native_tested"}:
676
+ raise ArtifactError("CAPABILITY_MISSING", "no matching tested binary in the installation")
677
+ if entry["native_tested"] is not True:
678
+ raise ArtifactError("UNVERIFIED_PLATFORM", "cross-compilation is not native qualification")
679
+ name = entry["file"]
680
+ expected_name = f"ca-artifact-{system}-{arch}" + (".exe" if system == "windows" else "")
681
+ if name != expected_name:
682
+ raise ArtifactError("INVALID_INSTALLATION", "binary filename does not match the selected platform")
683
+ if not isinstance(entry["sha256"], str) or not re.fullmatch(r"[0-9a-f]{64}", entry["sha256"]):
684
+ raise ArtifactError("INVALID_INSTALLATION", "binary digest is malformed")
685
+ binary_path = self.installation / name
686
+ fd = _open_pinned_regular(binary_path)
687
+ except OSError as exc:
688
+ raise ArtifactError("CAPABILITY_MISSING", "install the pinned artifact payload; no PATH fallback is permitted") from exc
689
+ try:
690
+ info = os.fstat(fd)
691
+ if (not stat.S_ISREG(info.st_mode) or info.st_size > 32 << 20
692
+ or (system != "windows" and not info.st_mode & stat.S_IXUSR)):
693
+ raise ArtifactError("INVALID_INSTALLATION", "binary is not a bounded executable regular file")
694
+ digest = hashlib.sha256()
695
+ while chunk := os.read(fd, 1 << 20):
696
+ digest.update(chunk)
697
+ if digest.hexdigest() != entry["sha256"]:
698
+ raise ArtifactError("PACKAGE_INTEGRITY", "installed executable bytes differ from release manifest")
699
+ os.lseek(fd, 0, os.SEEK_SET)
700
+ header = os.read(fd, 4)
701
+ magic = {"linux":(b"\x7fELF",), "darwin":(b"\xcf\xfa\xed\xfe",b"\xca\xfe\xba\xbe",b"\xbe\xba\xfe\xca"), "windows":(b"MZ",)}[system]
702
+ if not header.startswith(magic):
703
+ raise ArtifactError("INVALID_INSTALLATION", "unexpected native executable format")
704
+ os.lseek(fd, 0, os.SEEK_SET)
705
+ return fd
706
+ except BaseException:
707
+ os.close(fd)
708
+ raise
709
+
710
+ def call(self, operation: str, request: dict[str, Any] | None = None, *, permit_invalid: bool = False) -> dict:
711
+ if not re.fullmatch(r"[a-z][a-z-]{0,39}", operation):
712
+ raise ArtifactError("UNKNOWN_OPERATION", "invalid internal operation name")
713
+ request = dict(request or {})
714
+ if "protocol" in request and request["protocol"] != PROTOCOL:
715
+ raise ArtifactError("UNSUPPORTED_VERSION", "request protocol mismatch")
716
+ request["protocol"] = PROTOCOL
717
+ try:
718
+ raw = json.dumps(request, ensure_ascii=True, allow_nan=False, separators=(",", ":")).encode()
719
+ except (TypeError, ValueError) as exc:
720
+ raise ArtifactError("INVALID_REQUEST", "request must contain finite JSON values") from exc
721
+ if len(raw) > MAX_REQUEST:
722
+ raise ArtifactError("REQUEST_TOO_LARGE", "request exceeds 8 MiB")
723
+ fd = self._open_binary()
724
+ try:
725
+ # Execute the verified open descriptor, not a raceable pathname.
726
+ if platform.system() == "Linux":
727
+ executable = f"/proc/self/fd/{fd}"
728
+ elif platform.system() == "Darwin":
729
+ with tempfile.TemporaryDirectory(prefix="ca-artifact-exec-") as temporary:
730
+ try:
731
+ directory = Path(os.path.realpath(temporary))
732
+ executable = _stage_darwin_executable(fd, directory)
733
+ os.chmod(directory, stat.S_IRUSR | stat.S_IXUSR)
734
+ code, stdout, stderr = _bounded_child(
735
+ [str(executable), operation, "--root", str(self.root), "--request", "-"],
736
+ raw, fd, self.timeout)
737
+ except OSError as exc:
738
+ raise ArtifactError(
739
+ "CAPABILITY_MISSING",
740
+ "could not stage the verified macOS artifact executable",
741
+ ) from exc
742
+ finally:
743
+ os.chmod(directory, stat.S_IRWXU)
744
+ executable = None
745
+ else:
746
+ executable = str(self.installation / self._binary_name())
747
+ if executable is not None:
748
+ code, stdout, stderr = _bounded_child(
749
+ [executable, operation, "--root", str(self.root), "--request", "-"],
750
+ raw, fd, self.timeout)
751
+ finally:
752
+ os.close(fd)
753
+ result = _decode(stdout)
754
+ if not isinstance(result, dict) or result.get("protocol") != PROTOCOL or result.get("operation") != operation or not isinstance(result.get("ok"), bool):
755
+ raise ArtifactError("INVALID_RESPONSE", "subprocess response does not match request")
756
+ if not result["ok"]:
757
+ error = result.get("error")
758
+ if (set(result) != {"protocol", "operation", "ok", "error"}
759
+ or not isinstance(error, dict)
760
+ or not {"code", "message"} <= set(error)
761
+ or set(error) - {"code", "message", "symbol", "field", "operation_id"}
762
+ or any(not isinstance(v, str) for v in error.values())
763
+ or not re.fullmatch(r"[A-Z][A-Z0-9_]{0,79}", error["code"])
764
+ or code == 0):
765
+ raise ArtifactError("INVALID_RESPONSE", "malformed failure envelope")
766
+ raise ArtifactError(error["code"], error["message"][:512])
767
+ if set(result) != {"protocol", "operation", "ok", "result"} or not isinstance(result.get("result"), dict):
768
+ raise ArtifactError("INVALID_RESPONSE", "malformed success envelope")
769
+ if code != 0 and not (permit_invalid and operation == "validate" and code == 2 and result["result"].get("valid") is False):
770
+ raise ArtifactError("SUBPROCESS_FAILED", f"operation returned exit {code}")
771
+ if not isinstance(result.get("result"), dict):
772
+ raise ArtifactError("INVALID_RESPONSE", "subprocess result must be an object")
773
+ return result["result"]
774
+
775
+ @staticmethod
776
+ def _binary_name() -> str:
777
+ system = {"Linux":"linux", "Darwin":"darwin", "Windows":"windows"}[platform.system()]
778
+ arch = {"x86_64":"amd64", "amd64":"amd64", "aarch64":"arm64", "arm64":"arm64"}[platform.machine().lower()]
779
+ return f"ca-artifact-{system}-{arch}" + (".exe" if system == "windows" else "")
780
+
781
+ @staticmethod
782
+ def _check_page(page: dict, offset: int, field: str):
783
+ values = page.get(field)
784
+ if not isinstance(values, list) or "next_offset" not in page:
785
+ raise ArtifactError("INVALID_RESPONSE", "malformed bounded page")
786
+ next_offset = page["next_offset"]
787
+ if next_offset is not None and (type(next_offset) is not int or next_offset <= offset or not values):
788
+ raise ArtifactError("INVALID_RESPONSE", "pagination must make forward progress")
789
+
790
+ def index(self, kind: str | None = None):
791
+ request = {"budget": 16384}
792
+ if kind:
793
+ request["kind"] = kind
794
+ for _ in range(1025):
795
+ page = self.call("index", request)
796
+ self._check_page(page, request.get("offset", 0), "entries")
797
+ yield from page["entries"]
798
+ if page["next_offset"] is None:
799
+ return
800
+ request.update(offset=page["next_offset"], catalog_sha256=page["catalog_sha256"])
801
+ raise ArtifactError("INVALID_RESPONSE", "index did not terminate")
802
+
803
+ def outline(self, artifact_id: str):
804
+ request = {"artifact_id": artifact_id, "budget": 16384}
805
+ for _ in range(8193):
806
+ page = self.call("outline", request)
807
+ self._check_page(page, request.get("offset", 0), "records")
808
+ yield from page["records"]
809
+ if page["next_offset"] is None:
810
+ return
811
+ request.update(offset=page["next_offset"], model_sha256=page["model_sha256"])
812
+ raise ArtifactError("INVALID_RESPONSE", "outline did not terminate")
813
+
814
+ def contextual_pages(self, artifact_id: str, symbol: str, budget: int = 16384):
815
+ request = {"artifact_id": artifact_id, "symbol": symbol, "mode": "contextual", "budget": budget}
816
+ for _ in range(8193):
817
+ page = self.call("read", request)
818
+ complete = page.get("context_complete")
819
+ if type(complete) is not bool:
820
+ raise ArtifactError("INVALID_RESPONSE", "context page lacks a completeness flag")
821
+ if not complete and (not page.get("next_cursor") or page["next_cursor"] == request.get("cursor")):
822
+ raise ArtifactError("INCOMPLETE_CONTEXT", "incomplete context must have an advancing continuation")
823
+ yield page
824
+ if complete:
825
+ return
826
+ request["cursor"] = page["next_cursor"]
827
+ raise ArtifactError("INVALID_RESPONSE", "context did not terminate")
828
+
829
+
830
+ def has_html(root: str | Path) -> bool:
831
+ root = Path(root)
832
+ return any(
833
+ next((root / ".codearbiter" / kind).glob("*.html"), None) is not None for kind in ("specs", "plans"))
834
+
835
+
836
+ def checked_spec_index(root, installation) -> list[dict]:
837
+ """Fresh per-call authority validation, deliberately not an mtime cache."""
838
+ if not has_html(root):
839
+ return []
840
+ client = ArtifactClient(root, installation)
841
+ return [{"spec": x["artifact_id"], "path": x["path"], "globs": x.get("governs") or [], "artifact_html": True}
842
+ for x in client.index("spec") if x["authority"]["authority_verified"] and x.get("governs")]
843
+
844
+
845
+ def resolve_spec_file(filename, installation) -> tuple[ArtifactClient, dict]:
846
+ path = Path(filename).absolute()
847
+ if path.suffix != ".html" or path.parent.name != "specs" or path.parent.parent.name != ".codearbiter":
848
+ raise ArtifactError("INVALID_PATH", "expected canonical HTML spec path")
849
+ root = path.parent.parent.parent
850
+ client = ArtifactClient(root, installation)
851
+ relative = path.relative_to(root).as_posix()
852
+ matches = [x for x in client.index("spec") if x["path"] == relative]
853
+ if len(matches) != 1:
854
+ raise ArtifactError("SPEC_NOT_FOUND", "canonical path did not resolve uniquely")
855
+ return client, matches[0]