core-runtime-engine 11.5.1__py3-none-any.whl

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 (96) hide show
  1. core_runtime/__init__.py +10 -0
  2. core_runtime/__version__.py +17 -0
  3. core_runtime/cli/__init__.py +7 -0
  4. core_runtime/cli/__main__.py +22 -0
  5. core_runtime/cli/bump_version.py +176 -0
  6. core_runtime/cli/contract_preflight.py +69 -0
  7. core_runtime/cli/create_domain.py +66 -0
  8. core_runtime/cli/doctor.py +44 -0
  9. core_runtime/cli/inventory.py +85 -0
  10. core_runtime/cli/lint.py +8 -0
  11. core_runtime/cli/main.py +579 -0
  12. core_runtime/cli/release_check.py +65 -0
  13. core_runtime/cli/repair_artifact_paths.py +48 -0
  14. core_runtime/cli/sync_template.py +67 -0
  15. core_runtime/cli/validate.py +73 -0
  16. core_runtime/core/__init__.py +34 -0
  17. core_runtime/core/audit_event.py +760 -0
  18. core_runtime/core/audit_trail_index.py +100 -0
  19. core_runtime/core/canonicalization.py +55 -0
  20. core_runtime/core/contract_evaluator.py +945 -0
  21. core_runtime/core/contract_executability.py +307 -0
  22. core_runtime/core/contract_loader.py +57 -0
  23. core_runtime/core/contract_probes.py +630 -0
  24. core_runtime/core/contract_program.py +131 -0
  25. core_runtime/core/contract_program_registry.py +104 -0
  26. core_runtime/core/contract_program_v2.py +126 -0
  27. core_runtime/core/dsk_v3.py +142 -0
  28. core_runtime/core/explainability.py +2115 -0
  29. core_runtime/core/numeric_normalization.py +120 -0
  30. core_runtime/core/rule_anchor.py +1388 -0
  31. core_runtime/core/schema_fingerprint.py +69 -0
  32. core_runtime/core/sensor_evidence.py +548 -0
  33. core_runtime/data/contracts/CoreAnchor.sol +109 -0
  34. core_runtime/data/contracts/CoreRuleAnchor.abi.json +111 -0
  35. core_runtime/data/contracts/CoreRuleAnchor.bin +1 -0
  36. core_runtime/data/contracts/CoreRuleAnchor.build.json +20 -0
  37. core_runtime/data/contracts/CoreRuleAnchor.runtime.bin +1 -0
  38. core_runtime/data/contracts/CoreRuleAnchor.sol +74 -0
  39. core_runtime/data/package_data_manifest.v1.json +173 -0
  40. core_runtime/data/schemas/core/causal_trace.v1.json +141 -0
  41. core_runtime/data/schemas/core/context_gate.v1.json +38 -0
  42. core_runtime/data/schemas/core/context_threshold.v1.json +46 -0
  43. core_runtime/data/schemas/core/contract_program.v1.json +186 -0
  44. core_runtime/data/schemas/core/contract_program.v2.json +187 -0
  45. core_runtime/data/schemas/core/control_decision.v1.json +114 -0
  46. core_runtime/data/schemas/core/dsk.v3.json +105 -0
  47. core_runtime/data/schemas/core/effect_result.v1.json +39 -0
  48. core_runtime/data/schemas/core/entropy_signal.v1.json +108 -0
  49. core_runtime/data/schemas/core/execution_receipt.v1.json +93 -0
  50. core_runtime/data/schemas/core/frozen_release_manifest.v1.json +87 -0
  51. core_runtime/data/schemas/core/frozen_release_manifest.v2.json +72 -0
  52. core_runtime/data/schemas/core/frozen_release_manifest.v3.json +38 -0
  53. core_runtime/data/schemas/core/frozen_release_manifest.v4.json +72 -0
  54. core_runtime/data/schemas/core/frozen_release_manifest.v5.json +38 -0
  55. core_runtime/data/schemas/core/frozen_release_manifest.v6.json +116 -0
  56. core_runtime/data/schemas/core/frozen_release_manifest.v7.json +37 -0
  57. core_runtime/data/schemas/core/frozen_release_manifest.v8.json +114 -0
  58. core_runtime/data/schemas/core/frozen_rule_set.v1.json +282 -0
  59. core_runtime/data/schemas/core/memory_artifact.v1.json +120 -0
  60. core_runtime/data/schemas/core/memory_generation_result.v1.json +37 -0
  61. core_runtime/data/schemas/core/operational_learning_event.v1.json +63 -0
  62. core_runtime/data/schemas/core/pattern_candidate.v1.json +114 -0
  63. core_runtime/data/schemas/core/physical_safety_assurance_case.v1.json +676 -0
  64. core_runtime/data/schemas/core/policy_lifecycle.v1.json +99 -0
  65. core_runtime/data/schemas/core/retention_manifest.v1.json +53 -0
  66. core_runtime/data/schemas/core/reversibility_policy.v1.json +107 -0
  67. core_runtime/data/schemas/core/rule_anchor_batch.v1.json +93 -0
  68. core_runtime/data/schemas/core/rule_anchor_chain_evidence.v1.json +56 -0
  69. core_runtime/data/schemas/core/rule_approval.v1.json +49 -0
  70. core_runtime/data/schemas/core/rule_approval_request.v1.json +42 -0
  71. core_runtime/data/schemas/core/state_transition.v1.json +115 -0
  72. core_runtime/data/schemas/core/task_closeout.v1.json +47 -0
  73. core_runtime/data/schemas/core/template_promotion_candidate.v1.json +83 -0
  74. core_runtime/data/schemas/core/unsigned_rule_anchor_deployment.v1.json +106 -0
  75. core_runtime/data/schemas/core/unsigned_rule_anchor_transaction.v1.json +116 -0
  76. core_runtime/tooling/__init__.py +48 -0
  77. core_runtime/tooling/bump_version.py +900 -0
  78. core_runtime/tooling/contract_preflight.py +293 -0
  79. core_runtime/tooling/create_domain.py +254 -0
  80. core_runtime/tooling/diagnostics.py +129 -0
  81. core_runtime/tooling/doctor.py +482 -0
  82. core_runtime/tooling/file_inventory.py +182 -0
  83. core_runtime/tooling/json_checks.py +100 -0
  84. core_runtime/tooling/release_check.py +1017 -0
  85. core_runtime/tooling/repair_artifact_paths.py +458 -0
  86. core_runtime/tooling/report_writer.py +176 -0
  87. core_runtime/tooling/repository_inventory.py +399 -0
  88. core_runtime/tooling/safety_checks.py +172 -0
  89. core_runtime/tooling/sync_template.py +303 -0
  90. core_runtime/tooling/validation.py +507 -0
  91. core_runtime/tooling/version_inventory.py +256 -0
  92. core_runtime_engine-11.5.1.dist-info/METADATA +35 -0
  93. core_runtime_engine-11.5.1.dist-info/RECORD +96 -0
  94. core_runtime_engine-11.5.1.dist-info/WHEEL +5 -0
  95. core_runtime_engine-11.5.1.dist-info/entry_points.txt +2 -0
  96. core_runtime_engine-11.5.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,482 @@
