Skip to content

Commit 1139dba

Browse files
Bordaclaude[bot]codex
committed
refine(codemap): anchor paths at git root, add guards
- Anchor every codemap index and log path at the git toplevel instead of the process working directory, across the provider and all four consumer plugins: queries from a repository subdirectory previously compared subdirectory-relative paths against root-relative index entries (permanent stale, self-heal every call) or derived a different index path than the writer (false no_index), and log shards split across two directories so session joins returned nothing. Provider-side this covers the staleness git anchoring, the memoized single git SHA query, the stale_undetermined verdict when git fails inside a repository, and the log-root resolver; consumer-side it rewrites cc_develop's resolver/scanner/gate and skill bash blocks, cc_foundry's six agent files, and cc_oss's review-mode context block. - Report the index file a query actually loaded as index.index_path, captured at load time rather than recomputed at emission; the codex-rig adapter records it per query, tolerates absence as null for older providers, and reports disagreement with the probe's resolver-derived path as evidence under index_path_divergence instead of reconciling it (structural-context artifact schema version 3). - Compose coexisting codex-rig caveats into stale+degraded instead of letting a stale index mask a coverage gap, and let a targetless standard batch omit target-requiring queries so analysis without --target can report an honest status. - Add fail-closed cache freshness to cc_oss's codemap cache via an index_stamp field (size plus mtime), and read the index under a shared rwgate lease in check-index-currency while raising the helper size ceilings from 50 MB to the engine's 512 MB — the old ceiling reported no_index for any index above 50 MB, measured against this repository's own 131 MB index. - Canonicalize module names from the index instead of sed-based path guessing: resolve_centrality.py gains --modules-only and ordered_modules(), the cc_oss review and dispatch modes query it, and consumer project-name sanitization is dropped for the provider's raw-basename rule. - Add guard infrastructure: new check_codemap_guard.py (MANIFEST-managed vs registry-declared vs provider-CLI taxonomy, wired into audit_static.py and a new check-codemap-guard pre-commit hook), a canonical codemap-context snippet for cc_foundry, and check_cli_flag_drift.py extended to validate flags in a script's own docstring Usage block against its argparse surface with origin tracking. - Align the shared codemap-gates contract with reality: the build route is codemap-py index (the scan-index alias leases in-engine and is a deprecated shim, not ungated as four prose sites claimed), consumer wrappers drop their now-redundant override clauses, and the inject-preamble hook's stale ungated-scan comment and model-facing directive are corrected. - Consolidate the five codemap-py hooks onto a shared _hookutil module for project_name and session_key so path derivation cannot silently diverge between the writer and reader of a session sentinel. - Port setup_scan_env.sh to stdlib-only setup_scan_env.py (Windows-safe, no python3-on-PATH dependency, shared format_scan_args() quoting) with the .sh kept as a deprecated exec shim, and convert claude-skills dispatcher invocations to bare PATH-literal codemap-py form. - Gate new codemap-py code on complexity limits (C901, PLR0911/0912/0915) from the root pyproject.toml via a negated per-file-ignore, refactor check_currency under the gate, and enumerate the six pre-existing offenders as accepted debt. - Correct the codex usage-aggregation docstring to what the README literally claims and record the audit of all 401 captured real turns (exactly one usage event per turn, so max() and sum() are indistinguishable on real data), and add benchmarks/conftest.py so doctest collection can import _bench_common. - Record per-skill codemap route selection in the codex-rig contract with a drift test, and bump plugin versions (codemap-py 0.30.0, codex-rig 0.7.5, cc_foundry 0.46.1, cc_develop 0.22.1, cc_oss 0.28.1, cc_research) with matching CHANGELOG and README updates. --- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: OpenAI Codex <codex@openai.com>
1 parent 67b5006 commit 1139dba

117 files changed

