loki-mode 7.129.5 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +81 -5
  2. package/SKILL.md +66 -5
  3. package/VERSION +1 -1
  4. package/autonomy/app-runner.sh +37 -0
  5. package/autonomy/completion-council.sh +862 -28
  6. package/autonomy/council-v2.sh +39 -0
  7. package/autonomy/crash.sh +3 -2
  8. package/autonomy/grill.sh +42 -0
  9. package/autonomy/hooks/validate-bash.sh +301 -4
  10. package/autonomy/lib/cockpit-render.sh +8 -2
  11. package/autonomy/lib/cr-rematerialize.py +101 -4
  12. package/autonomy/lib/deadline.py +957 -0
  13. package/autonomy/lib/dependency-setup.sh +205 -0
  14. package/autonomy/lib/done-recognition.sh +45 -0
  15. package/autonomy/lib/efficiency_cost.py +13 -6
  16. package/autonomy/lib/no_mock_scan.py +793 -0
  17. package/autonomy/lib/prd-enrich.sh +42 -0
  18. package/autonomy/lib/proof-analytics-props.py +69 -0
  19. package/autonomy/lib/proof-generator.py +282 -95
  20. package/autonomy/lib/proof-template.html +15 -12
  21. package/autonomy/lib/proof-verify.py +151 -102
  22. package/autonomy/lib/requirements_contract.py +848 -0
  23. package/autonomy/lib/sdk-mode.sh +103 -0
  24. package/autonomy/lib/secret-scan.sh +139 -0
  25. package/autonomy/lib/spec-expand.sh +208 -0
  26. package/autonomy/lib/tree_digest.py +266 -0
  27. package/autonomy/lib/voter-agents.sh +58 -8
  28. package/autonomy/lib/workspace_diff.py +124 -0
  29. package/autonomy/loki +189 -17
  30. package/autonomy/playwright-verify.sh +501 -0
  31. package/autonomy/prd-checklist.sh +17 -8
  32. package/autonomy/provider-offer.sh +111 -0
  33. package/autonomy/run.sh +4417 -676
  34. package/autonomy/sandbox.sh +42 -0
  35. package/autonomy/spec-interrogation.sh +148 -5
  36. package/autonomy/spec.sh +118 -1
  37. package/autonomy/telemetry.sh +133 -7
  38. package/autonomy/verify.sh +107 -0
  39. package/bin/loki +110 -3
  40. package/completions/_loki +10 -0
  41. package/completions/loki.bash +1 -1
  42. package/dashboard/__init__.py +1 -1
  43. package/dashboard/audit.py +96 -7
  44. package/dashboard/build_supervisor.py +1619 -0
  45. package/dashboard/control.py +8 -0
  46. package/dashboard/prompt_optimizer.py +7 -0
  47. package/dashboard/server.py +577 -22
  48. package/dashboard/static/trust.html +1 -1
  49. package/docs/ARCHITECTURE-OVERVIEW.md +207 -0
  50. package/docs/AUTONOMI-ECOSYSTEM.md +107 -0
  51. package/docs/INSTALLATION.md +19 -2
  52. package/docs/MODEL-EQUIVALENCE-HARNESS-PLAN.md +70 -0
  53. package/docs/PLANS-INDEX.md +33 -0
  54. package/docs/PRIVACY.md +29 -1
  55. package/docs/SIGNED-RECEIPTS.md +102 -0
  56. package/docs/SONNET5-DEFAULT-PLAN.md +1 -1
  57. package/docs/V8-ACCEPTANCE-TRIAGE-2026-07-24.md +114 -0
  58. package/docs/V8-AGENT-SDK-PLAN.md +692 -0
  59. package/docs/V8-COMPLEXITY-AUDIT-2026-07-24.md +45 -0
  60. package/docs/V8-MAJOR-RELEASE-PLAN.md +137 -0
  61. package/docs/V8-OVERNIGHT-PLAN-2026-07-25.md +82 -0
  62. package/docs/V8-RUNTIME-TRUTH-2026-07-25.md +232 -0
  63. package/docs/V8-SDK-RESEARCH-RAW.md +129 -0
  64. package/docs/alternative-installations.md +4 -4
  65. package/loki-ts/dist/loki.js +674 -285
  66. package/loki-ts/package.json +2 -0
  67. package/mcp/__init__.py +1 -1
  68. package/package.json +7 -6
  69. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  70. package/providers/claude.sh +75 -0
  71. package/providers/codex.sh +85 -13
  72. package/references/sdk-mode.md +106 -0
  73. package/skills/model-selection.md +1 -1
  74. package/skills/quality-gates.md +22 -0