1
+ """Read-only environment diagnostics for CORE tooling."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import platform
7
+ import shutil
8
+ import subprocess
9
+ import sys
10
+ from dataclasses import dataclass, field
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from core_runtime.tooling.diagnostics import DiagnosticCollection
15
+ from core_runtime.tooling.version_inventory import VersionInventory
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class DoctorItem:
20
+ """A single environment readiness check."""
21
+
22
+ kind: str
23
+ name: str
24
+ path: str
25
+ status: str
26
+ details: dict[str, Any] = field(default_factory=dict)
27
+
28
+ def to_dict(self) -> dict[str, Any]:
29
+ result = {
30
+ "kind": self.kind,
31
+ "name": self.name,
32
+ "path": self.path,
33
+ "status": self.status,
34
+ }
35
+ if self.details:
36
+ result["details"] = self.details
37
+ return result
38
+
39
+
40
+ @dataclass
41
+ class DoctorReport:
42
+ """Normalized report for `core-runtime doctor`."""
43
+
44
+ tool: str
45
+ command: str
46
+ status: str
47
+ mutation_performed: bool = False
48
+ summary: dict[str, Any] = field(default_factory=dict)
49
+ items: list[DoctorItem] = field(default_factory=list)
50
+ diagnostics: DiagnosticCollection = field(default_factory=DiagnosticCollection)
51
+
52
+ def to_dict(self) -> dict[str, Any]:
53
+ counts = self.diagnostics.count_by_severity()
54
+ summary = dict(self.summary)
55
+ summary.setdefault("info", counts["info"])
56
+ summary.setdefault("warning", counts["warning"])
57
+ summary.setdefault("error", counts["error"])
58
+ summary.setdefault("blocked", counts["blocked"])
59
+ return {
60
+ "tool": self.tool,
61
+ "command": self.command,
62
+ "status": self.status,
63
+ "mutation_performed": self.mutation_performed,
64
+ "summary": summary,
65
+ "items": [item.to_dict() for item in self.items],
66
+ "diagnostics": [d.to_dict() for d in self.diagnostics.diagnostics],
67
+ }
68
+
69
+ def to_markdown(self) -> str:
70
+ counts = self.diagnostics.count_by_severity()
71
+ summary = dict(self.summary)
72
+ summary.setdefault("info", counts["info"])
73
+ summary.setdefault("warning", counts["warning"])
74
+ summary.setdefault("error", counts["error"])
75
+ summary.setdefault("blocked", counts["blocked"])
76
+ lines: list[str] = []
77
+ lines.append("# CORE doctor report")
78
+ lines.append("")
79
+ lines.append("## Summary")
80
+ lines.append("")
81
+ lines.append("| Metric | Value |")
82
+ lines.append("|--------|-------|")
83
+ lines.append("| Tool | {0} |".format(self.tool))
84
+ lines.append("| Command | {0} |".format(self.command))
85
+ lines.append("| Status | {0} |".format(self.status.upper()))
86
+ lines.append("| Mutation Performed | No |")
87
+ lines.append("| Checks | {0} |".format(summary.get("item_count", len(self.items))))
88
+ lines.append("| Info | {0} |".format(counts["info"]))
89
+ lines.append("| Warning | {0} |".format(counts["warning"]))
90
+ lines.append("| Error | {0} |".format(counts["error"]))
91
+ lines.append("| Blocked | {0} |".format(counts["blocked"]))
92
+ lines.append("")
93
+
94
+ if self.items:
95
+ lines.append("## Checks")
96
+ lines.append("")
97
+ lines.append("| Kind | Name | Path | Status |")
98
+ lines.append("|------|------|------|--------|")
99
+ for item in self.items:
100
+ lines.append("| {0} | {1} | {2} | {3} |".format(item.kind, item.name, item.path, item.status))
101
+ lines.append("")
102
+
103
+ if self.diagnostics.diagnostics:
104
+ lines.append("## Diagnostics")
105
+ lines.append("")
106
+ lines.append("| Severity | Code | Path | Message |")
107
+ lines.append("|----------|------|------|---------|")
108
+ for diagnostic in self.diagnostics.diagnostics:
109
+ path = diagnostic.path or "-"
110
+ message = diagnostic.message.replace("|", "\\|")
111
+ lines.append(
112
+ "| {0} | {1} | {2} | {3} |".format(
113
+ diagnostic.severity.value.upper(),
114
+ diagnostic.code,
115
+ path,
116
+ message,
117
+ )
118
+ )
119
+ lines.append("")
120
+
121
+ return "\n".join(lines)
122
+
123
+
124
+ class RepositoryDoctor:
125
+ """Build deterministic environment diagnostics for local CORE tooling."""
126
+
127
+ def __init__(self, repo_root: Path):
128
+ self.repo_root = repo_root
129
+ self.version_inventory = VersionInventory(repo_root)
130
+
131
+ def build_report(self, diagnostics: DiagnosticCollection | None = None) -> DoctorReport:
132
+ diagnostics = diagnostics or DiagnosticCollection()
133
+ items: list[DoctorItem] = []
134
+
135
+ python_version = self._check_python_version(diagnostics, items)
136
+ git_info = self._check_git(diagnostics, items)
137
+ self._check_tools(diagnostics, items)
138
+ self._check_verify_release_help(diagnostics, items)
139
+ self._check_release_report_permissions(diagnostics, items)
140
+ self._check_version_bearing_files(git_info, diagnostics, items)
141
+
142
+ passed = sum(1 for item in items if item.status == "passed")
143
+ warnings = sum(1 for item in items if item.status == "warning")
144
+ skipped = sum(1 for item in items if item.status == "skipped")
145
+ status = "pass"
146
+ if diagnostics.has_blocked():
147
+ status = "blocked"
148
+ elif diagnostics.has_errors():
149
+ status = "error"
150
+ elif warnings:
151
+ status = "warning"
152
+
153
+ summary = {
154
+ "item_count": len(items),
155
+ "passed": passed,
156
+ "warnings": warnings,
157
+ "skipped": skipped,
158
+ "python_version": python_version,
159
+ "repo_root": str(self.repo_root),
160
+ }
161
+ if git_info is not None:
162
+ summary["git_branch"] = git_info["branch"]
163
+ summary["git_version"] = git_info["version"]
164
+
165
+ return DoctorReport(
166
+ tool="core-runtime doctor",
167
+ command="doctor",
168
+ status=status,
169
+ summary=summary,
170
+ items=items,
171
+ diagnostics=diagnostics,
172
+ )
173
+
174
+ def _check_python_version(self, diagnostics: DiagnosticCollection, items: list[DoctorItem]) -> str:
175
+ current = platform.python_version()
176
+ required = "3.11"
177
+ status = "passed"
178
+ if sys.version_info < (3, 11):
179
+ diagnostics.add_warning(
180
+ code="core.doctor.python_version_too_low",
181
+ message="Python version is below the supported baseline",
182
+ path="python",
183
+ expected=">= 3.11",
184
+ actual=current,
185
+ )
186
+ status = "warning"
187
+ items.append(
188
+ DoctorItem(
189
+ kind="environment",
190
+ name="python",
191
+ path="python",
192
+ status=status,
193
+ details={"version": current, "required": required},
194
+ )
195
+ )
196
+ return current
197
+
198
+ def _check_tools(self, diagnostics: DiagnosticCollection, items: list[DoctorItem]) -> None:
199
+ for tool in ("pytest", "ruff", "mypy"):
200
+ version = self._tool_version(tool)
201
+ if version is None:
202
+ diagnostics.add_warning(
203
+ code=f"core.doctor.{tool}_missing",
204
+ message=f"Required development tool not found: {tool}",
205
+ path=tool,
206
+ expected="installed",
207
+ actual="missing",
208
+ )
209
+ items.append(
210
+ DoctorItem(
211
+ kind="tool",
212
+ name=tool,
213
+ path=tool,
214
+ status="warning",
215
+ details={"version": None, "available": False},
216
+ )
217
+ )
218
+ continue
219
+ items.append(
220
+ DoctorItem(
221
+ kind="tool",
222
+ name=tool,
223
+ path=tool,
224
+ status="passed",
225
+ details={"version": version, "available": True},
226
+ )
227
+ )
228
+
229
+ def _check_git(self, diagnostics: DiagnosticCollection, items: list[DoctorItem]) -> dict[str, str] | None:
230
+ version = self._tool_version("git")
231
+ if version is None:
232
+ diagnostics.add_warning(
233
+ code="core.doctor.git_missing",
234
+ message="Git is not available in PATH",
235
+ path="git",
236
+ expected="installed",
237
+ actual="missing",
238
+ )
239
+ items.append(
240
+ DoctorItem(
241
+ kind="tool",
242
+ name="git",
243
+ path="git",
244
+ status="warning",
245
+ details={"version": None, "available": False},
246
+ )
247
+ )
248
+ return None
249
+
250
+ branch = self._git_branch()
251
+ if branch is None:
252
+ diagnostics.add_warning(
253
+ code="core.doctor.git_branch_unavailable",
254
+ message="Git branch could not be determined",
255
+ path=str(self.repo_root),
256
+ expected="branch name",
257
+ actual="unknown",
258
+ )
259
+ status = "warning"
260
+ branch = "unknown"
261
+ elif branch == "HEAD":
262
+ diagnostics.add_warning(
263
+ code="core.doctor.git_detached_head",
264
+ message="Git repository is in detached HEAD state",
265
+ path=str(self.repo_root),
266
+ expected="named branch",
267
+ actual="HEAD",
268
+ )
269
+ status = "warning"
270
+ else:
271
+ status = "passed"
272
+
273
+ items.append(
274
+ DoctorItem(
275
+ kind="tool",
276
+ name="git",
277
+ path="git",
278
+ status=status,
279
+ details={"version": version, "branch": branch, "available": True},
280
+ )
281
+ )
282
+ return {"version": version, "branch": branch}
283
+
284
+ def _check_verify_release_help(self, diagnostics: DiagnosticCollection, items: list[DoctorItem]) -> None:
285
+ script = self.repo_root / "scripts" / "verify_release.py"
286
+ if not script.is_file():
287
+ diagnostics.add_warning(
288
+ code="core.doctor.verify_release_missing",
289
+ message="verify_release.py script is missing",
290
+ path="scripts/verify_release.py",
291
+ expected="exists",
292
+ actual="missing",
293
+ )
294
+ items.append(
295
+ DoctorItem(
296
+ kind="script",
297
+ name="verify_release.py",
298
+ path="scripts/verify_release.py",
299
+ status="warning",
300
+ details={"available": False},
301
+ )
302
+ )
303
+ return
304
+
305
+ result = subprocess.run(
306
+ [sys.executable, str(script), "--help"],
307
+ cwd=self.repo_root,
308
+ capture_output=True,
309
+ text=True,
310
+ check=False,
311
+ )
312
+ if result.returncode != 0:
313
+ diagnostics.add_warning(
314
+ code="core.doctor.verify_release_help_failed",
315
+ message="verify_release.py --help did not exit cleanly",
316
+ path="scripts/verify_release.py",
317
+ expected="exit 0",
318
+ actual=str(result.returncode),
319
+ )
320
+ status = "warning"
321
+ else:
322
+ status = "passed"
323
+ items.append(
324
+ DoctorItem(
325
+ kind="script",
326
+ name="verify_release.py",
327
+ path="scripts/verify_release.py",
328
+ status=status,
329
+ details={"available": True, "returncode": result.returncode},
330
+ )
331
+ )
332
+
333
+ def _check_release_report_permissions(self, diagnostics: DiagnosticCollection, items: list[DoctorItem]) -> None:
334
+ releases_dir = self.repo_root / "docs" / "releases"
335
+ if not releases_dir.is_dir():
336
+ diagnostics.add_warning(
337
+ code="core.doctor.release_dir_missing",
338
+ message="Release notes directory is missing",
339
+ path="docs/releases",
340
+ expected="directory",
341
+ actual="missing",
342
+ )
343
+ items.append(
344
+ DoctorItem(
345
+ kind="path",
346
+ name="release-notes",
347
+ path="docs/releases",
348
+ status="warning",
349
+ details={"exists": False, "writable": False},
350
+ )
351
+ )
352
+ return
353
+
354
+ writable = os.access(releases_dir, os.W_OK)
355
+ if not writable:
356
+ diagnostics.add_warning(
357
+ code="core.doctor.release_dir_not_writable",
358
+ message="Release notes directory is not writable",
359
+ path="docs/releases",
360
+ expected="writable",
361
+ actual="read-only",
362
+ )
363
+ status = "warning"
364
+ else:
365
+ status = "passed"
366
+
367
+ items.append(
368
+ DoctorItem(
369
+ kind="path",
370
+ name="release-notes",
371
+ path="docs/releases",
372
+ status=status,
373
+ details={"exists": True, "writable": writable},
374
+ )
375
+ )
376
+
377
+ def _check_version_bearing_files(
378
+ self,
379
+ git_info: dict[str, str] | None,
380
+ diagnostics: DiagnosticCollection,
381
+ items: list[DoctorItem],
382
+ ) -> None:
383
+ sources = self.version_inventory.discover()
384
+ version_paths = [str(source.path.relative_to(self.repo_root)) for source in sources]
385
+ missing = [source.name for source in sources if not source.path.exists()]
386
+ if missing:
387
+ diagnostics.add_warning(
388
+ code="core.doctor.version_source_missing",
389
+ message="One or more version-bearing files are missing",
390
+ path=missing[0],
391
+ expected="exists",
392
+ actual=", ".join(missing),
393
+ )
394
+ items.append(
395
+ DoctorItem(
396
+ kind="repo",
397
+ name="version-bearing-files",
398
+ path="version-bearing-files",
399
+ status="warning",
400
+ details={"missing": missing, "dirty": []},
401
+ )
402
+ )
403
+ return
404
+
405
+ if git_info is None:
406
+ items.append(
407
+ DoctorItem(
408
+ kind="repo",
409
+ name="version-bearing-files",
410
+ path="version-bearing-files",
411
+ status="skipped",
412
+ details={"dirty": [], "reason": "git unavailable"},
413
+ )
414
+ )
415
+ diagnostics.add_warning(
416
+ code="core.doctor.version_dirty_unknown",
417
+ message="Cannot inspect version-bearing files without git",
418
+ path="version-bearing-files",
419
+ expected="git available",
420
+ actual="git missing",
421
+ )
422
+ return
423
+
424
+ result = subprocess.run(
425
+ ["git", "-C", str(self.repo_root), "status", "--porcelain", "--", *version_paths],
426
+ capture_output=True,
427
+ text=True,
428
+ check=False,
429
+ )
430
+ dirty: list[str] = []
431
+ for line in result.stdout.splitlines():
432
+ if len(line) < 4:
433
+ continue
434
+ dirty.append(line[3:].strip())
435
+
436
+ if dirty:
437
+ diagnostics.add_warning(
438
+ code="core.doctor.version_dirty",
439
+ message="Version-bearing files have uncommitted changes",
440
+ path=dirty[0],
441
+ expected="clean",
442
+ actual=", ".join(dirty),
443
+ )
444
+ status = "warning"
445
+ else:
446
+ status = "passed"
447
+
448
+ items.append(
449
+ DoctorItem(
450
+ kind="repo",
451
+ name="version-bearing-files",
452
+ path="version-bearing-files",
453
+ status=status,
454
+ details={"dirty": dirty, "checked": version_paths},
455
+ )
456
+ )
457
+
458
+ def _tool_version(self, tool: str) -> str | None:
459
+ resolved = shutil.which(tool)
460
+ if not resolved:
461
+ return None
462
+ result = subprocess.run(
463
+ [resolved, "--version"],
464
+ cwd=self.repo_root,
465
+ capture_output=True,
466
+ text=True,
467
+ check=False,
468
+ )
469
+ if result.returncode != 0:
470
+ return None
471
+ return result.stdout.strip() or result.stderr.strip() or "unknown"
472
+
473
+ def _git_branch(self) -> str | None:
474
+ result = subprocess.run(
475
+ ["git", "-C", str(self.repo_root), "rev-parse", "--abbrev-ref", "HEAD"],
476
+ capture_output=True,
477
+ text=True,
478
+ check=False,
479
+ )
480
+ if result.returncode != 0:
481
+ return None
482
+ return result.stdout.strip() or None
@@ -0,0 +1,182 @@
1
+ """File inventory - check presence of required files."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from core_runtime.tooling.diagnostics import DiagnosticCollection
8
+
9
+
10
+ # Required files for CORE tooling
11
+ REQUIRED_FILES = [
12
+ "README.md",
13
+ "pyproject.toml",
14
+ "CHANGELOG.md",
15
+ "core_runtime/__version__.py",
16
+ "core_runtime/__init__.py",
17
+ "docs/VERSIONING_POLICY.md",
18
+ "docs/CORE_RELEASE_README.md",
19
+ "docs/REPRODUCIBILITY.md",
20
+ "docs/QUALITY_GATE.md",
21
+ "docs/releases/README.md",
22
+ "scripts/verify_release.py",
23
+ "scripts/check_version_consistency.py",
24
+ "scripts/bump_version.py",
25
+ "scripts/generate_requirements_lock.py",
26
+ "contracts/CoreRuleAnchor.abi.json",
27
+ "contracts/CoreRuleAnchor.bin",
28
+ "contracts/CoreRuleAnchor.build.json",
29
+ "contracts/CoreRuleAnchor.runtime.bin",
30
+ "contracts/CoreRuleAnchor.sol",
31
+ "core_runtime/core/contract_evaluator.py",
32
+ "core_runtime/core/contract_executability.py",
33
+ "core_runtime/core/rule_anchor.py",
34
+ "schemas/core/frozen_release_manifest.v1.json",
35
+ "schemas/core/frozen_release_manifest.v2.json",
36
+ "schemas/core/frozen_release_manifest.v3.json",
37
+ "schemas/core/dsk.v3.json",
38
+ "schemas/core/frozen_release_manifest.v7.json",
39
+ "schemas/core/frozen_release_manifest.v8.json",
40
+ "schemas/core/dsk.v3.json",
41
+ "schemas/core/frozen_release_manifest.v7.json",
42
+ "schemas/core/frozen_rule_set.v1.json",
43
+ "schemas/core/physical_safety_assurance_case.v1.json",
44
+ "schemas/core/rule_anchor_chain_evidence.v1.json",
45
+ "schemas/core/rule_approval.v1.json",
46
+ "schemas/core/rule_approval_request.v1.json",
47
+ "schemas/core/rule_anchor_batch.v1.json",
48
+ "schemas/core/unsigned_rule_anchor_deployment.v1.json",
49
+ "schemas/core/unsigned_rule_anchor_transaction.v1.json",
50
+ "scripts/audit_contract_executability.py",
51
+ "scripts/build_frozen_release_manifest.py",
52
+ "scripts/build_frozen_release_manifest_v11_2.py",
53
+ "scripts/build_frozen_release_manifest_v11_2_frozen.py",
54
+ "scripts/build_frozen_release_manifest_v11_5.py",
55
+ "scripts/build_frozen_release_manifest_v11_5.py",
56
+ "scripts/validate_frozen_rule_set.py",
57
+ "scripts/validate_frozen_release_manifest.py",
58
+ "scripts/validate_frozen_release_manifest_v11_2.py",
59
+ "scripts/validate_frozen_release_manifest_v11_2_frozen.py",
60
+ "scripts/validate_dsk_v3.py",
61
+ "scripts/validate_frozen_release_manifest_v11_5.py",
62
+ "scripts/validate_frozen_release_manifest_v11_5_1.py",
63
+ "scripts/build_frozen_release_manifest_v11_5_1.py",
64
+ "scripts/validate_dsk_v3.py",
65
+ "scripts/validate_frozen_release_manifest_v11_5.py",
66
+ "scripts/validate_rule_approval.py",
67
+ "scripts/validate_rule_anchor_batch.py",
68
+ "scripts/validate_unsigned_rule_anchor_deployment.py",
69
+ "scripts/validate_unsigned_rule_anchor_transaction.py",
70
+ "scripts/build_rule_anchor_batch.py",
71
+ "scripts/compile_core_rule_anchor.py",
72
+ "scripts/create_private_rule_commitment.py",
73
+ "scripts/create_rule_approval_request.py",
74
+ "scripts/evaluate_core_contract.py",
75
+ "scripts/finalize_rule_approval.py",
76
+ "scripts/prepare_core_rule_anchor_deployment.py",
77
+ "scripts/prepare_rule_anchor_transaction.py",
78
+ "scripts/verify_merkle_proof.py",
79
+ "scripts/verify_rule_anchor_onchain.py",
80
+ "docs/EXECUTABLE_CONTRACTS_AND_PHYSICAL_SAFETY.md",
81
+ "docs/FROZEN_RULE_ANCHORING.md",
82
+ "docs/PROJECTION_AND_RESPONSIBLE_AGENCY.md",
83
+ "examples/frozen_release_manifest/accepted_v11_1_0.json",
84
+ "examples/frozen_release_manifest/accepted_v11_2_0_candidate.json",
85
+ "examples/frozen_release_manifest/accepted_v11_2_0.json",
86
+ "examples/frozen_release_manifest/accepted_v11_5_0_candidate.json",
87
+ "examples/frozen_release_manifest/accepted_v11_5_1_candidate.json",
88
+ "examples/frozen_release_manifest/accepted_v11_5_0_candidate.json",
89
+ "tests/test_frozen_release_manifest.py",
90
+ "tests/test_frozen_release_manifest_v11_5_1.py",
91
+ "tests/test_frozen_release_manifest_v11_2.py",
92
+ "tests/test_frozen_release_manifest_v11_2_frozen.py",
93
+ "requirements.lock",
94
+ "requirements-dev.txt",
95
+ ]
96
+
97
+ # Required directories
98
+ REQUIRED_DIRS = [
99
+ "schemas",
100
+ "examples",
101
+ "tests",
102
+ ".github/workflows",
103
+ ]
104
+
105
+ # Optional files (created by this implementation)
106
+ OPTIONAL_FILES = [
107
+ "docs/CORE_TOOLING.md",
108
+ ]
109
+
110
+
111
+ class FileInventory:
112
+ """Check presence of required files and directories."""
113
+
114
+ def __init__(self, repo_root: Path):
115
+ self.repo_root = repo_root
116
+
117
+ def check_file(self, rel_path: str) -> bool:
118
+ """Check if a file exists."""
119
+ return (self.repo_root / rel_path).is_file()
120
+
121
+ def check_dir(self, rel_path: str) -> bool:
122
+ """Check if a directory exists."""
123
+ return (self.repo_root / rel_path).is_dir()
124
+
125
+ def check_all(self, diagnostics: DiagnosticCollection) -> dict[str, bool]:
126
+ """Check all required files and directories."""
127
+ results = {}
128
+
129
+ # Check required files
130
+ for rel_path in REQUIRED_FILES:
131
+ exists = self.check_file(rel_path)
132
+ results[rel_path] = exists
133
+ if not exists:
134
+ diagnostics.add_error(
135
+ code="core.file.missing",
136
+ message="Required file missing: {0}".format(rel_path),
137
+ path=rel_path,
138
+ expected="exists",
139
+ actual="missing",
140
+ )
141
+
142
+ # Check required directories
143
+ for rel_path in REQUIRED_DIRS:
144
+ exists = self.check_dir(rel_path)
145
+ results[rel_path] = exists
146
+ if not exists:
147
+ diagnostics.add_error(
148
+ code="core.dir.missing",
149
+ message="Required directory missing: {0}".format(rel_path),
150
+ path=rel_path,
151
+ expected="exists",
152
+ actual="missing",
153
+ )
154
+
155
+ # Check optional files (just report, don't error)
156
+ for rel_path in OPTIONAL_FILES:
157
+ exists = self.check_file(rel_path)
158
+ results[rel_path] = exists
159
+ if not exists:
160
+ diagnostics.add_info(
161
+ code="core.file.optional_missing",
162
+ message="Optional file not yet present: {0}".format(rel_path),
163
+ path=rel_path,
164
+ expected="optional",
165
+ actual="missing",
166
+ )
167
+
168
+ return results
169
+
170
+ def check_release_note_exists(self, version: str, diagnostics: DiagnosticCollection) -> bool:
171
+ """Check if release note for given version exists."""
172
+ rel_path = "docs/releases/v{0}.md".format(version)
173
+ exists = self.check_file(rel_path)
174
+ if not exists:
175
+ diagnostics.add_error(
176
+ code="core.file.release_note_missing",
177
+ message="Release note for v{0} not found".format(version),
178
+ path=rel_path,
179
+ expected="exists",
180
+ actual="missing",
181
+ )
182
+ return exists