Lines changed: 5937 additions & 996 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-manifests.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: CI manifests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
paths:
8+
- "plugins/**"
9+
- "benchmarks/**"
10+
- "pyproject.toml"
11+
12+
defaults:
13+
run:
14+
shell: bash
15+
16+
jobs:
17+
manifests:
18+
name: manifest ${{ matrix.manifest }} (${{ matrix.os }})
19+
runs-on: ${{ matrix.os }}
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
24+
manifest: ["provider-parity-methodology", "codex-integration", "codex-agentic"]
25+
timeout-minutes: 10
26+
env:
27+
UV_PYTHON: "3.12"
28+
steps:
29+
- name: 📥 Checkout
30+
uses: actions/checkout@v4
31+
32+
# The job-level UV_PYTHON is uv's own equivalent of --python, so no uv run below
33+
# repeats the version; the action input installs that interpreter.
34+
- name: 📦 Install uv and Python
35+
uses: astral-sh/setup-uv@v5
36+
with:
37+
python-version: ${{ env.UV_PYTHON }}
38+
39+
# Manifests are gitignored generated artifacts, so a fresh checkout has none to
40+
# compare against: build first, then --check that a rebuild is byte-identical.
41+
# The builders form a chain — codex-agentic hashes codex-integration.json, and both
42+
# Codex builders read provider-parity-methodology.json — so a job builds every
43+
# manifest its own target depends on before verifying that target alone.
44+
# Bytes are Python-version independent but embed an OS-resolved scan root, so the
45+
# matrix covers operating systems, not interpreter versions.
46+
- name: 🔨 Build provider-parity-methodology
47+
run: uv run --only-group test python benchmarks/build-provider-parity-methodology-manifest.py
48+
49+
- name: 🔨 Build codex-integration
50+
if: matrix.manifest != 'provider-parity-methodology'
51+
run: uv run --only-group test python benchmarks/build-codex-integration-manifest.py
52+
53+
- name: 🔨 Build codex-agentic
54+
if: matrix.manifest == 'codex-agentic'
55+
run: uv run --only-group test python benchmarks/build-codex-agentic-manifest.py
56+
57+
- name: 🔒 Verify ${{ matrix.manifest }} rebuilds byte-identically
58+
run: uv run --only-group test python "benchmarks/build-${{ matrix.manifest }}-manifest.py" --check

.github/workflows/ci-tests.yml

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,31 @@ defaults:
1515
shell: bash
1616

1717
jobs:
18+
codex-rig:
19+
name: codex-rig entrypoints (windows-latest)
20+
runs-on: windows-latest
21+
timeout-minutes: 10
22+
env:
23+
UV_PYTHON: "3.12"
24+
steps:
25+
- name: 📥 Checkout
26+
uses: actions/checkout@v4
27+
28+
# The job-level UV_PYTHON is uv's own equivalent of --python, so no uv run below
29+
# repeats the version; the action input installs that interpreter.
30+
- name: 📦 Install uv and Python
31+
uses: astral-sh/setup-uv@v5
32+
with:
33+
python-version: ${{ env.UV_PYTHON }}
34+
35+
- name: 🪟 Verify native Codex Rig entrypoints
36+
shell: pwsh
37+
run: |
38+
$env:PYTHONDONTWRITEBYTECODE = "1"
39+
uv run --only-group test python plugins/codex-rig/scripts/build_package.py --check
40+
uv run --only-group test python plugins/codex-rig/scripts/validate_package.py
41+
uv run --only-group test python plugins/codex-rig/shared/collect_pr.py --help
42+
1843
tests:
1944
runs-on: ${{ matrix.os }}
2045
strategy:
@@ -28,33 +53,17 @@ jobs:
2853
- name: 📥 Checkout
2954
uses: actions/checkout@v4
3055

31-
- name: 🐍 Set up Python
32-
uses: actions/setup-python@v5
33-
with:
34-
python-version: ${{ matrix.python-version }}
35-
3656
- name: 🟢 Set up Node
3757
uses: actions/setup-node@v4
3858
with:
3959
node-version: "20"
4060

41-
- name: 📦 Install uv
61+
# The action's python-version input sets UV_PYTHON, uv's equivalent of --python,
62+
# so the pytest run below does not repeat the matrix version.
63+
- name: 📦 Install uv and Python
4264
uses: astral-sh/setup-uv@v5
43-
44-
- name: 🔒 Verify deterministic benchmark manifests
45-
run: |
46-
uv run --only-group test --python ${{ matrix.python-version }} python benchmarks/build-provider-parity-methodology-manifest.py --check
47-
uv run --only-group test --python ${{ matrix.python-version }} python benchmarks/build-codex-integration-manifest.py --check
48-
uv run --only-group test --python ${{ matrix.python-version }} python benchmarks/build-codex-agentic-manifest.py --check
65+
with:
66+
python-version: ${{ matrix.python-version }}
4967

