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,579 @@
1
+ """CLI argument parser and command dispatch."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+ from core_runtime.cli.bump_version import cmd_bump_version
9
+ from core_runtime.cli.create_domain import cmd_create_domain
10
+ from core_runtime.cli.contract_preflight import cmd_contract_preflight
11
+ from core_runtime.cli.doctor import cmd_doctor
12
+ from core_runtime.cli.inventory import cmd_info, cmd_list
13
+ from core_runtime.cli.release_check import cmd_release_check
14
+ from core_runtime.cli.repair_artifact_paths import cmd_repair_artifact_paths
15
+ from core_runtime.cli.sync_template import cmd_sync_template
16
+ from core_runtime.cli.validate import cmd_validate
17
+ from core_runtime.tooling.diagnostics import DiagnosticCollection
18
+ from core_runtime.tooling.file_inventory import FileInventory
19
+ from core_runtime.tooling.json_checks import JSONChecks
20
+ from core_runtime.tooling.report_writer import ReportWriter
21
+ from core_runtime.tooling.release_check import RELEASE_CHECK_PROFILES
22
+ from core_runtime.tooling.safety_checks import SafetyChecks
23
+ from core_runtime.tooling.version_inventory import VersionInventory
24
+
25
+
26
+ def build_parser() -> argparse.ArgumentParser:
27
+ """Build the argument parser with subcommands."""
28
+ parser = argparse.ArgumentParser(
29
+ prog="core-runtime",
30
+ description="CORE Runtime tooling commands",
31
+ )
32
+ subparsers = parser.add_subparsers(dest="command", metavar="COMMAND")
33
+
34
+ # lint subcommand
35
+ lint_parser = subparsers.add_parser("lint", help="Run tooling lint checks")
36
+ lint_parser.add_argument(
37
+ "--scope",
38
+ choices=["tooling"],
39
+ default="tooling",
40
+ help="Scope of lint checks (default: tooling)",
41
+ )
42
+ lint_parser.add_argument(
43
+ "--format",
44
+ choices=["json", "markdown"],
45
+ default="json",
46
+ help="Output format (default: json)",
47
+ )
48
+ lint_parser.add_argument(
49
+ "--output",
50
+ type=Path,
51
+ help="Write output to file instead of stdout",
52
+ )
53
+ lint_parser.set_defaults(func=cmd_lint)
54
+
55
+ # release-check subcommand
56
+ release_check_parser = subparsers.add_parser(
57
+ "release-check",
58
+ help="Run lint precheck and the authoritative release gate",
59
+ )
60
+ release_check_parser.add_argument(
61
+ "--target",
62
+ type=str,
63
+ default=None,
64
+ help="Release target (default: canonical version from core_runtime/__version__.py)",
65
+ )
66
+ release_check_parser.add_argument(
67
+ "--format",
68
+ choices=["json", "markdown"],
69
+ default="json",
70
+ help="Output format (default: json)",
71
+ )
72
+ release_check_parser.add_argument(
73
+ "--output",
74
+ type=Path,
75
+ help="Write output to file instead of stdout",
76
+ )
77
+ release_check_parser.add_argument(
78
+ "--skip-tooling-lint",
79
+ action="store_true",
80
+ default=False,
81
+ help="Skip the tooling lint precheck",
82
+ )
83
+ release_check_parser.add_argument(
84
+ "--timeout",
85
+ type=int,
86
+ default=120,
87
+ help="Maximum seconds for the release gate subprocess (default: 120)",
88
+ )
89
+ release_check_parser.add_argument(
90
+ "--preflight-only",
91
+ action="store_true",
92
+ default=False,
93
+ help="Run bounded preflight checks without the full release gate",
94
+ )
95
+ release_check_parser.add_argument(
96
+ "--group",
97
+ default=None,
98
+ help="Run a named release-gate group instead of the full gate",
99
+ )
100
+ release_check_parser.add_argument(
101
+ "--profile",
102
+ choices=sorted(RELEASE_CHECK_PROFILES),
103
+ default=None,
104
+ help="Run a named release-check profile preset",
105
+ )
106
+ release_check_parser.add_argument(
107
+ "--list-checks",
108
+ action="store_true",
109
+ default=False,
110
+ help="List available release-gate checks without executing them",
111
+ )
112
+ release_check_parser.add_argument(
113
+ "--plan",
114
+ action="store_true",
115
+ default=False,
116
+ help="Emit the release-gate execution plan without running checks",
117
+ )
118
+ release_check_parser.add_argument(
119
+ "--timing-json",
120
+ default=None,
121
+ help="Write deterministic release-gate timing output to a JSON file",
122
+ )
123
+ release_check_parser.add_argument(
124
+ "--debug",
125
+ action="store_true",
126
+ default=False,
127
+ help="Include debug details in the report",
128
+ )
129
+ release_check_parser.set_defaults(func=cmd_release_check)
130
+
131
+ # bump-version subcommand
132
+ bump_parser = subparsers.add_parser(
133
+ "bump-version",
134
+ help="Plan or apply a version bump",
135
+ )
136
+ bump_parser.add_argument(
137
+ "target_version",
138
+ help="Target version (e.g. 10.5.1)",
139
+ )
140
+ bump_parser.add_argument(
141
+ "--dry-run",
142
+ action="store_true",
143
+ default=False,
144
+ help="Dry-run mode (compute planned changes without mutation)",
145
+ )
146
+ bump_parser.add_argument(
147
+ "--apply",
148
+ action="store_true",
149
+ default=False,
150
+ help="Apply mode (perform the actual version mutation)",
151
+ )
152
+ bump_parser.add_argument(
153
+ "--confirm-current",
154
+ type=str,
155
+ default=None,
156
+ help="Confirm the current version before apply (required with --apply)",
157
+ )
158
+ bump_parser.add_argument(
159
+ "--format",
160
+ choices=["json", "markdown"],
161
+ default="json",
162
+ help="Output format (default: json)",
163
+ )
164
+ bump_parser.add_argument(
165
+ "--output",
166
+ type=Path,
167
+ help="Write output to file instead of stdout",
168
+ )
169
+ bump_parser.set_defaults(func=cmd_bump_version)
170
+
171
+ # list subcommand
172
+ list_parser = subparsers.add_parser("list", help="List read-only repository inventory items")
173
+ list_parser.add_argument(
174
+ "kind",
175
+ nargs="?",
176
+ default="schemas",
177
+ help="Inventory kind to list (schemas|contracts|adapters|domains; default: schemas)",
178
+ )
179
+ list_parser.add_argument(
180
+ "--format",
181
+ choices=["json", "markdown"],
182
+ default="json",
183
+ help="Output format (default: json)",
184
+ )
185
+ list_parser.add_argument(
186
+ "--output",
187
+ type=Path,
188
+ help="Write output to file instead of stdout",
189
+ )
190
+ list_parser.set_defaults(func=cmd_list)
191
+
192
+ # info subcommand
193
+ info_parser = subparsers.add_parser("info", help="Show repository inventory summary or item details")
194
+ info_parser.add_argument(
195
+ "kind",
196
+ nargs="?",
197
+ default=None,
198
+ help="Optional inventory kind to inspect (schema|schemas|contract|contracts|adapter|adapters|domain|domains)",
199
+ )
200
+ info_parser.add_argument(
201
+ "name",
202
+ nargs="?",
203
+ default=None,
204
+ help="Optional item name to inspect inside the selected kind",
205
+ )
206
+ info_parser.add_argument(
207
+ "--format",
208
+ choices=["json", "markdown"],
209
+ default="json",
210
+ help="Output format (default: json)",
211
+ )
212
+ info_parser.add_argument(
213
+ "--output",
214
+ type=Path,
215
+ help="Write output to file instead of stdout",
216
+ )
217
+ info_parser.set_defaults(func=cmd_info)
218
+
219
+ # validate subcommand
220
+ validate_parser = subparsers.add_parser("validate", help="Run read-only structural validation")
221
+ validate_parser.add_argument(
222
+ "kind",
223
+ nargs="?",
224
+ default="schemas",
225
+ help="Validation kind (schemas|examples|manifests|contracts|domain; default: schemas)",
226
+ )
227
+ validate_parser.add_argument(
228
+ "name",
229
+ nargs="?",
230
+ default=None,
231
+ help="Optional name for domain validation",
232
+ )
233
+ validate_parser.add_argument(
234
+ "--format",
235
+ choices=["json", "markdown"],
236
+ default="json",
237
+ help="Output format (default: json)",
238
+ )
239
+ validate_parser.add_argument(
240
+ "--output",
241
+ type=Path,
242
+ help="Write output to file instead of stdout",
243
+ )
244
+ validate_parser.set_defaults(func=cmd_validate)
245
+
246
+ # doctor subcommand
247
+ doctor_parser = subparsers.add_parser("doctor", help="Run read-only environment diagnostics")
248
+ doctor_parser.add_argument(
249
+ "--format",
250
+ choices=["json", "markdown"],
251
+ default="json",
252
+ help="Output format (default: json)",
253
+ )
254
+ doctor_parser.add_argument(
255
+ "--output",
256
+ type=Path,
257
+ help="Write output to file instead of stdout",
258
+ )
259
+ doctor_parser.set_defaults(func=cmd_doctor)
260
+
261
+ # contract-preflight subcommand
262
+ contract_preflight_parser = subparsers.add_parser(
263
+ "contract-preflight",
264
+ help="Run advisory-only contract candidate review",
265
+ )
266
+ mode_group = contract_preflight_parser.add_mutually_exclusive_group(required=True)
267
+ mode_group.add_argument(
268
+ "--candidate",
269
+ type=str,
270
+ default=None,
271
+ help="Review a known contract candidate by name",
272
+ )
273
+ mode_group.add_argument(
274
+ "--compare",
275
+ nargs=2,
276
+ metavar=("LEFT", "RIGHT"),
277
+ default=None,
278
+ help="Compare two known contract candidates",
279
+ )
280
+ contract_preflight_parser.add_argument(
281
+ "--format",
282
+ choices=["json", "markdown"],
283
+ default="json",
284
+ help="Output format (default: json)",
285
+ )
286
+ contract_preflight_parser.add_argument(
287
+ "--output",
288
+ type=Path,
289
+ help="Write output to file instead of stdout",
290
+ )
291
+ contract_preflight_parser.set_defaults(func=cmd_contract_preflight)
292
+
293
+ # create-domain subcommand
294
+ create_domain_parser = subparsers.add_parser(
295
+ "create-domain",
296
+ help="Plan a new domain scaffold (dry-run only in this slice)",
297
+ )
298
+ create_domain_parser.add_argument(
299
+ "name",
300
+ help="Domain name to scaffold",
301
+ )
302
+ create_domain_parser.add_argument(
303
+ "--template",
304
+ default="generic",
305
+ help="Template name to use for the plan (default: generic)",
306
+ )
307
+ create_domain_parser.add_argument(
308
+ "--dry-run",
309
+ action="store_true",
310
+ default=False,
311
+ help="Required for this slice; emit plan without mutating files",
312
+ )
313
+ create_domain_parser.add_argument(
314
+ "--format",
315
+ choices=["json", "markdown"],
316
+ default="json",
317
+ help="Output format (default: json)",
318
+ )
319
+ create_domain_parser.add_argument(
320
+ "--output",
321
+ type=Path,
322
+ help="Write output to file instead of stdout",
323
+ )
324
+ create_domain_parser.set_defaults(func=cmd_create_domain)
325
+
326
+ # sync-template subcommand
327
+ sync_template_parser = subparsers.add_parser(
328
+ "sync-template",
329
+ help="Compare domains against the canonical scaffold template",
330
+ )
331
+ sync_mode_group = sync_template_parser.add_mutually_exclusive_group(required=True)
332
+ sync_mode_group.add_argument(
333
+ "--domain",
334
+ type=str,
335
+ default=None,
336
+ help="Sync a single domain against the template",
337
+ )
338
+ sync_mode_group.add_argument(
339
+ "--all",
340
+ action="store_true",
341
+ default=False,
342
+ help="Sync all discovered domains against the template",
343
+ )
344
+ sync_template_parser.add_argument(
345
+ "--template",
346
+ default="generic",
347
+ help="Template name to compare against (default: generic)",
348
+ )
349
+ sync_template_parser.add_argument(
350
+ "--dry-run",
351
+ action="store_true",
352
+ default=False,
353
+ help="Required for this slice; emit plan without mutating files",
354
+ )
355
+ sync_template_parser.add_argument(
356
+ "--format",
357
+ choices=["json", "markdown"],
358
+ default="json",
359
+ help="Output format (default: json)",
360
+ )
361
+ sync_template_parser.add_argument(
362
+ "--output",
363
+ type=Path,
364
+ help="Write output to file instead of stdout",
365
+ )
366
+ sync_template_parser.set_defaults(func=cmd_sync_template)
367
+
368
+ # repair-artifact-paths subcommand
369
+ repair_parser = subparsers.add_parser(
370
+ "repair-artifact-paths",
371
+ help="Plan repairs for migrated artifact path references",
372
+ )
373
+ repair_parser.add_argument(
374
+ "--from",
375
+ dest="source_path",
376
+ default=None,
377
+ help="Source path or prefix to replace",
378
+ )
379
+ repair_parser.add_argument(
380
+ "--to",
381
+ dest="destination_path",
382
+ default=None,
383
+ help="Destination path or prefix to use",
384
+ )
385
+ repair_parser.add_argument(
386
+ "--manifest",
387
+ type=Path,
388
+ default=None,
389
+ help="Optional migration manifest to drive repair rules",
390
+ )
391
+ repair_parser.add_argument(
392
+ "--dry-run",
393
+ action="store_true",
394
+ default=False,
395
+ help="Required in this slice; emit a repair plan without mutating files",
396
+ )
397
+ repair_parser.add_argument(
398
+ "--apply",
399
+ action="store_true",
400
+ default=False,
401
+ help="Reserved for a later guarded mutation slice",
402
+ )
403
+ repair_parser.add_argument(
404
+ "--format",
405
+ choices=["json", "markdown"],
406
+ default="json",
407
+ help="Output format (default: json)",
408
+ )
409
+ repair_parser.add_argument(
410
+ "--output",
411
+ type=Path,
412
+ help="Write output to file instead of stdout",
413
+ )
414
+ repair_parser.set_defaults(func=cmd_repair_artifact_paths)
415
+
416
+ return parser
417
+
418
+
419
+ def cmd_lint(args: argparse.Namespace) -> int:
420
+ """Execute the lint command."""
421
+ repo_root = Path(__file__).resolve().parents[2] # core_runtime/cli/ -> core_runtime/ -> repo_root
422
+
423
+ # Initialize checkers
424
+ version_inv = VersionInventory(repo_root)
425
+ file_inv = FileInventory(repo_root)
426
+ json_checks = JSONChecks(repo_root)
427
+ safety_checks = SafetyChecks(repo_root)
428
+ report_writer = ReportWriter(repo_root)
429
+
430
+ from core_runtime.tooling.diagnostics import DiagnosticCollection
431
+
432
+ diagnostics = DiagnosticCollection()
433
+
434
+ # 1. Version inventory and consistency
435
+ version_sources = version_inv.check_consistency(diagnostics)
436
+ version_inv.check_changelog_latest(diagnostics)
437
+ version_inv.check_release_note(diagnostics)
438
+
439
+ # 2. Required file inventory
440
+ file_results = file_inv.check_all(diagnostics)
441
+
442
+ # 3. Script compilation checks
443
+ check_script_compilation(repo_root, diagnostics)
444
+
445
+ # 4. JSON parse checks
446
+ schema_checked, schema_errors = json_checks.check_schemas(diagnostics)
447
+ example_checked, example_errors = json_checks.check_examples(diagnostics)
448
+ lock_ok = json_checks.check_requirements_lock(diagnostics)
449
+
450
+ json_results = {
451
+ "schemas_checked": schema_checked,
452
+ "schemas_errors": schema_errors,
453
+ "examples_checked": example_checked,
454
+ "examples_errors": example_errors,
455
+ "requirements_lock_readable": lock_ok,
456
+ }
457
+
458
+ # 5. Stale documentation checks (warnings)
459
+ check_stale_docs(repo_root, diagnostics)
460
+
461
+ # 6. Safety checks
462
+ safety_checks.check_private_path_leakage(diagnostics)
463
+ safety_checks.check_proposal_execution_safety(diagnostics)
464
+ safety_checks.check_todo_templates(diagnostics)
465
+
466
+ safety_results = {
467
+ "private_path_scan": "completed",
468
+ "proposal_safety_scan": "completed",
469
+ "template_scan": "completed",
470
+ }
471
+
472
+ # Write output
473
+ if args.format == "json":
474
+ report = report_writer.write_json(
475
+ diagnostics=diagnostics,
476
+ scope=args.scope,
477
+ output_path=args.output,
478
+ version_sources=version_sources,
479
+ file_inventory=file_results,
480
+ json_checks=json_results,
481
+ safety_checks=safety_results,
482
+ )
483
+ if not args.output:
484
+ import json
485
+ print(json.dumps(report, indent=2, ensure_ascii=False))
486
+ else:
487
+ markdown = report_writer.write_markdown(
488
+ diagnostics=diagnostics,
489
+ scope=args.scope,
490
+ output_path=args.output,
491
+ version_sources=version_sources,
492
+ file_inventory=file_results,
493
+ json_checks=json_results,
494
+ safety_checks=safety_results,
495
+ )
496
+ if not args.output:
497
+ print(markdown)
498
+
499
+ # Return exit code
500
+ return diagnostics.compute_exit_code().value
501
+
502
+
503
+ def check_script_compilation(repo_root: Path, diagnostics: DiagnosticCollection) -> dict:
504
+ """Check that key scripts compile without errors."""
505
+ import py_compile
506
+
507
+ scripts = [
508
+ "scripts/verify_release.py",
509
+ "scripts/check_version_consistency.py",
510
+ "scripts/bump_version.py",
511
+ "scripts/generate_requirements_lock.py",
512
+ ]
513
+
514
+ results = {}
515
+ for script in scripts:
516
+ script_path = repo_root / script
517
+ if not script_path.exists():
518
+ diagnostics.add_error(
519
+ code="core.script.missing",
520
+ message="Required script not found: {0}".format(script),
521
+ path=script,
522
+ expected="exists",
523
+ actual="missing",
524
+ )
525
+ results[script] = False
526
+ continue
527
+
528
+ try:
529
+ py_compile.compile(str(script_path), doraise=True)
530
+ results[script] = True
531
+ except py_compile.PyCompileError as e:
532
+ # e.args = (message, (filename, lineno, offset, text))
533
+ lineno = e.args[1][1] if len(e.args) > 1 and len(e.args[1]) > 1 else "unknown"
534
+ diagnostics.add_error(
535
+ code="core.script.compile_error",
536
+ message="Script compilation failed: {0}".format(e.msg),
537
+ path=script,
538
+ details="line {0}: {1}".format(lineno, e.msg),
539
+ )
540
+ results[script] = False
541
+ except Exception as e:
542
+ diagnostics.add_error(
543
+ code="core.script.compile_error",
544
+ message="Script compilation error: {0}".format(e),
545
+ path=script,
546
+ )
547
+ results[script] = False
548
+
549
+ return results
550
+
551
+
552
+ def check_stale_docs(repo_root: Path, diagnostics: DiagnosticCollection) -> None:
553
+ """Check for known stale documentation references."""
554
+ def _is_historical_reference(text: str) -> bool:
555
+ return "historical" in text.lower()
556
+
557
+ # VERSIONING_POLICY.md - v4.x compatibility matrix
558
+ vpolicy = repo_root / "docs" / "VERSIONING_POLICY.md"
559
+ if vpolicy.exists():
560
+ text = vpolicy.read_text(encoding="utf-8")
561
+ if "v4." in text and "compatibility" in text.lower() and not _is_historical_reference(text):
562
+ diagnostics.add_warning(
563
+ code="core.docs.stale_compatibility_matrix",
564
+ message="VERSIONING_POLICY.md contains v4.x-era compatibility matrix",
565
+ path="docs/VERSIONING_POLICY.md",
566
+ details="Should be updated for current versioning",
567
+ )
568
+
569
+ # QUALITY_GATE.md - v4.4.0-rc1 reference
570
+ qgate = repo_root / "docs" / "QUALITY_GATE.md"
571
+ if qgate.exists():
572
+ text = qgate.read_text(encoding="utf-8")
573
+ if ("v4.4.0-rc1" in text or "4.4.0-rc1" in text) and not _is_historical_reference(text):
574
+ diagnostics.add_warning(
575
+ code="core.docs.stale_quality_gate",
576
+ message="QUALITY_GATE.md references v4.4.0-rc1",
577
+ path="docs/QUALITY_GATE.md",
578
+ details="Should reference current version",
579
+ )
@@ -0,0 +1,65 @@
1
+ """CLI command for release-check — wrapper around verify_release.py."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from core_runtime.tooling.diagnostics import ExitCode
9
+ from core_runtime.tooling.release_check import ReleaseCheckRunner
10
+
11
+
12
+ def cmd_release_check(args: object) -> int:
13
+ """Execute the release-check command."""
14
+ target = getattr(args, "target", None)
15
+ fmt: str = getattr(args, "format", "json")
16
+ output = getattr(args, "output", None)
17
+ skip_tooling_lint: bool = getattr(args, "skip_tooling_lint", False)
18
+ timeout_seconds: int = int(getattr(args, "timeout", 120))
19
+ preflight_only: bool = getattr(args, "preflight_only", False)
20
+ debug: bool = getattr(args, "debug", False)
21
+ group = getattr(args, "group", None)
22
+ profile = getattr(args, "profile", None)
23
+ list_checks: bool = getattr(args, "list_checks", False)
24
+ plan: bool = getattr(args, "plan", False)
25
+ timing_json = getattr(args, "timing_json", None)
26
+
27
+ repo_root = Path(__file__).resolve().parents[2]
28
+ runner = ReleaseCheckRunner(repo_root)
29
+ report = runner.run(
30
+ target=target,
31
+ skip_tooling_lint=skip_tooling_lint,
32
+ timeout_seconds=timeout_seconds,
33
+ preflight_only=preflight_only,
34
+ debug=debug,
35
+ group=group,
36
+ profile=profile,
37
+ list_checks=list_checks,
38
+ plan=plan,
39
+ timing_json=timing_json,
40
+ )
41
+ output_path = Path(output) if output else None
42
+
43
+ if fmt == "json":
44
+ payload = report.to_dict()
45
+ if output_path:
46
+ output_path.parent.mkdir(parents=True, exist_ok=True)
47
+ output_path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
48
+ else:
49
+ print(json.dumps(payload, indent=2, ensure_ascii=False))
50
+ else:
51
+ markdown = report.to_markdown()
52
+ if output_path:
53
+ output_path.parent.mkdir(parents=True, exist_ok=True)
54
+ output_path.write_text(markdown, encoding="utf-8")
55
+ else:
56
+ print(markdown)
57
+
58
+ status_to_exit = {
59
+ "pass": ExitCode.OK.value,
60
+ "warning": ExitCode.OK.value,
61
+ "error": ExitCode.ERROR.value,
62
+ "blocked": ExitCode.BLOCKED.value,
63
+ "internal_error": ExitCode.INTERNAL_ERROR.value,
64
+ }
65
+ return status_to_exit.get(report.status, ExitCode.INTERNAL_ERROR.value)
@@ -0,0 +1,48 @@
1
+ """CLI command for artifact path repair preflight."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from core_runtime.tooling.diagnostics import ExitCode
9
+ from core_runtime.tooling.repair_artifact_paths import ArtifactPathRepairPlanner
10
+
11
+
12
+ def _emit_report(report, fmt: str, output) -> None:
13
+ payload = report.to_dict()
14
+ if fmt == "json":
15
+ text = json.dumps(payload, indent=2, ensure_ascii=False)
16
+ else:
17
+ text = report.to_markdown()
18
+ if output:
19
+ output_path = Path(output)
20
+ output_path.parent.mkdir(parents=True, exist_ok=True)
21
+ output_path.write_text(text + ("\n" if fmt == "json" else ""), encoding="utf-8")
22
+ else:
23
+ print(text)
24
+
25
+
26
+ def cmd_repair_artifact_paths(args: object) -> int:
27
+ """Plan artifact path repairs without mutating the repository."""
28
+ repo_root = Path(__file__).resolve().parents[2]
29
+ planner = ArtifactPathRepairPlanner(repo_root)
30
+
31
+ report = planner.build_plan(
32
+ dry_run=getattr(args, "dry_run", False),
33
+ source=getattr(args, "source_path", None),
34
+ destination=getattr(args, "destination_path", None),
35
+ manifest_path=getattr(args, "manifest", None),
36
+ apply=getattr(args, "apply", False),
37
+ )
38
+ fmt: str = getattr(args, "format", "json")
39
+ output = getattr(args, "output", None)
40
+ _emit_report(report, fmt, output)
41
+
42
+ return {
43
+ "pass": ExitCode.OK.value,
44
+ "warning": ExitCode.OK.value,
45
+ "error": ExitCode.ERROR.value,
46
+ "blocked": ExitCode.BLOCKED.value,
47
+ "internal_error": ExitCode.INTERNAL_ERROR.value,
48
+ }.get(report.status, ExitCode.INTERNAL_ERROR.value)