cortex-loop 0.1.0a1__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 (52) hide show
  1. cortex/__init__.py +7 -0
  2. cortex/adapters.py +339 -0
  3. cortex/blocklist.py +51 -0
  4. cortex/challenges.py +210 -0
  5. cortex/cli.py +7 -0
  6. cortex/core.py +601 -0
  7. cortex/core_helpers.py +190 -0
  8. cortex/data/identity_preamble.md +5 -0
  9. cortex/data/layer1_part_a.md +65 -0
  10. cortex/data/layer1_part_b.md +17 -0
  11. cortex/executive.py +295 -0
  12. cortex/foundation.py +185 -0
  13. cortex/genome.py +348 -0
  14. cortex/graveyard.py +226 -0
  15. cortex/hooks/__init__.py +27 -0
  16. cortex/hooks/_shared.py +167 -0
  17. cortex/hooks/post_tool_use.py +13 -0
  18. cortex/hooks/pre_tool_use.py +13 -0
  19. cortex/hooks/session_start.py +13 -0
  20. cortex/hooks/stop.py +13 -0
  21. cortex/invariants.py +258 -0
  22. cortex/packs.py +118 -0
  23. cortex/repomap.py +6 -0
  24. cortex/requirements.py +497 -0
  25. cortex/retry.py +312 -0
  26. cortex/stop_contract.py +217 -0
  27. cortex/stop_payload.py +122 -0
  28. cortex/stop_policy.py +100 -0
  29. cortex/stop_runtime.py +400 -0
  30. cortex/stop_signals.py +75 -0
  31. cortex/store.py +793 -0
  32. cortex/templates/__init__.py +10 -0
  33. cortex/utils.py +58 -0
  34. cortex_loop-0.1.0a1.dist-info/METADATA +121 -0
  35. cortex_loop-0.1.0a1.dist-info/RECORD +52 -0
  36. cortex_loop-0.1.0a1.dist-info/WHEEL +5 -0
  37. cortex_loop-0.1.0a1.dist-info/entry_points.txt +3 -0
  38. cortex_loop-0.1.0a1.dist-info/licenses/LICENSE +21 -0
  39. cortex_loop-0.1.0a1.dist-info/top_level.txt +3 -0
  40. cortex_ops_cli/__init__.py +3 -0
  41. cortex_ops_cli/_adapter_validation.py +119 -0
  42. cortex_ops_cli/_check_report.py +454 -0
  43. cortex_ops_cli/_check_report_output.py +270 -0
  44. cortex_ops_cli/_openai_bridge_probe.py +241 -0
  45. cortex_ops_cli/_openai_bridge_protocol.py +469 -0
  46. cortex_ops_cli/_runtime_profile_templates.py +341 -0
  47. cortex_ops_cli/_runtime_profiles.py +445 -0
  48. cortex_ops_cli/gemini_hooks.py +301 -0
  49. cortex_ops_cli/main.py +911 -0
  50. cortex_ops_cli/openai_app_server_bridge.py +375 -0
  51. cortex_repomap/__init__.py +1 -0
  52. cortex_repomap/engine.py +1201 -0
