arxo-codegen 0.4.0__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 (152) hide show
  1. arxo_codegen/__init__.py +5 -0
  2. arxo_codegen/__main__.py +7 -0
  3. arxo_codegen/active-outcomes.json +6837 -0
  4. arxo_codegen/check.py +158 -0
  5. arxo_codegen/check_active_canaries.py +262 -0
  6. arxo_codegen/check_api.py +76 -0
  7. arxo_codegen/check_conformance.py +414 -0
  8. arxo_codegen/check_matrix.py +131 -0
  9. arxo_codegen/check_packages.py +281 -0
  10. arxo_codegen/check_semantic_probes.py +293 -0
  11. arxo_codegen/check_xlsx.py +320 -0
  12. arxo_codegen/consumer_runner.py +316 -0
  13. arxo_codegen/core_support.py +203 -0
  14. arxo_codegen/coverage.py +341 -0
  15. arxo_codegen/deliver.py +180 -0
  16. arxo_codegen/examples/xlsx/pricing.lawir.json +409 -0
  17. arxo_codegen/examples/xlsx/pricing.xlsx.json +52 -0
  18. arxo_codegen/excel_plan.py +602 -0
  19. arxo_codegen/harness/verify/ci/gates/backends/check_backends.py +1248 -0
  20. arxo_codegen/harness/verify/ci/gates/backends/l1_fixtures.py +463 -0
  21. arxo_codegen/inert-nodes.json +62 -0
  22. arxo_codegen/inert.py +91 -0
  23. arxo_codegen/inputs.py +59 -0
  24. arxo_codegen/package.py +565 -0
  25. arxo_codegen/plan.py +4053 -0
  26. arxo_codegen/recertify_registry.py +100 -0
  27. arxo_codegen/runtime-cert.json +5259 -0
  28. arxo_codegen/runtime_cert.py +233 -0
  29. arxo_codegen/survey.py +272 -0
  30. arxo_codegen/target_runner.py +101 -0
  31. arxo_codegen/targets/bsl/cert.bsl +113 -0
  32. arxo_codegen/targets/bsl/emit.py +356 -0
  33. arxo_codegen/targets/bsl/json.bsl +243 -0
  34. arxo_codegen/targets/bsl/runner.bsl +210 -0
  35. arxo_codegen/targets/bsl/runtime.bsl +858 -0
  36. arxo_codegen/targets/cs/Cert.cs +90 -0
  37. arxo_codegen/targets/cs/Runner.cs +154 -0
  38. arxo_codegen/targets/cs/Runtime.cs +243 -0
  39. arxo_codegen/targets/cs/emit.py +223 -0
  40. arxo_codegen/targets/dart/cert.dart +99 -0
  41. arxo_codegen/targets/dart/emit.py +206 -0
  42. arxo_codegen/targets/dart/json.dart +166 -0
  43. arxo_codegen/targets/dart/runner.dart +154 -0
  44. arxo_codegen/targets/dart/runtime.dart +293 -0
  45. arxo_codegen/targets/erl/cert.erl +64 -0
  46. arxo_codegen/targets/erl/emit.py +216 -0
  47. arxo_codegen/targets/erl/rt.erl +238 -0
  48. arxo_codegen/targets/erl/runner.erl +130 -0
  49. arxo_codegen/targets/ex/cert.exs +62 -0
  50. arxo_codegen/targets/ex/emit.py +204 -0
  51. arxo_codegen/targets/ex/runner.exs +124 -0
  52. arxo_codegen/targets/ex/runtime.ex +227 -0
  53. arxo_codegen/targets/go/apiBase.go +483 -0
  54. arxo_codegen/targets/go/apicheck.go +97 -0
  55. arxo_codegen/targets/go/cert.go +218 -0
  56. arxo_codegen/targets/go/emit.py +1806 -0
  57. arxo_codegen/targets/go/evaluate.go +1826 -0
  58. arxo_codegen/targets/go/runner.go +38 -0
  59. arxo_codegen/targets/go/runtime.go +2612 -0
  60. arxo_codegen/targets/java/Cert.java +91 -0
  61. arxo_codegen/targets/java/Json.java +148 -0
  62. arxo_codegen/targets/java/Runner.java +151 -0
  63. arxo_codegen/targets/java/Runtime.java +243 -0
  64. arxo_codegen/targets/java/emit.py +198 -0
  65. arxo_codegen/targets/kt/Cert.kt +67 -0
  66. arxo_codegen/targets/kt/Json.kt +103 -0
  67. arxo_codegen/targets/kt/Runner.kt +126 -0
  68. arxo_codegen/targets/kt/Runtime.kt +196 -0
  69. arxo_codegen/targets/kt/emit.py +195 -0
  70. arxo_codegen/targets/lua/cert.lua +82 -0
  71. arxo_codegen/targets/lua/emit.py +250 -0
  72. arxo_codegen/targets/lua/json.lua +133 -0
  73. arxo_codegen/targets/lua/runner.lua +167 -0
  74. arxo_codegen/targets/lua/runtime.lua +541 -0
  75. arxo_codegen/targets/php/cert.php +84 -0
  76. arxo_codegen/targets/php/emit.py +229 -0
  77. arxo_codegen/targets/php/json.php +144 -0
  78. arxo_codegen/targets/php/runner.php +189 -0
  79. arxo_codegen/targets/php/runtime.php +660 -0
  80. arxo_codegen/targets/py/api_base.py +334 -0
  81. arxo_codegen/targets/py/apicheck.py +51 -0
  82. arxo_codegen/targets/py/cert.py +140 -0
  83. arxo_codegen/targets/py/emit.py +1140 -0
  84. arxo_codegen/targets/py/evaluate.py +980 -0
  85. arxo_codegen/targets/py/runner.py +38 -0
  86. arxo_codegen/targets/py/runtime.py +1634 -0
  87. arxo_codegen/targets/rb/cert.rb +73 -0
  88. arxo_codegen/targets/rb/emit.py +203 -0
  89. arxo_codegen/targets/rb/runner.rb +130 -0
  90. arxo_codegen/targets/rb/runtime.rb +255 -0
  91. arxo_codegen/targets/rs/Cargo.lock +142 -0
  92. arxo_codegen/targets/rs/Cargo.toml +16 -0
  93. arxo_codegen/targets/rs/cert.rs +106 -0
  94. arxo_codegen/targets/rs/emit.py +233 -0
  95. arxo_codegen/targets/rs/prefetch.rs +1 -0
  96. arxo_codegen/targets/rs/runner.rs +181 -0
  97. arxo_codegen/targets/rs/runtime.rs +448 -0
  98. arxo_codegen/targets/scala/Cert.scala +77 -0
  99. arxo_codegen/targets/scala/Json.scala +140 -0
  100. arxo_codegen/targets/scala/Runner.scala +121 -0
  101. arxo_codegen/targets/scala/Runtime.scala +269 -0
  102. arxo_codegen/targets/scala/emit.py +193 -0
  103. arxo_codegen/targets/swift/cert.swift +105 -0
  104. arxo_codegen/targets/swift/emit.py +231 -0
  105. arxo_codegen/targets/swift/json.swift +208 -0
  106. arxo_codegen/targets/swift/runner.swift +133 -0
  107. arxo_codegen/targets/swift/runtime.swift +528 -0
  108. arxo_codegen/targets/ts/apiBase.ts +250 -0
  109. arxo_codegen/targets/ts/apicheck.ts +37 -0
  110. arxo_codegen/targets/ts/cert.ts +96 -0
  111. arxo_codegen/targets/ts/emit.py +1214 -0
  112. arxo_codegen/targets/ts/evaluate.ts +894 -0
  113. arxo_codegen/targets/ts/package-lock.json +45 -0
  114. arxo_codegen/targets/ts/package.json +9 -0
  115. arxo_codegen/targets/ts/runner.ts +31 -0
  116. arxo_codegen/targets/ts/runtime.ts +1369 -0
  117. arxo_codegen/targets/xlsx/README.ru.md +176 -0
  118. arxo_codegen/targets/xlsx/emit.py +198 -0
  119. arxo_codegen/temporal.py +59 -0
  120. arxo_codegen/test_alias_types.py +171 -0
  121. arxo_codegen/test_api_contract.py +89 -0
  122. arxo_codegen/test_calendar_policy.py +48 -0
  123. arxo_codegen/test_check.py +49 -0
  124. arxo_codegen/test_check_active_canaries.py +96 -0
  125. arxo_codegen/test_check_conformance.py +132 -0
  126. arxo_codegen/test_check_semantic_probes.py +85 -0
  127. arxo_codegen/test_check_xlsx.py +52 -0
  128. arxo_codegen/test_consumer_runner.py +175 -0
  129. arxo_codegen/test_core_support.py +80 -0
  130. arxo_codegen/test_e0212_decision_time.py +63 -0
  131. arxo_codegen/test_head_aggregate.py +71 -0
  132. arxo_codegen/test_inert.py +143 -0
  133. arxo_codegen/test_instant_types.py +113 -0
  134. arxo_codegen/test_key_conflict_scope.py +92 -0
  135. arxo_codegen/test_key_conflict_targets.py +17 -0
  136. arxo_codegen/test_package_layout.py +163 -0
  137. arxo_codegen/test_plan_language_version.py +44 -0
  138. arxo_codegen/test_positions_refusal.py +43 -0
  139. arxo_codegen/test_recertify_registry.py +77 -0
  140. arxo_codegen/test_ruby_target.py +41 -0
  141. arxo_codegen/test_runtime_cert.py +83 -0
  142. arxo_codegen/test_secondary_key_conflict_scope.py +17 -0
  143. arxo_codegen/test_stage_r.py +108 -0
  144. arxo_codegen/test_standalone_inputs.py +71 -0
  145. arxo_codegen/test_support.py +150 -0
  146. arxo_codegen/test_survey_inputs.py +115 -0
  147. arxo_codegen-0.4.0.dist-info/LICENSE +202 -0
  148. arxo_codegen-0.4.0.dist-info/METADATA +1673 -0
  149. arxo_codegen-0.4.0.dist-info/RECORD +152 -0
  150. arxo_codegen-0.4.0.dist-info/WHEEL +5 -0
  151. arxo_codegen-0.4.0.dist-info/entry_points.txt +13 -0
  152. arxo_codegen-0.4.0.dist-info/top_level.txt +1 -0