5068
- name: 🧪 Run plugin tests (Python bin/ + JS hooks)
51-
run: uv run --only-group test --python ${{ matrix.python-version }} pytest -W error::DeprecationWarning
52-
53-
- name: 🪟 Verify native Codex Rig entrypoints
54-
if: runner.os == 'Windows'
55-
shell: pwsh
56-
run: |
57-
$env:PYTHONDONTWRITEBYTECODE = "1"
58-
uv run --only-group test --python ${{ matrix.python-version }} python plugins/codex-rig/scripts/build_package.py --check
59-
uv run --only-group test --python ${{ matrix.python-version }} python plugins/codex-rig/scripts/validate_package.py
60-
uv run --only-group test --python ${{ matrix.python-version }} python plugins/codex-rig/shared/collect_pr.py --help
69+
run: uv run --only-group test pytest -W error::DeprecationWarning

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,13 @@ repos:
259259
pass_filenames: false
260260
always_run: true
261261

262+
- id: check-codemap-guard
263+
name: 🗺️ unmanaged codemap index-guard copy
264+
language: system
265+
entry: python3 plugins/cc_foundry/bin/check_codemap_guard.py
266+
pass_filenames: false
267+
always_run: true
268+
262269
- id: check-bash-persistence
263270
name: 🫙 shell var persistence across Bash blocks
264271
language: system

benchmarks/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ The current Codex agentic adapter uses all 16 committed BA tasks across `A_plain
109109
bash benchmarks/run-all.sh codex --agentic --dry-run
110110
```
111111

112-
The deterministic review lock is `benchmarks/manifests/codex-agentic.json`; regenerate or verify it with `python3 benchmarks/build-codex-agentic-manifest.py [--check]`. The dedicated human companion records the current manifest SHA, task order, treatment contract, exact approval variable, and retry-inclusive per-cell timeout in seconds. No-model dry runs require no credentials and no paid approval. A paid run requires the exact active machine-manifest SHA and private auth source; the launcher creates a fresh timestamped run directory automatically, with an optional `CODEX_RUN_DIR` override for a new path. Final run checksums attest the result artifacts, invocation launcher, and `source.sha256`; verify the archived source bytes separately with `(cd "$RUN_DIR/.launcher/source" && shasum -a 256 -c ../source.sha256)`. Codex CLI version is recorded as observed provenance only and is not a pinned or admission requirement. Each cell has only the retry-inclusive per-cell timeout; no total-run ceiling or wall-clock environment/CLI control applies. A non-default repetition or selected scope must additionally present the resolver's scope SHA-256.
112+
The deterministic review lock is `benchmarks/manifests/codex-agentic.json`; regenerate or verify it with `uv run python benchmarks/build-codex-agentic-manifest.py [--check]`. The dedicated human companion records the current manifest SHA, task order, treatment contract, exact approval variable, and retry-inclusive per-cell timeout in seconds. No-model dry runs require no credentials and no paid approval. A paid run requires the exact active machine-manifest SHA and private auth source; the launcher creates a fresh timestamped run directory automatically, with an optional `CODEX_RUN_DIR` override for a new path. Final run checksums attest the result artifacts, invocation launcher, and `source.sha256`; verify the archived source bytes separately with `(cd "$RUN_DIR/.launcher/source" && shasum -a 256 -c ../source.sha256)`. Codex CLI version is recorded as observed provenance only and is not a pinned or admission requirement. Each cell has only the retry-inclusive per-cell timeout; no total-run ceiling or wall-clock environment/CLI control applies. A non-default repetition or selected scope must additionally present the resolver's scope SHA-256.
113113