@@ -0,0 +1,10 @@
1
+ """Built-in challenge template identifiers for Cortex."""
2
+
3
+ BUILTIN_CHALLENGE_TEMPLATES = {
4
+ "null_inputs": "Require tests for None/null/empty inputs and missing optional fields.",
5
+ "boundary_values": "Require tests at min/max/zero/one/off-by-one boundaries.",
6
+ "error_handling": "Require tests for expected failure paths and exception handling.",
7
+ "graveyard_regression": "Require tests covering relevant previously failed approaches.",
8
+ }
9
+
10
+ __all__ = ["BUILTIN_CHALLENGE_TEMPLATES"]
cortex/utils.py ADDED
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+
8
+ def _as_bool(value: Any, default: bool) -> bool:
9
+ if isinstance(value, bool):
10
+ return value
11
+ if isinstance(value, str):
12
+ lowered = value.strip().lower()
13
+ if lowered in {"true", "yes", "on", "1"}:
14
+ return True
15
+ if lowered in {"false", "no", "off", "0"}:
16
+ return False
17
+ return default
18
+
19
+
20
+ def _as_string_list(value: Any) -> list[str]:
21
+ if isinstance(value, str):
22
+ text = value.strip()
23
+ return [text] if text else []
24
+ if isinstance(value, (list, tuple)):
25
+ return [text for v in value if v is not None for text in [str(v).strip()] if text]
26
+ return []
27
+
28
+
29
+ def _unique_list(values: list[str]) -> list[str]:
30
+ seen: set[str] = set()
31
+ out: list[str] = []
32
+ for value in values:
33
+ if value in seen:
34
+ continue
35
+ seen.add(value)
36
+ out.append(value)
37
+ return out
38
+
39
+
40
+ def _normalize_repo_relative_path(value: str, *, root: Path) -> str | None:
41
+ raw = str(value).strip().strip("'\"")
42
+ if not raw or raw.startswith(("http://", "https://")):
43
+ return None
44
+ raw = raw.split("#", 1)[0].strip()
45
+ raw = re.sub(r":\d+(?::\d+|-\d+)?$", "", raw).strip().rstrip(".,;:")
46
+ if not raw:
47
+ return None
48
+ raw = raw.replace("\\", "/")
49
+ if raw.startswith("./"):
50
+ raw = raw[2:]
51
+ candidate = Path(raw).expanduser()
52
+ if not candidate.is_absolute():
53
+ candidate = root / candidate
54
+ resolved = candidate.resolve()
55
+ try:
56
+ return resolved.relative_to(root).as_posix()
57
+ except ValueError:
58
+ return None
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: cortex-loop
3
+ Version: 0.1.0a1
4
+ Summary: Runtime-agnostic enforcement layer for AI coding agents
5
+ Author: Cortex contributors
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/cortex-loop/cortex-loop
8
+ Project-URL: Repository, https://github.com/cortex-loop/cortex-loop
9
+ Project-URL: Issues, https://github.com/cortex-loop/cortex-loop/issues
10
+ Keywords: ai,coding-agent,enforcement,verification,runtime-agnostic
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Intended Audience :: Developers
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Provides-Extra: repomap
21
+ Requires-Dist: grep-ast==0.9.0; extra == "repomap"
22
+ Requires-Dist: numpy>=2.0; extra == "repomap"
23
+ Requires-Dist: networkx==3.4.2; extra == "repomap"
24
+ Requires-Dist: tree-sitter-language-pack==0.13.0; extra == "repomap"
25
+ Requires-Dist: tree-sitter==0.25.2; extra == "repomap"
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.2; extra == "dev"
28
+ Requires-Dist: pytest>=8.0; extra == "dev"
29
+ Requires-Dist: ruff>=0.3; extra == "dev"
30
+ Requires-Dist: twine>=6.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ ![cortex-loop banner](docs/assets/cortex-loop-banner.webp)
34
+
35
+ # Cortex
36
+
37
+ Cortex is a runtime-agnostic enforcement layer for AI coding agents. It verifies completion claims through a deterministic stop path instead of trusting summaries, so "done" only lands when the evidence is real. Coding agents can sound finished before reality has caught up; Cortex turns that completion claim into something the system can prove or deny.
38
+
39
+ With Cortex, the path of least resistance becomes the path of best practice: the easiest way to finish is to do the work, satisfy the evidence boundary, and let the stop path close honestly.
40
+
41
+ The stop path is the product. Cortex is not a planning framework, generic memory layer, or workflow wrapper. It exists to make completion claims legible, checkable, and hard to bluff.
42
+
43
+ ## Runtime Status
44
+
45
+ | Runtime | Install profile | Status | Notes |
46
+ | --- | --- | --- | --- |
47
+ | Claude Code | `cortex runtime install --profile claude` | Shipped | Strongest current runtime. The truthful boundary is live-proven; remaining caveats are minor. |
48
+ | Gemini CLI | `cortex runtime install --profile gemini` | Shipped with watchlist | The truthful boundary is live-proven. One operational watchlist remains: blocked malformed stops can leave Gemini CLI resident until operator termination. |
49
+ | OpenAI Codex App Server | `cortex runtime install --profile openai` | Experimental | Several critical paths are proven on the latest stable surface, but positive strict close is still not dependable enough for broader support. |
50
+
51
+ Status labels in this table:
52
+ - `Shipped`: live-proven on the shared harness; remaining caveats are non-critical.
53
+ - `Shipped with watchlist`: live-proven, but one named runtime quirk still creates real operator risk.
54
+ - `Experimental`: several important paths are proven, but one boundary-critical guarantee remains unproven or unstable.
55
+
56
+ Detailed runtime release evidence lives in [docs/ADAPTER_VALIDATION.md](docs/ADAPTER_VALIDATION.md) plus committed provenance under [tests/fixtures/adapter_validation/claude/PROVENANCE.json](tests/fixtures/adapter_validation/claude/PROVENANCE.json), [tests/fixtures/adapter_validation/gemini/PROVENANCE.json](tests/fixtures/adapter_validation/gemini/PROVENANCE.json), and [tests/fixtures/adapter_validation/openai/PROVENANCE.json](tests/fixtures/adapter_validation/openai/PROVENANCE.json).
57
+
58
+ ## Quickstart
59
+
60
+ As of 2026-03-07, `cortex-loop` is not yet published on PyPI. Until live
61
+ package publication is proven, the truthful first-run path is from a repo
62
+ checkout:
63
+
64
+ ```bash
65
+ python3 -m venv .venv
66
+ . .venv/bin/activate
67
+ python -m pip install . pytest
68
+ cortex init
69
+ cortex runtime install --profile claude
70
+ ```
71
+
72
+ Before `cortex check`, choose the baseline that matches the repository:
73
+
74
+ - trusted local repo: switch `cortex.toml` to the trusted-host baseline in
75
+ [docs/SECURE_DEFAULTS.md](docs/SECURE_DEFAULTS.md)
76
+ - untrusted or container baseline: keep the defaults and ensure Docker is on
77
+ `PATH`
78
+
79
+ Then run:
80
+
81
+ ```bash
82
+ cortex check
83
+ ```
84
+
85
+ The staged public install posture, update and uninstall commands, and the PyPI
86
+ publication gate live in [docs/INSTALL.md](docs/INSTALL.md).
87
+
88
+ For a first evaluation, keep `claude`. Use `gemini` when you want the shipped
89
+ watchlist surface. Use `openai` only when you are explicitly evaluating the
90
+ experimental surface.
91
+
92
+ ## What Cortex Enforces
93
+
94
+ - Stop-claim normalization and strict payload handling ([tests/test_stop_contract.py](tests/test_stop_contract.py))
95
+ - Challenge coverage across active categories ([tests/test_challenges.py](tests/test_challenges.py))
96
+ - Invariant execution outside model output ([tests/test_invariants.py](tests/test_invariants.py))
97
+ - Deterministic verdict policy ([tests/test_stop_policy.py](tests/test_stop_policy.py))
98
+ - Session-scoped failure memory and retry controls ([tests/test_retry.py](tests/test_retry.py), [tests/test_graveyard.py](tests/test_graveyard.py))
99
+
100
+ ## What Cortex Is Not
101
+
102
+ - not a generic multi-agent framework
103
+ - not prompt theater that trusts summaries
104
+ - not a workflow layer whose main job is planning or project management
105
+
106
+ ## Read Next
107
+
108
+ 1. [START_HERE.md](START_HERE.md)
109
+ 2. [ARCHITECTURE.md](ARCHITECTURE.md)
110
+ 3. [MISSION.md](MISSION.md)
111
+ 4. [docs/README.md](docs/README.md)
112
+ 5. [CONTRIBUTING.md](CONTRIBUTING.md)
113
+
114
+ ## Repository Boundaries
115
+
116
+ - Product-critical code lives in `cortex/`, `cortex_ops_cli/`, `cortex_repomap/`, runtime profile templates, and core tests.
117
+ - Extension manifests live in `packs/`; this repo's pack validation suites live in `tests/packs/`.
118
+ - `eval/` is internal and historical validation only. It is not a downstream product interface or product design authority.
119
+ - `docs/archive/` and `_governance_archive/` are historical context, not active authority.
120
+
121
+ v0.1 remains kernel-first: one hardened kernel, one reference pack, and runtime adapters with capture-backed tests.
@@ -0,0 +1,52 @@
1
+ cortex/__init__.py,sha256=cwzWyrl6tMawCTOEHhOcu-rhj64cq0v_kt8poslR-oI,147
2
+ cortex/adapters.py,sha256=9nDohD-xYtSVPRPKayVXqa13PDUibXN3FU9R_TbKcIs,12709
3
+ cortex/blocklist.py,sha256=mVgdIfzgC2iHbEeZ0pnxcxWQY8duVw4feg7Ex12YBPA,1231
4
+ cortex/challenges.py,sha256=ULgpv4YvRfFJ75jIyxVIG_ElMpj13gZqeXJ834GVdZE,9075
5
+ cortex/cli.py,sha256=_rcsSIwtyiljl0iBTFIRj8ZihLOpNpqasT-Xpqefgt4,439
6
+ cortex/core.py,sha256=CjUER-W45sXLU7vqz65BO-X8P7SEvu1fGEH3ijfb5KI,26158
7
+ cortex/core_helpers.py,sha256=GB8l7ey1M9l9pXYR8amCmc1EIoGVr6BvfX1PP2vsxEk,6897
8
+ cortex/executive.py,sha256=Vzui9PBszEaaxw5-6iU-gtBS-8m4kM-9quOhIKJQrko,11843
9
+ cortex/foundation.py,sha256=NL6XnDQ_k46gX88VxAkdvhjpkJPH-i4i83RT2twFpxM,6580
10
+ cortex/genome.py,sha256=RyCMSztvFbIApfJ6gf_9Yc8GP3KeMuo1fqLIlCs2GU0,16599
11
+ cortex/graveyard.py,sha256=1QckuRFMbfmfGIRjOqcSbuvhabcDOCayhJBa81qb5bM,7936
12
+ cortex/invariants.py,sha256=ZBKCrOkJiDe6WdXv72PKneY4hFCIIyWELQ8YJ82XK3k,10229
13
+ cortex/packs.py,sha256=ZB8yk1S9bD1slaXgXuobn4Gw2F5JpnRJgx_WzGSPQXI,4565
14
+ cortex/repomap.py,sha256=NnEGnhpJzszqlBGme0MsAr-dPk7Zx6pY7waQ4ERQaeE,369
15
+ cortex/requirements.py,sha256=Io_yZw1-wwS4dGSGFPYoY0o5tOfVGeSk-9uxvYIYN3k,21472
16
+ cortex/retry.py,sha256=GhOCtvqORF_Q4MpGtZCeROvUhyqGQ9v00LHdZI0N9Uo,11270
17
+ cortex/stop_contract.py,sha256=kjoeFywrFnD4Kzn_gzrkiqiAMu9zO73m_cE56BIbfG0,8691
18
+ cortex/stop_payload.py,sha256=QJADV0ngCqHDPFKl8TjWOCntpeRlyqZwDqQ6NR_hPEY,4239
19
+ cortex/stop_policy.py,sha256=sNJO1feiS6G4AqRHTCkyAgCcPAk_bW2Ud3l1O2oBtRg,3173
20
+ cortex/stop_runtime.py,sha256=TGu2u0Yr3DNBqnQSWS5lQ95MJBtCxf6lY3cHNpnqUEA,18845
21
+ cortex/stop_signals.py,sha256=zO0WtPevYC6wdBGIxyMIA6hmN-IpLZxQwS2-cjflbdk,2688
22
+ cortex/store.py,sha256=QsYfzpPETcnPrVM9fsz7qU-Ffe9f2k2wtNtFlh6_e9c,29701
23
+ cortex/utils.py,sha256=DWew3WVmMelwtAg6Oe_xx-9eI4KJp2JRUDMmAqA8wR0,1653
24
+ cortex/data/identity_preamble.md,sha256=rkR0eVyUnY0P9MsFefg9OUFUeo0mHD95YEfVdJlfU1U,527
25
+ cortex/data/layer1_part_a.md,sha256=_biyFF7QnRzGuHKGHOgfr9BQDgl5BQVrPkvMQ4xDcj8,6275
26
+ cortex/data/layer1_part_b.md,sha256=h9xw4HG5TUT4VyyDXWIAWyhxVdKHFbFSxXpcD7STwPA,499
27
+ cortex/hooks/__init__.py,sha256=pMV2LmKpErjPEbyPeVawTCqsBaUwRwvwHjjsxUJo4Eg,784
28
+ cortex/hooks/_shared.py,sha256=G1HU1TIxoqCtDHhQ5IY4Q42fO3_pm7QuNMdsfs2Mm7Q,6224
29
+ cortex/hooks/post_tool_use.py,sha256=0J9xB3Zu-Og4d7XAvKhpyST0S7R_XvYuujQMBtB_GnQ,282
30
+ cortex/hooks/pre_tool_use.py,sha256=ggfu6XjduYfALtdXCPCQO5e40lxKZ-w3HUIp6joEmks,280
31
+ cortex/hooks/session_start.py,sha256=7iDjjTOyNoMud5YfoMA-4a2khs8shziQjTxwe4h-Ui4,283
32
+ cortex/hooks/stop.py,sha256=dlmFgd7q59gdsGVMX84zgDpIFeDtrcdSCpHW_dpyH-Y,266
33
+ cortex/templates/__init__.py,sha256=BLtmAsDpit2J4RipSZJsS-QFBAK_8MMkqYsWX1IDJis,494
34
+ cortex_loop-0.1.0a1.dist-info/licenses/LICENSE,sha256=DaXPE9pxOKJUUhD8aSeRMoM3uS8-AVvrBkaKdc3ZT0A,1076
35
+ cortex_ops_cli/__init__.py,sha256=9EVxmFiWsAoqWJ6br1bc3BxlA71JyOQP28fUHhX2k7E,43
36
+ cortex_ops_cli/_adapter_validation.py,sha256=R2HgLFpZeqawsFx7CwB7awQSDgAcp0WxsMRo9k8_4bw,3979
37
+ cortex_ops_cli/_check_report.py,sha256=RiWORrUTtXcZwNG_SW2OHYdjfXm8Lj3iU_kmRXHWnMA,19562
38
+ cortex_ops_cli/_check_report_output.py,sha256=X1fBIVogxfA36SOpNgbFd-MaoU1PGoYPUn776Sdzw8I,9826
39
+ cortex_ops_cli/_openai_bridge_probe.py,sha256=M90gcTDCOGlkHMcCdp0jePLWlmD_K5-gn7L0F7cAK_w,9131
40
+ cortex_ops_cli/_openai_bridge_protocol.py,sha256=7-QPW02DOSnW0hBXqjwCnEWraPEmutaeutauK5412mg,19744
41
+ cortex_ops_cli/_runtime_profile_templates.py,sha256=GJksAkQEWAG0E2plUOv0n-5eYKXKJMUiuBh9VOO6ZNY,12049
42
+ cortex_ops_cli/_runtime_profiles.py,sha256=ukfFB5aYYG-Jx1We0phwVR0EPa57kg0_DwHwPKBufYg,17611
43
+ cortex_ops_cli/gemini_hooks.py,sha256=QN_GL23-DkImrLZNtM6769tZ7WHdwcmNpDWoJsFWL0I,11535
44
+ cortex_ops_cli/main.py,sha256=Scy8gHaHhDYyBKhf6v4VRmgzAZto-qv4AzVnFyAjC7k,34266
45
+ cortex_ops_cli/openai_app_server_bridge.py,sha256=B_GqLsLE2SddjAmoUGhRTRaWH-QQs0qwbISqwBteO0U,13925
46
+ cortex_repomap/__init__.py,sha256=RveJ9jdSdavpg9kvWTapEiArxITr2c_hqLHI3gv9mwA,41
47
+ cortex_repomap/engine.py,sha256=2A0ysNUlXrnRDuAxiRdMOp6rQBg89OIHT4elktTrBEA,41871
48
+ cortex_loop-0.1.0a1.dist-info/METADATA,sha256=2a8d2fSaibnBRLCTcgo2jXt5Nxdgkoy_0VdMz8iXU7A,6171
49
+ cortex_loop-0.1.0a1.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
50
+ cortex_loop-0.1.0a1.dist-info/entry_points.txt,sha256=PKd9MOWCIC4D_gW3t-X5TLZ4D4KP7EVH2nMQW2eTkQg,73
51
+ cortex_loop-0.1.0a1.dist-info/top_level.txt,sha256=c5dHF6bFp3Fqf48SUkuleOZxtdLDaPZbqTsvgAkNt1Q,37
52
+ cortex_loop-0.1.0a1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cortex = cortex.cli:main
3
+ cortex-loop = cortex.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Cortex contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ cortex
2
+ cortex_ops_cli
3
+ cortex_repomap
@@ -0,0 +1,3 @@
1
+ from .main import main
2
+
3
+ __all__ = ["main"]
@@ -0,0 +1,119 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ from collections.abc import Callable
6
+ from pathlib import Path
7
+
8
+
9
+ VALIDATION_ADAPTERS = ("claude", "gemini", "openai")
10
+ VALIDATION_SCENARIOS = (
11
+ "install_bootstrap",
12
+ "check_wiring",
13
+ "pass_minimal",
14
+ "structured_gap",
15
+ "truth_gap",
16
+ "adapter_caveat",
17
+ )
18
+ PROMPT_SCENARIOS = ("pass_minimal", "structured_gap", "truth_gap")
19
+ HARNESS_TEST_COMMAND = "python -m pytest -q tests/test_normalize_port.py"
20
+
21
+ _PROMPT_FILENAMES = {
22
+ "pass_minimal": "pass_minimal.md",
23
+ "structured_gap": "structured_gap.md",
24
+ "truth_gap": "truth_gap.md",
25
+ }
26
+ _ADAPTER_NOTE_FILENAMES = {
27
+ "claude": "claude_note.md",
28
+ "gemini": "gemini_note.md",
29
+ "openai": "openai_note.md",
30
+ }
31
+ _CONFIG_REPLACEMENTS = (
32
+ ('trust_profile = "untrusted"', 'trust_profile = "trusted"'),
33
+ ('execution_mode = "container"', 'execution_mode = "host"'),
34
+ ("enabled = false", "enabled = true"),
35
+ ("prefer_ast_graph = true", "prefer_ast_graph = false"),
36
+ ('mode = "advisory"', 'mode = "strict"'),
37
+ ("fail_on_missing_challenge_coverage = false", "fail_on_missing_challenge_coverage = true"),
38
+ ("require_requirement_audit = false", "require_requirement_audit = true"),
39
+ ("fail_on_requirement_audit_gap = false", "fail_on_requirement_audit_gap = true"),
40
+ )
41
+
42
+
43
+ def fixtures_root(repo_root: Path) -> Path:
44
+ return repo_root / "tests" / "fixtures" / "adapter_validation"
45
+
46
+
47
+ def project_template_dir(repo_root: Path) -> Path:
48
+ return fixtures_root(repo_root) / "project_template"
49
+
50
+
51
+ def prompts_dir(repo_root: Path) -> Path:
52
+ return fixtures_root(repo_root) / "prompts"
53
+
54
+
55
+ def prompt_path(repo_root: Path, scenario: str) -> Path:
56
+ if scenario not in _PROMPT_FILENAMES:
57
+ raise ValueError(f"Unsupported adapter-validation prompt scenario: {scenario}")
58
+ return prompts_dir(repo_root) / _PROMPT_FILENAMES[scenario]
59
+
60
+
61
+ def adapter_note_path(repo_root: Path, adapter: str) -> Path:
62
+ if adapter not in _ADAPTER_NOTE_FILENAMES:
63
+ raise ValueError(f"Unsupported adapter-validation adapter note: {adapter}")
64
+ return prompts_dir(repo_root) / _ADAPTER_NOTE_FILENAMES[adapter]
65
+
66
+
67
+ def copy_project_template(*, repo_root: Path, root: Path) -> None:
68
+ shutil.copytree(project_template_dir(repo_root), root, dirs_exist_ok=True)
69
+
70
+
71
+ def apply_strict_harness_patch(config_path: Path) -> None:
72
+ text = config_path.read_text(encoding="utf-8")
73
+ for old, new in _CONFIG_REPLACEMENTS:
74
+ if old not in text:
75
+ raise ValueError(f"missing expected config token: {old}")
76
+ text = text.replace(old, new, 1)
77
+ config_path.write_text(text, encoding="utf-8")
78
+
79
+
80
+ def git_init_and_commit(root: Path, *, message: str = "baseline") -> None:
81
+ subprocess.run(["git", "init"], cwd=root, check=True, capture_output=True, text=True)
82
+ subprocess.run(["git", "add", "."], cwd=root, check=True, capture_output=True, text=True)
83
+ subprocess.run(
84
+ [
85
+ "git",
86
+ "-c",
87
+ "user.name=Cortex Tests",
88
+ "-c",
89
+ "user.email=cortex-tests@example.com",
90
+ "commit",
91
+ "-m",
92
+ message,
93
+ ],
94
+ cwd=root,
95
+ check=True,
96
+ capture_output=True,
97
+ text=True,
98
+ )
99
+
100
+
101
+ def bootstrap_project(
102
+ *,
103
+ repo_root: Path,
104
+ root: Path,
105
+ profile: str,
106
+ cli_main: Callable[[list[str]], int],
107
+ ) -> None:
108
+ if profile not in VALIDATION_ADAPTERS:
109
+ raise ValueError(f"Unsupported adapter-validation profile: {profile}")
110
+
111
+ copy_project_template(repo_root=repo_root, root=root)
112
+ init_rc = cli_main(["init", "--root", str(root)])
113
+ if init_rc != 0:
114
+ raise RuntimeError(f"cortex init failed for {root}")
115
+ apply_strict_harness_patch(root / "cortex.toml")
116
+ install_rc = cli_main(["runtime", "install", "--profile", profile, "--root", str(root)])
117
+ if install_rc != 0:
118
+ raise RuntimeError(f"cortex runtime install failed for profile {profile}")
119
+ git_init_and_commit(root)