arxo_codegen/inert.py ADDED
@@ -0,0 +1,91 @@
1
+ """Манифест инертных конструкций среза (CODEGEN-COVERAGE-PLAN §1.1, W1).
2
+
3
+ Статус «инертна»: конструкция присутствует в пакете, но на ответ поддержанных
4
+ видов вопросов не влияет; план её пропускает, а не отвергает. Пропуск
5
+ закрепляется строкой манифеста `inert-nodes.json` и ДОКАЗЫВАЕТСЯ парой
6
+ векторов: половина с конструкцией (`witness`) и половина без неё (`bare`)
7
+ над одной программой, делом и вопросом дают у оракула один документ по
8
+ `results`, `positions`, `issues`, `conflicts`, `proofGraph`; `manifest` и
9
+ `resultHash` различаются по построению (§209 покрывает конверт, §208 —
10
+ manifest). Ворота conformance требуют: обе половины экспортированы, половина
11
+ с конструкцией совпала с голденом на каждой активной цели, голдены половин
12
+ совпадают по перечисленным ключам. Строка без такого свидетеля — отказ ворот.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ from pathlib import Path
18
+
19
+ HERE = Path(__file__).resolve().parent
20
+ MANIFEST = HERE / "inert-nodes.json"
21
+ FORMAT = "law.codegen-inert-nodes/0.1"
22
+ #: Ключи evaluation-документа, по которым половины пары обязаны совпасть.
23
+ DOCUMENT_KEYS = ("results", "positions", "issues", "conflicts", "proofGraph")
24
+ FAMILIES = ("node:", "rulefield:")
25
+
26
+
27
+ def load(path: Path = MANIFEST) -> dict:
28
+ manifest = json.loads(path.read_text(encoding="utf-8"))
29
+ if manifest.get("format") != FORMAT or not isinstance(manifest.get("constructs"), dict):
30
+ raise ValueError(f"манифест инертности не {FORMAT}: {path}")
31
+ for construct, row in manifest["constructs"].items():
32
+ if not construct.startswith(FAMILIES):
33
+ raise ValueError(f"манифест инертности: конструкция вне семейств {FAMILIES}: {construct}")
34
+ if not isinstance(row, dict) or not all(isinstance(row.get(k), str) and row[k] for k in ("witness", "bare")):
35
+ raise ValueError(f"манифест инертности: {construct} без пары witness/bare")
36
+ if row["witness"] == row["bare"]:
37
+ raise ValueError(f"манифест инертности: {construct} — одна половина названа дважды")
38
+ return manifest
39
+
40
+
41
+ def constructs(path: Path = MANIFEST) -> dict[str, dict]:
42
+ return load(path)["constructs"]
43
+
44
+
45
+ def node_kinds(manifest: dict) -> frozenset[str]:
46
+ return frozenset(c.removeprefix("node:") for c in manifest["constructs"] if c.startswith("node:"))
47
+
48
+
49
+ def rule_fields(manifest: dict) -> frozenset[str]:
50
+ return frozenset(c.removeprefix("rulefield:") for c in manifest["constructs"] if c.startswith("rulefield:"))
51
+
52
+
53
+ def _document(vectors: Path, ident: str, index: dict[str, Path]) -> dict | None:
54
+ directory = index.get(ident)
55
+ if directory is None:
56
+ return None
57
+ golden = directory / "expected.json"
58
+ if not golden.is_file():
59
+ return None
60
+ return json.loads(golden.read_text(encoding="utf-8"))
61
+
62
+
63
+ def witness_failures(manifest: dict, rows: list[dict], vectors: Path) -> tuple[list[dict], list[str]]:
64
+ """Свидетели каждой строки манифеста против отчёта conformance.
65
+
66
+ `rows` — строки `report["vectors"]` (`id`, `actual`), `vectors` — каталог
67
+ экспортированных векторов. Возвращает таблицу свидетелей и список отказов.
68
+ """
69
+ actual = {row["id"]: row.get("actual") for row in rows}
70
+ index = {d.name: d for d in vectors.rglob("*") if d.is_dir() and (d / "expected.json").is_file()}
71
+ table, failures = [], []
72
+ for construct, row in sorted(manifest["constructs"].items()):
73
+ witness, bare = row["witness"], row["bare"]
74
+ entry = {"construct": construct, "witness": witness, "bare": bare,
75
+ "witnessOutcome": actual.get(witness), "bareOutcome": actual.get(bare)}
76
+ for ident in (witness, bare):
77
+ if ident not in actual:
78
+ failures.append(f"{construct}: свидетель {ident} не среди активных векторов")
79
+ elif actual[ident] != "match":
80
+ failures.append(f"{construct}: свидетель {ident} — «{actual[ident]}», а не совпадение")
81
+ docs = (_document(vectors, witness, index), _document(vectors, bare, index))
82
+ if None in docs:
83
+ failures.append(f"{construct}: у половины пары нет голдена expected.json")
84
+ entry["documentsAgree"] = None
85
+ else:
86
+ differing = [k for k in DOCUMENT_KEYS if docs[0].get(k) != docs[1].get(k)]
87
+ entry["documentsAgree"] = not differing
88
+ if differing:
89
+ failures.append(f"{construct}: половины пары расходятся по {', '.join(differing)} — конструкция не инертна")
90
+ table.append(entry)
91
+ return table, failures
arxo_codegen/inputs.py ADDED
@@ -0,0 +1,59 @@
1
+ """Explicit inputs for standalone code generation; no repository discovery."""
2
+ from __future__ import annotations
3
+
4
+ import hashlib
5
+ import json
6
+ from pathlib import Path
7
+
8
+ from plan import Refused
9
+
10
+
11
+ def dependency_index(documents: list[dict]) -> dict[str, dict]:
12
+ result = {}
13
+ for document in documents:
14
+ name = (document.get("package") or {}).get("name")
15
+ if not isinstance(name, str) or not name:
16
+ raise Refused("зависимость CLIR без имени пакета")
17
+ if name in result:
18
+ raise Refused(f"неоднозначная зависимость CLIR: {name}")
19
+ result[name] = document
20
+ return result
21
+
22
+
23
+ def load_resources(manifest: Path) -> dict[str, bytes]:
24
+ root = manifest.resolve().parent
25
+ entries = json.loads(manifest.read_text(encoding="utf-8"))
26
+ if not isinstance(entries, dict):
27
+ raise Refused("ресурсы: ожидается объект URI → {path, sha256}")
28
+ resources = {}
29
+ for uri, entry in entries.items():
30
+ if (not isinstance(entry, dict) or set(entry) != {"path", "sha256"}
31
+ or not isinstance(entry["path"], str) or not isinstance(entry["sha256"], str)):
32
+ raise Refused(f"ресурсы: некорректная запись {uri}")
33
+ path = (root / entry["path"]).resolve()
34
+ if not path.is_relative_to(root):
35
+ raise Refused(f"ресурсы: путь вне комплекта {uri}")
36
+ if not path.is_file():
37
+ raise Refused(f"ресурсы: нет файла {uri}")
38
+ data = path.read_bytes()
39
+ if "sha256:" + hashlib.sha256(data).hexdigest() != entry["sha256"]:
40
+ raise Refused(f"ресурсы: неверный хэш {uri}")
41
+ resources[uri] = data
42
+ return resources
43
+
44
+
45
+ def corpus_resources(documents: list[dict], root: Path) -> dict[str, bytes]:
46
+ """Read only declared artifact resources beneath an explicitly selected root."""
47
+ root = Path(root).resolve()
48
+ resources = {}
49
+ for document in documents:
50
+ for node in document.get("nodes", []):
51
+ uri = node.get("resourceUri", "")
52
+ if node.get("kind") != "calendar_snapshot" or not isinstance(uri, str) or not uri.startswith("artifact:"):
53
+ continue
54
+ path = (root / uri[len("artifact:"):]).resolve()
55
+ if not path.is_relative_to(root):
56
+ raise Refused("resource artifact escapes explicit corpus root")
57
+ if path.is_file():
58
+ resources[uri] = path.read_bytes()
59
+ return resources