@@ -0,0 +1,848 @@
1
+ #!/usr/bin/env python3
2
+ """Bind an immutable specification to a structured requirement verdict schema."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import hashlib
7
+ import hmac
8
+ import json
9
+ import os
10
+ import re
11
+ import stat
12
+ import sys
13
+ from copy import deepcopy
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+
17
+
18
+ PRODUCT_QUALITY_CONTRACT_END = "--- END AUTONOMI PRODUCT QUALITY CONTRACT ---"
19
+ PRODUCT_QUALITY_REQUIREMENT_PREFIXES = (
20
+ "Every visible control must perform its stated action.",
21
+ "Do not ship dead forms,",
22
+ "If the user explicitly requests no backend,",
23
+ "Treat commercial claims as user-supplied,",
24
+ "Label illustrative material in the interface and omit unsupported customer logos,",
25
+ "Add or update at least one non-vacuous automated test for the critical path,",
26
+ )
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class Contract:
31
+ specification: bytes
32
+ manifest: dict[str, object]
33
+ schema: dict[str, object]
34
+
35
+ @property
36
+ def manifest_bytes(self) -> bytes:
37
+ return json.dumps(self.manifest, sort_keys=True).encode("utf-8")
38
+
39
+ @property
40
+ def schema_bytes(self) -> bytes:
41
+ return json.dumps(self.schema, sort_keys=True).encode("utf-8")
42
+
43
+
44
+ MAX_REQUIREMENTS_PER_SHARD = 8
45
+
46
+
47
+ def _shard_path(shard_dir: Path, kind: str, index: int) -> Path:
48
+ if kind not in {"manifest", "schema", "result"} or index < 1:
49
+ raise ValueError("invalid_shard")
50
+ suffix = "json" if kind in {"manifest", "schema"} else "txt"
51
+ return shard_dir / f"{kind}-{index:03d}.{suffix}"
52
+
53
+
54
+ def _validate_shard_size(raw_size: str | int) -> int:
55
+ text = str(raw_size)
56
+ if re.fullmatch(r"[0-9]+", text) is None:
57
+ raise ValueError("invalid_shard_size")
58
+ size = int(text, 10)
59
+ if not 1 <= size <= MAX_REQUIREMENTS_PER_SHARD:
60
+ raise ValueError("invalid_shard_size")
61
+ return size
62
+
63
+
64
+ def _safe_directory(path: Path) -> None:
65
+ try:
66
+ info = os.lstat(path)
67
+ except OSError as exc:
68
+ raise RuntimeError("unsafe_shard_directory") from exc
69
+ if (
70
+ not stat.S_ISDIR(info.st_mode)
71
+ or info.st_uid != os.getuid()
72
+ or stat.S_IMODE(info.st_mode) != 0o700
73
+ ):
74
+ raise RuntimeError("unsafe_shard_directory")
75
+
76
+
77
+ def extract_requirement_units(text: str) -> list[str]:
78
+ """Return deterministic acceptance units without interpreting product verbs."""
79
+ units: list[str] = []
80
+ paragraph: list[str] = []
81
+ list_item: list[str] = []
82
+
83
+ def flush_paragraph() -> None:
84
+ if not paragraph:
85
+ return
86
+ joined = " ".join(paragraph)
87
+ units.extend(
88
+ part.strip()
89
+ for part in re.split(r"(?<=[.!?])\s+(?=[A-Z0-9])", joined)
90
+ if part.strip()
91
+ )
92
+ paragraph.clear()
93
+
94
+ def flush_item() -> None:
95
+ if list_item:
96
+ units.append(" ".join(list_item))
97
+ list_item.clear()
98
+
99
+ for raw_line in text.splitlines():
100
+ line = raw_line.strip()
101
+ if not line:
102
+ flush_item()
103
+ flush_paragraph()
104
+ continue
105
+ heading = re.fullmatch(r"#{1,6}\s+(.+)", line)
106
+ if heading:
107
+ flush_item()
108
+ flush_paragraph()
109
+ units.append(heading.group(1).strip())
110
+ continue
111
+ item = re.match(
112
+ r"^(?:[-*+]\s+(?:\[[ xX]\]\s*)?|\d+[.)]\s+)(.+)$", line
113
+ )
114
+ if item:
115
+ flush_item()
116
+ flush_paragraph()
117
+ list_item.append(item.group(1).strip())
118
+ elif list_item and raw_line[:1].isspace():
119
+ list_item.append(line)
120
+ else:
121
+ flush_item()
122
+ paragraph.append(line)
123
+ flush_item()
124
+ flush_paragraph()
125
+ return units
126
+
127
+
128
+ def extract_bound_requirement_units(text: str) -> list[str]:
129
+ """Extract the user brief when a platform quality policy precedes it."""
130
+ if PRODUCT_QUALITY_CONTRACT_END in text:
131
+ text = text.split(PRODUCT_QUALITY_CONTRACT_END, 1)[1].strip()
132
+ return extract_requirement_units(text)
133
+
134
+
135
+ def extract_product_quality_requirement_units(text: str) -> list[str]:
136
+ """Select the mandatory review rules from a wrapped product quality policy."""
137
+ if PRODUCT_QUALITY_CONTRACT_END not in text:
138
+ return []
139
+ policy = text.split(PRODUCT_QUALITY_CONTRACT_END, 1)[0]
140
+ units = extract_requirement_units(policy)
141
+ selected: list[str] = []
142
+ for prefix in PRODUCT_QUALITY_REQUIREMENT_PREFIXES:
143
+ matches = [unit for unit in units if unit.startswith(prefix)]
144
+ if len(matches) != 1:
145
+ raise LookupError("incomplete_product_quality_contract")
146
+ selected.append(matches[0])
147
+ return selected
148
+
149
+
150
+ def _schema(spec_sha256: str, ids: list[str], count: int) -> dict[str, object]:
151
+ return {
152
+ "$schema": "http://json-schema.org/draft-07/schema#",
153
+ "type": "object",
154
+ "additionalProperties": False,
155
+ "required": [
156
+ "schema",
157
+ "spec_sha256",
158
+ "verdict",
159
+ "requirements",
160
+ "findings",
161
+ ],
162
+ "properties": {
163
+ "schema": {"const": "loki-requirements-verdict/v1"},
164
+ "spec_sha256": {"const": spec_sha256},
165
+ "verdict": {"enum": ["PASS", "FAIL"]},
166
+ "requirements": {
167
+ "type": "array",
168
+ "minItems": count,
169
+ "maxItems": count,
170
+ "items": {
171
+ "type": "object",
172
+ "additionalProperties": False,
173
+ "required": ["id", "status", "evidence"],
174
+ "properties": {
175
+ "id": {"enum": ids},
176
+ "status": {"enum": ["PASS", "FAIL"]},
177
+ "evidence": {
178
+ "type": "string",
179
+ "minLength": 1,
180
+ "maxLength": 180,
181
+ },
182
+ },
183
+ },
184
+ },
185
+ "findings": {
186
+ "type": "array",
187
+ "items": {
188
+ "type": "object",
189
+ "additionalProperties": False,
190
+ "required": ["severity", "description"],
191
+ "properties": {
192
+ "severity": {
193
+ "enum": ["Critical", "High", "Medium", "Low"]
194
+ },
195
+ "description": {
196
+ "type": "string",
197
+ "minLength": 1,
198
+ "maxLength": 320,
199
+ },
200
+ },
201
+ },
202
+ },
203
+ },
204
+ }
205
+
206
+
207
+ def _limit(raw_limit: str, hard_limit: int) -> int:
208
+ if re.fullmatch(r"[0-9]+", raw_limit) is None:
209
+ raise ValueError("invalid_limit")
210
+ limit = int(raw_limit, 10)
211
+ if not 1 <= limit <= hard_limit:
212
+ raise ValueError("invalid_limit")
213
+ return limit
214
+
215
+
216
+ def _read_regular(
217
+ path: Path, maximum: int, *, exact_mode: int | None = None
218
+ ) -> bytes:
219
+ flags = os.O_RDONLY
220
+ if hasattr(os, "O_NOFOLLOW"):
221
+ flags |= os.O_NOFOLLOW
222
+ if hasattr(os, "O_CLOEXEC"):
223
+ flags |= os.O_CLOEXEC
224
+ try:
225
+ descriptor = os.open(path, flags)
226
+ info = os.fstat(descriptor)
227
+ path_info = os.lstat(path)
228
+ if (
229
+ not stat.S_ISREG(info.st_mode)
230
+ or not stat.S_ISREG(path_info.st_mode)
231
+ or info.st_uid != os.getuid()
232
+ or info.st_nlink != 1
233
+ or (
234
+ exact_mode is not None
235
+ and stat.S_IMODE(info.st_mode) != exact_mode
236
+ )
237
+ or (info.st_dev, info.st_ino) != (path_info.st_dev, path_info.st_ino)
238
+ ):
239
+ raise RuntimeError("unsafe_file")
240
+ content = bytearray()
241
+ while len(content) <= maximum:
242
+ chunk = os.read(descriptor, min(65_536, maximum + 1 - len(content)))
243
+ if not chunk:
244
+ break
245
+ content.extend(chunk)
246
+ final_info = os.fstat(descriptor)
247
+ final_path_info = os.lstat(path)
248
+ if (
249
+ (info.st_dev, info.st_ino) != (final_info.st_dev, final_info.st_ino)
250
+ or (info.st_dev, info.st_ino)
251
+ != (final_path_info.st_dev, final_path_info.st_ino)
252
+ ):
253
+ raise RuntimeError("replaced_file")
254
+ except OSError as exc:
255
+ raise RuntimeError("unreadable") from exc
256
+ finally:
257
+ if "descriptor" in locals():
258
+ os.close(descriptor)
259
+ if len(content) > maximum:
260
+ raise OverflowError(f"oversized:{len(content)}")
261
+ return bytes(content)
262
+
263
+
264
+ def _path_identity(path: Path, *, exact_mode: int = 0o600) -> str:
265
+ flags = os.O_RDONLY
266
+ if hasattr(os, "O_NOFOLLOW"):
267
+ flags |= os.O_NOFOLLOW
268
+ if hasattr(os, "O_CLOEXEC"):
269
+ flags |= os.O_CLOEXEC
270
+ try:
271
+ descriptor = os.open(path, flags)
272
+ info = os.fstat(descriptor)
273
+ path_info = os.lstat(path)
274
+ except OSError as exc:
275
+ raise RuntimeError("unreadable") from exc
276
+ finally:
277
+ if "descriptor" in locals():
278
+ os.close(descriptor)
279
+ if (
280
+ not stat.S_ISREG(info.st_mode)
281
+ or not stat.S_ISREG(path_info.st_mode)
282
+ or info.st_uid != os.getuid()
283
+ or info.st_nlink != 1
284
+ or stat.S_IMODE(info.st_mode) != exact_mode
285
+ or (info.st_dev, info.st_ino) != (path_info.st_dev, path_info.st_ino)
286
+ ):
287
+ raise RuntimeError("unsafe_file")
288
+ return f"{info.st_dev}:{info.st_ino}"
289
+
290
+
291
+ def artifact_identity(*paths: Path) -> str:
292
+ return ",".join(_path_identity(path) for path in paths)
293
+
294
+
295
+ def _write_new(path: Path, content: bytes) -> None:
296
+ flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
297
+ if hasattr(os, "O_NOFOLLOW"):
298
+ flags |= os.O_NOFOLLOW
299
+ if hasattr(os, "O_CLOEXEC"):
300
+ flags |= os.O_CLOEXEC
301
+ try:
302
+ descriptor = os.open(path, flags, 0o600)
303
+ os.fchmod(descriptor, 0o600)
304
+ view = memoryview(content)
305
+ while view:
306
+ written = os.write(descriptor, view)
307
+ if written <= 0:
308
+ raise OSError("short write")
309
+ view = view[written:]
310
+ info = os.fstat(descriptor)
311
+ path_info = os.lstat(path)
312
+ if (
313
+ not stat.S_ISREG(info.st_mode)
314
+ or info.st_uid != os.getuid()
315
+ or stat.S_IMODE(info.st_mode) != 0o600
316
+ or info.st_nlink != 1
317
+ or (info.st_dev, info.st_ino) != (path_info.st_dev, path_info.st_ino)
318
+ ):
319
+ raise RuntimeError("unsafe_file")
320
+ except FileExistsError:
321
+ if not hmac.compare_digest(
322
+ _read_regular(path, len(content), exact_mode=0o600), content
323
+ ):
324
+ raise RuntimeError("contract_mismatch")
325
+ return
326
+ except OSError as exc:
327
+ raise RuntimeError("contract_write_failed") from exc
328
+ finally:
329
+ if "descriptor" in locals():
330
+ os.close(descriptor)
331
+
332
+
333
+ def publish_bound(stage: Path, destination: Path, maximum: int) -> str:
334
+ """Publish one validated staged result after its producer has quiesced."""
335
+ content = _read_regular(stage, maximum)
336
+ if not content:
337
+ raise RuntimeError("empty_file")
338
+ try:
339
+ destination_info = os.lstat(destination)
340
+ except FileNotFoundError:
341
+ destination_info = None
342
+ if destination_info is not None:
343
+ if stat.S_ISDIR(destination_info.st_mode):
344
+ raise RuntimeError("unsafe_destination")
345
+ os.unlink(destination)
346
+ os.replace(stage, destination)
347
+ published = _read_regular(destination, maximum)
348
+ if not hmac.compare_digest(content, published):
349
+ raise RuntimeError("publish_mismatch")
350
+ return (
351
+ hashlib.sha256(published).hexdigest()
352
+ + "|"
353
+ + _path_identity(destination)
354
+ )
355
+
356
+
357
+ def derive_contract(
358
+ source: Path,
359
+ expected_sha256: str,
360
+ raw_limit: str,
361
+ hard_limit: int,
362
+ ) -> Contract:
363
+ limit = _limit(raw_limit, hard_limit)
364
+ content = _read_regular(source, limit)
365
+ actual_sha256 = hashlib.sha256(content).hexdigest()
366
+ if not hmac.compare_digest(actual_sha256, expected_sha256):
367
+ raise PermissionError("hash_mismatch")
368
+ try:
369
+ text = content.decode("utf-8")
370
+ except UnicodeDecodeError as exc:
371
+ raise UnicodeError("invalid_utf8") from exc
372
+ units = extract_bound_requirement_units(text)
373
+ quality_units = extract_product_quality_requirement_units(text)
374
+ if not units:
375
+ raise LookupError("no_requirements")
376
+ requirements = [
377
+ {
378
+ "id": f"R{index:03d}",
379
+ "text": unit,
380
+ "sha256": hashlib.sha256(unit.encode("utf-8")).hexdigest(),
381
+ }
382
+ for index, unit in enumerate(units, 1)
383
+ ]
384
+ requirements.extend(
385
+ {
386
+ "id": f"Q{index:03d}",
387
+ "text": unit,
388
+ "sha256": hashlib.sha256(unit.encode("utf-8")).hexdigest(),
389
+ }
390
+ for index, unit in enumerate(quality_units, 1)
391
+ )
392
+ manifest = {
393
+ "schema": "loki-requirements-manifest/v1",
394
+ "spec_sha256": actual_sha256,
395
+ "requirements": requirements,
396
+ }
397
+ return Contract(
398
+ specification=content,
399
+ manifest=manifest,
400
+ schema=_schema(
401
+ actual_sha256,
402
+ [item["id"] for item in requirements],
403
+ len(requirements),
404
+ ),
405
+ )
406
+
407
+
408
+ def derive_shards(contract: Contract, raw_size: str | int) -> list[Contract]:
409
+ """Split one verified contract into deterministic balanced contiguous shards."""
410
+ maximum = _validate_shard_size(raw_size)
411
+ requirements = contract.manifest.get("requirements")
412
+ if not isinstance(requirements, list) or not requirements:
413
+ raise RuntimeError("invalid_full_contract")
414
+ total = len(requirements)
415
+ shard_count = (total + maximum - 1) // maximum
416
+ base_size, extra = divmod(total, shard_count)
417
+ full_manifest_sha256 = hashlib.sha256(contract.manifest_bytes).hexdigest()
418
+ shards: list[Contract] = []
419
+ offset = 0
420
+ for zero_index in range(shard_count):
421
+ shard_size = base_size + (1 if zero_index < extra else 0)
422
+ selected = deepcopy(requirements[offset : offset + shard_size])
423
+ ids = [item.get("id") for item in selected if isinstance(item, dict)]
424
+ if len(ids) != shard_size or any(not isinstance(item, str) for item in ids):
425
+ raise RuntimeError("invalid_full_contract")
426
+ manifest = {
427
+ "schema": "loki-requirements-manifest/v1",
428
+ "spec_sha256": contract.manifest["spec_sha256"],
429
+ "requirements": selected,
430
+ "shard": {
431
+ "schema": "loki-requirements-shard/v1",
432
+ "index": zero_index + 1,
433
+ "count": shard_count,
434
+ "max_requirements": maximum,
435
+ "requirement_offset": offset,
436
+ "full_requirement_count": total,
437
+ "full_manifest_sha256": full_manifest_sha256,
438
+ },
439
+ }
440
+ shards.append(
441
+ Contract(
442
+ specification=contract.specification,
443
+ manifest=manifest,
444
+ schema=_schema(contract.manifest["spec_sha256"], ids, shard_size),
445
+ )
446
+ )
447
+ offset += shard_size
448
+ if offset != total:
449
+ raise RuntimeError("incomplete_shards")
450
+ return shards
451
+
452
+
453
+ def write_shards(
454
+ contract: Contract,
455
+ raw_size: str,
456
+ shard_dir: Path,
457
+ ) -> dict[str, object]:
458
+ _safe_directory(shard_dir)
459
+ shards = derive_shards(contract, raw_size)
460
+ identities: list[str] = []
461
+ sizes: list[int] = []
462
+ for index, shard in enumerate(shards, 1):
463
+ manifest_path = _shard_path(shard_dir, "manifest", index)
464
+ schema_path = _shard_path(shard_dir, "schema", index)
465
+ _write_new(manifest_path, shard.manifest_bytes)
466
+ _write_new(schema_path, shard.schema_bytes)
467
+ identities.append(artifact_identity(manifest_path, schema_path))
468
+ sizes.append(len(shard.manifest["requirements"]))
469
+ return {
470
+ "schema": "loki-requirements-shards/v1",
471
+ "count": len(shards),
472
+ "max_requirements": _validate_shard_size(raw_size),
473
+ "sizes": sizes,
474
+ "identities": identities,
475
+ "full_manifest_sha256": hashlib.sha256(contract.manifest_bytes).hexdigest(),
476
+ }
477
+
478
+
479
+ def verify_shard(
480
+ contract: Contract,
481
+ raw_size: str,
482
+ shard_dir: Path,
483
+ index: int,
484
+ expected_identity: str = "",
485
+ ) -> Contract:
486
+ _safe_directory(shard_dir)
487
+ shards = derive_shards(contract, raw_size)
488
+ if index < 1 or index > len(shards):
489
+ raise ValueError("invalid_shard")
490
+ shard = shards[index - 1]
491
+ manifest_path = _shard_path(shard_dir, "manifest", index)
492
+ schema_path = _shard_path(shard_dir, "schema", index)
493
+ for path, expected in (
494
+ (manifest_path, shard.manifest_bytes),
495
+ (schema_path, shard.schema_bytes),
496
+ ):
497
+ actual = _read_regular(path, len(expected), exact_mode=0o600)
498
+ if not hmac.compare_digest(actual, expected):
499
+ raise RuntimeError("shard_contract_mismatch")
500
+ actual_identity = artifact_identity(manifest_path, schema_path)
501
+ if expected_identity and not hmac.compare_digest(
502
+ actual_identity, expected_identity
503
+ ):
504
+ raise RuntimeError("shard_contract_replaced")
505
+ return shard
506
+
507
+
508
+ def _decode_json_list(raw: str, expected_count: int) -> list[str]:
509
+ try:
510
+ value = json.loads(raw)
511
+ except json.JSONDecodeError as exc:
512
+ raise ValueError("invalid_binding_list") from exc
513
+ if (
514
+ not isinstance(value, list)
515
+ or len(value) != expected_count
516
+ or not all(isinstance(item, str) and item for item in value)
517
+ ):
518
+ raise ValueError("invalid_binding_list")
519
+ return value
520
+
521
+
522
+ def _read_bound_result(path: Path, binding: str, maximum: int) -> bytes:
523
+ try:
524
+ expected_sha256, expected_identity = binding.split("|", 1)
525
+ except ValueError as exc:
526
+ raise ValueError("invalid_result_binding") from exc
527
+ if re.fullmatch(r"[0-9a-f]{64}", expected_sha256) is None:
528
+ raise ValueError("invalid_result_binding")
529
+ content = _read_regular(path, maximum, exact_mode=0o600)
530
+ if not hmac.compare_digest(hashlib.sha256(content).hexdigest(), expected_sha256):
531
+ raise RuntimeError("result_mismatch")
532
+ if not hmac.compare_digest(_path_identity(path), expected_identity):
533
+ raise RuntimeError("result_replaced")
534
+ return content
535
+
536
+
537
+ def _parse_legacy_result(content: bytes) -> tuple[str, list[str]]:
538
+ try:
539
+ text = content.decode("utf-8")
540
+ except UnicodeDecodeError as exc:
541
+ raise ValueError("invalid_result") from exc
542
+ lines = text.splitlines()
543
+ if (
544
+ len(lines) < 3
545
+ or lines[0] not in {"VERDICT: PASS", "VERDICT: FAIL"}
546
+ or lines[1] != "FINDINGS:"
547
+ or any(not line.startswith("- ") or len(line) <= 2 for line in lines[2:])
548
+ ):
549
+ raise ValueError("invalid_result")
550
+ findings = lines[2:]
551
+ if "- None" in findings and findings != ["- None"]:
552
+ raise ValueError("invalid_result")
553
+ verdict = lines[0].removeprefix("VERDICT: ")
554
+ if verdict == "PASS" and findings != ["- None"]:
555
+ raise ValueError("invalid_result")
556
+ return verdict, findings
557
+
558
+
559
+ def synthesize_shards(
560
+ contract: Contract,
561
+ raw_size: str,
562
+ shard_dir: Path,
563
+ contract_identities_json: str,
564
+ result_bindings_json: str,
565
+ maximum: int,
566
+ destination: Path,
567
+ ) -> str:
568
+ """Create one logical verdict only after every exact shard result is bound."""
569
+ shards = derive_shards(contract, raw_size)
570
+ contract_identities = _decode_json_list(
571
+ contract_identities_json, len(shards)
572
+ )
573
+ result_bindings = _decode_json_list(result_bindings_json, len(shards))
574
+ verdicts: list[str] = []
575
+ findings: list[str] = []
576
+ for index, (contract_identity, result_binding) in enumerate(
577
+ zip(contract_identities, result_bindings, strict=True), 1
578
+ ):
579
+ verify_shard(contract, raw_size, shard_dir, index, contract_identity)
580
+ result_path = _shard_path(shard_dir, "result", index)
581
+ verdict, shard_findings = _parse_legacy_result(
582
+ _read_bound_result(result_path, result_binding, maximum)
583
+ )
584
+ verdicts.append(verdict)
585
+ if shard_findings != ["- None"]:
586
+ findings.extend(shard_findings)
587
+ logical_verdict = "PASS" if all(item == "PASS" for item in verdicts) else "FAIL"
588
+ logical_findings = findings or ["- None"]
589
+ logical = (
590
+ "VERDICT: "
591
+ + logical_verdict
592
+ + "\nFINDINGS:\n"
593
+ + "\n".join(logical_findings)
594
+ + "\n"
595
+ ).encode("utf-8")
596
+ _write_new(destination, logical)
597
+ return hashlib.sha256(logical).hexdigest() + "|" + _path_identity(destination)
598
+
599
+
600
+ def synthesize_failed_shard(
601
+ contract: Contract,
602
+ raw_size: str,
603
+ shard_dir: Path,
604
+ index: int,
605
+ contract_identity: str,
606
+ result_binding: str,
607
+ maximum: int,
608
+ destination: Path,
609
+ ) -> str:
610
+ """Publish one exact valid FAIL without waiting for irrelevant PASS shards."""
611
+ verify_shard(contract, raw_size, shard_dir, index, contract_identity)
612
+ content = _read_bound_result(
613
+ _shard_path(shard_dir, "result", index), result_binding, maximum
614
+ )
615
+ verdict, _ = _parse_legacy_result(content)
616
+ if verdict != "FAIL":
617
+ raise RuntimeError("shard_did_not_fail")
618
+ _write_new(destination, content)
619
+ return hashlib.sha256(content).hexdigest() + "|" + _path_identity(destination)
620
+
621
+
622
+ def verify_contract(
623
+ source: Path,
624
+ snapshot: Path,
625
+ expected_sha256: str,
626
+ raw_limit: str,
627
+ hard_limit: int,
628
+ manifest_path: Path,
629
+ schema_path: Path,
630
+ expected_identity: str = "",
631
+ ) -> Contract:
632
+ contract = derive_contract(source, expected_sha256, raw_limit, hard_limit)
633
+ for path, expected in (
634
+ (snapshot, contract.specification),
635
+ (manifest_path, contract.manifest_bytes),
636
+ (schema_path, contract.schema_bytes),
637
+ ):
638
+ actual = _read_regular(path, len(expected), exact_mode=0o600)
639
+ if not hmac.compare_digest(actual, expected):
640
+ raise RuntimeError("contract_mismatch")
641
+ actual_identity = artifact_identity(snapshot, manifest_path, schema_path)
642
+ if expected_identity and not hmac.compare_digest(
643
+ actual_identity, expected_identity
644
+ ):
645
+ raise RuntimeError("contract_replaced")
646
+ return contract
647
+
648
+
649
+ def write_contract(
650
+ source: Path,
651
+ snapshot: Path,
652
+ expected_sha256: str,
653
+ raw_limit: str,
654
+ hard_limit: int,
655
+ manifest_path: Path,
656
+ schema_path: Path,
657
+ ) -> str:
658
+ contract = derive_contract(source, expected_sha256, raw_limit, hard_limit)
659
+ try:
660
+ _write_new(snapshot, contract.specification)
661
+ _write_new(manifest_path, contract.manifest_bytes)
662
+ _write_new(schema_path, contract.schema_bytes)
663
+ except RuntimeError:
664
+ raise
665
+ return f"ok:{len(contract.specification)}"
666
+
667
+
668
+ def _emit(contract: Contract, kind: str) -> None:
669
+ if kind == "snapshot":
670
+ sys.stdout.buffer.write(contract.specification)
671
+ elif kind == "manifest":
672
+ sys.stdout.buffer.write(contract.manifest_bytes)
673
+ elif kind == "schema":
674
+ sys.stdout.buffer.write(contract.schema_bytes)
675
+ elif kind == "prompt":
676
+ sys.stdout.write(
677
+ json.dumps(
678
+ {
679
+ "manifest": contract.manifest,
680
+ "schema": contract.schema,
681
+ "specification": contract.specification.decode("utf-8"),
682
+ },
683
+ sort_keys=True,
684
+ )
685
+ )
686
+ elif kind != "none":
687
+ raise ValueError("invalid_emit")
688
+
689
+
690
+ def main(argv: list[str]) -> int:
691
+ try:
692
+ if len(argv) == 5 and argv[1] == "publish-bound":
693
+ maximum = _limit(argv[4], int(argv[4]))
694
+ sys.stdout.write(
695
+ publish_bound(Path(argv[2]), Path(argv[3]), maximum)
696
+ )
697
+ elif len(argv) in (10, 11) and argv[1] == "verify":
698
+ contract = verify_contract(
699
+ Path(argv[2]),
700
+ Path(argv[3]),
701
+ argv[4],
702
+ argv[5],
703
+ int(argv[6]),
704
+ Path(argv[7]),
705
+ Path(argv[8]),
706
+ argv[10] if len(argv) == 11 else "",
707
+ )
708
+ _emit(contract, argv[9])
709
+ elif len(argv) == 9 and argv[1] == "bind":
710
+ verify_contract(
711
+ Path(argv[2]),
712
+ Path(argv[3]),
713
+ argv[4],
714
+ argv[5],
715
+ int(argv[6]),
716
+ Path(argv[7]),
717
+ Path(argv[8]),
718
+ )
719
+ sys.stdout.write(
720
+ artifact_identity(Path(argv[3]), Path(argv[7]), Path(argv[8]))
721
+ )
722
+ elif len(argv) in (5, 6) and argv[1] == "read-bound":
723
+ maximum = _limit(argv[4], int(argv[4]))
724
+ content = _read_regular(Path(argv[2]), maximum, exact_mode=0o600)
725
+ if not hmac.compare_digest(hashlib.sha256(content).hexdigest(), argv[3]):
726
+ raise PermissionError("hash_mismatch")
727
+ if len(argv) == 6 and not hmac.compare_digest(
728
+ _path_identity(Path(argv[2])), argv[5]
729
+ ):
730
+ raise RuntimeError("replaced_file")
731
+ sys.stdout.buffer.write(content)
732
+ elif len(argv) == 12 and argv[1] == "write-shards":
733
+ contract = verify_contract(
734
+ Path(argv[2]),
735
+ Path(argv[3]),
736
+ argv[4],
737
+ argv[5],
738
+ int(argv[6]),
739
+ Path(argv[7]),
740
+ Path(argv[8]),
741
+ argv[9],
742
+ )
743
+ sys.stdout.write(
744
+ json.dumps(
745
+ write_shards(contract, argv[10], Path(argv[11])),
746
+ sort_keys=True,
747
+ )
748
+ )
749
+ elif len(argv) == 15 and argv[1] == "verify-shard":
750
+ contract = verify_contract(
751
+ Path(argv[2]),
752
+ Path(argv[3]),
753
+ argv[4],
754
+ argv[5],
755
+ int(argv[6]),
756
+ Path(argv[7]),
757
+ Path(argv[8]),
758
+ argv[9],
759
+ )
760
+ shard = verify_shard(
761
+ contract,
762
+ argv[10],
763
+ Path(argv[11]),
764
+ int(argv[12]),
765
+ argv[14],
766
+ )
767
+ _emit(shard, argv[13])
768
+ elif len(argv) == 16 and argv[1] == "synthesize-shards":
769
+ contract = verify_contract(
770
+ Path(argv[2]),
771
+ Path(argv[3]),
772
+ argv[4],
773
+ argv[5],
774
+ int(argv[6]),
775
+ Path(argv[7]),
776
+ Path(argv[8]),
777
+ argv[9],
778
+ )
779
+ maximum = _limit(argv[14], int(argv[14]))
780
+ sys.stdout.write(
781
+ synthesize_shards(
782
+ contract,
783
+ argv[10],
784
+ Path(argv[11]),
785
+ argv[12],
786
+ argv[13],
787
+ maximum,
788
+ Path(argv[15]),
789
+ )
790
+ )
791
+ elif len(argv) == 17 and argv[1] == "synthesize-fail":
792
+ contract = verify_contract(
793
+ Path(argv[2]),
794
+ Path(argv[3]),
795
+ argv[4],
796
+ argv[5],
797
+ int(argv[6]),
798
+ Path(argv[7]),
799
+ Path(argv[8]),
800
+ argv[9],
801
+ )
802
+ maximum = _limit(argv[15], int(argv[15]))
803
+ sys.stdout.write(
804
+ synthesize_failed_shard(
805
+ contract,
806
+ argv[10],
807
+ Path(argv[11]),
808
+ int(argv[12]),
809
+ argv[13],
810
+ argv[14],
811
+ maximum,
812
+ Path(argv[16]),
813
+ )
814
+ )
815
+ elif len(argv) == 8:
816
+ print(
817
+ write_contract(
818
+ Path(argv[1]),
819
+ Path(argv[2]),
820
+ argv[3],
821
+ argv[4],
822
+ int(argv[5]),
823
+ Path(argv[6]),
824
+ Path(argv[7]),
825
+ )
826
+ )
827
+ else:
828
+ return 9
829
+ return 0
830
+ except OverflowError as exc:
831
+ print(str(exc))
832
+ return 4
833
+ except PermissionError:
834
+ print("hash_mismatch")
835
+ return 5
836
+ except UnicodeError as exc:
837
+ print(str(exc))
838
+ return 9
839
+ except ValueError:
840
+ print("invalid_limit")
841
+ return 2
842
+ except (OSError, RuntimeError, LookupError) as exc:
843
+ print(str(exc))
844
+ return 9
845
+
846
+
847
+ if __name__ == "__main__":
848
+ raise SystemExit(main(sys.argv))