114114
For approval UX, the matching no-model dry run prints a lowercase 16-character SHA-256 scope prefix for copyable `--paid-approval` (or its equivalent approval variable). The complete 64-character scope SHA-256 remains recorded in run metadata and provenance, and the CLI accepts that full value as well. Never mix a prefix or full scope from another dry run with the selected command; regenerate approval after any locked-source change.
115115

benchmarks/_bench_codex/runtime.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,18 @@ def _ingest_usage(result: CodexParseResult, usage: Mapping[str, Any]) -> None:
187187
"""Fold one native usage event into the turn totals and count schema drift.
188188
189189
``max()`` rather than a running sum is deliberate: ``benchmarks/README.md``
190-
records that native Codex input usage is *cumulative within a turn*, so each
191-
usage event restates the turn total and summing would multiply the reported
192-
cost. That semantic is an assumption about the provider, pinned here only by
193-
a synthetic fixture in ``tests/test_codex_runtime.py``
194-
(``test_usage_events_are_treated_as_cumulative_not_additive``) — it has not
195-
been confirmed against a captured real stream. If a future CLI emits per-event
196-
deltas instead, that fixture is the contract to revisit before changing this.
190+
records that native Codex input usage is *cumulative within a turn* — its
191+
literal claim is only that cached input is a subset of gross input; the
192+
stronger reading that each usage event restates the turn total is this
193+
module's interpretation, not the README's assertion. An audit of every
194+
captured real stream (401 turns, 2026-08-13) found exactly one usage-bearing
195+
event per turn, always terminal — so ``max()``, ``sum()`` and last-wins are
196+
indistinguishable on real data and the cumulative property is unobservable
197+
there, while the subset claim held on all 401 events. The semantic stays
198+
pinned only by a synthetic fixture in ``tests/test_codex_runtime.py``
199+
(``test_usage_events_are_treated_as_cumulative_not_additive``). If a future
200+
CLI emits several usage events per turn, that fixture is the contract to
201+
revisit before changing this.
197202
"""
198203
result.raw_usage.update(dict(usage))
199204
for attribute, value in (

benchmarks/build-codex-agentic-manifest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
ROOT = Path(__file__).resolve().parents[1]
1919
BENCHMARKS = ROOT / "benchmarks"
20+
# Self-named so a rename cannot leave the stale-output hint pointing at a missing script.
21+
REBUILD_COMMAND = f"uv run python {Path(__file__).resolve().relative_to(ROOT).as_posix()}"
2022
MANIFESTS = BENCHMARKS / "manifests"
2123
SOURCE_MANIFEST = MANIFESTS / "provider-parity-methodology.json"
2224
TASKS_PATH = BENCHMARKS / "suites" / "tasks-agentic.json"
@@ -337,9 +339,7 @@ def _write_or_check(path: Path, expected: bytes, *, check: bool) -> None:
337339
"""Write one generated artifact or fail closed when it differs."""
338340
if check:
339341
if not path.is_file() or path.read_bytes() != expected:
340-
raise ValueError(
341-
f"generated manifest is stale: {path}; run: python3 benchmarks/build-codex-agentic-manifest.py"
342-
)
342+
raise ValueError(f"generated manifest is stale: {path}; run: {REBUILD_COMMAND}")
343343
return
344344
path.parent.mkdir(parents=True, exist_ok=True)
345345
path.write_bytes(expected)

benchmarks/build-codex-integration-manifest.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
ROOT = Path(__file__).resolve().parents[1]
2424
BENCHMARKS = ROOT / "benchmarks"
25+
# Self-named so a rename cannot leave the stale-output hint pointing at a missing script.
26+
REBUILD_COMMAND = f"uv run python {Path(__file__).resolve().relative_to(ROOT).as_posix()}"
2527
MANIFESTS = BENCHMARKS / "manifests"
2628
SOURCE_MANIFEST = MANIFESTS / "provider-parity-methodology.json"
2729
OUTPUT_MANIFEST = MANIFESTS / "codex-integration.json"
@@ -634,9 +636,7 @@ def _write_or_check(path: Path, expected: bytes, check: bool) -> None:
634636
"""Write one generated record or reject any byte drift in check mode."""
635637
if check:
636638
if not path.is_file() or path.read_bytes() != expected:
637-
raise ValueError(
638-
f"generated record is stale: {path}; run: python3 benchmarks/build-codex-integration-manifest.py"
639-
)
639+
raise ValueError(f"generated record is stale: {path}; run: {REBUILD_COMMAND}")
640640
return
641641
path.write_bytes(expected)
642642

benchmarks/build-provider-parity-methodology-manifest.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
ROOT = Path(__file__).resolve().parents[1]
2323
BENCHMARKS = ROOT / "benchmarks"
24+
# Self-named so a rename cannot leave the stale-output hint pointing at a missing script.
25+
REBUILD_COMMAND = f"uv run python {Path(__file__).resolve().relative_to(ROOT).as_posix()}"
2426
OUTPUT_MANIFEST = BENCHMARKS / "manifests" / "provider-parity-methodology.json"
2527
POLICY_SEED = BENCHMARKS / "policy" / "provider-parity-methodology.json"
2628
POLICY_SEED_SHA256 = "1e5b1cad389513db9402ca2da39f58c1ff9b7cb36b0fdc4a23ce03886e12f1f1"
@@ -372,10 +374,7 @@ def _write_or_check(path: Path, expected: bytes, *, check: bool) -> None:
372374
"""Write generated output or fail closed when its exact bytes are stale."""
373375
if check:
374376
if not path.is_file() or path.read_bytes() != expected:
375-
raise ValueError(
376-
f"generated methodology record is stale: {path}; "
377-
"run: python3 benchmarks/build-provider-parity-methodology-manifest.py"
378-
)
377+
raise ValueError(f"generated methodology record is stale: {path}; run: {REBUILD_COMMAND}")
379378
return
380379
path.write_bytes(expected)
381380

benchmarks/conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""Make ``_bench_common`` and sibling top-level benchmark modules importable at collection.
2+
3+
``--doctest-modules`` (repo-root ``pyproject.toml``) imports every module under
4+
``benchmarks/`` during collection, and ``--import-mode=importlib`` deliberately does
5+
not put a module's parent directory on ``sys.path`` — so ``from _bench_common import
6+
presentation`` fails for any module collected outside ``benchmarks/tests/``, whose own
7+
conftest inserts the directory only for that subtree. This parent-level conftest runs
8+
first for the whole ``benchmarks/`` tree and applies the same insert once.
9+
"""
10+
11+
from __future__ import annotations
12+
13+
import sys
14+
from pathlib import Path
15+
16+
_BENCHMARKS_DIR = Path(__file__).resolve().parent
17+
if str(_BENCHMARKS_DIR) not in sys.path:
18+
sys.path.insert(0, str(_BENCHMARKS_DIR))

benchmarks/run-codex-structural.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,7 +2049,7 @@ def _treatment_artifact_lock_mismatch_message(artifact_name: str) -> str:
20492049
f"installed treatment artifact does not match lock: {artifact_name}. "
20502050
"The local treatment bytes changed after `benchmarks/manifests/codex-integration.json` was generated; "
20512051
"no paid model call was started. Refresh the lock with "
2052-
"`python3 benchmarks/build-codex-integration-manifest.py`, then resolve a new scope for the same study, "
2052+
"`uv run python benchmarks/build-codex-integration-manifest.py`, then resolve a new scope for the same study, "
20532053
"repository, model, and task IDs. Do not reuse the previous --paid-approval value. "
20542054
"If Codex Rig edits are still in progress, regenerate only after the intended local bytes are ready."
20552055
)
@@ -2065,7 +2065,7 @@ def _treatment_artifact_version_mismatch_message(version_drift: Mapping[str, tup
20652065
f"installed treatment version differs from the active manifest ({observed}). "
20662066
"No paid model call was started. The local plugin changed after the treatment manifest was generated. "
20672067
"When the intended local plugin bytes are ready, run "
2068-
"`python3 benchmarks/build-codex-integration-manifest.py`, then resolve a new scope for the same study, "
2068+
"`uv run python benchmarks/build-codex-integration-manifest.py`, then resolve a new scope for the same study, "
20692069
"repository, model, and task IDs. Do not reuse the previous --paid-approval value."
20702070
)
20712071

0 commit comments

Comments
 (0)