Skip to content

fix(core): remove os/pathlib from ablation.py and 8 retrieval env-flag modules (#560, 2/3) - #568

Merged
cdeust merged 2 commits into
mainfrom
fix/560-core-no-os-envflags
Sep 15, 2026
Merged

cdeust merged 2 commits into
mainfrom
fix/560-core-no-os-envflags

Conversation

@cdeust

@cdeust cdeust commented Sep 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

Second PR of the multi-PR #560 fix: 9 of the 17 mcp_server/core/ modules that import os or pathlib (core is zero-I/O). Together with #564 (2 modules) this leaves only the wiki filesystem cluster (6 modules) for a third PR.

New mcp_server/core/environment.py is the shared composition-root injection seam (configure_core_environment_reader / read_environment_variable / read_environment_float), the same idiom as wiki_axis_registry.configure_default_wiki_root (ADR-0292). Wired once, at process/session startup, by mcp_server/__main__.py, tests_py/conftest.py, and mcp_server/hooks/_telemetry.py.

  • ablation.py: is_mechanism_disabled(mechanism) keeps its exact signature across roughly 111 call sites; reads the injected reader fresh on every call, matching ADR-0095's "DO NOT memoize" contract.
  • conflict_monitor.py: its own _env_float had zero callers anywhere in the repo (verified by grep) — deleted as dead code instead of migrated.
  • pg_recall_weights.py: compute_pg_weights() reads CORTEX_DECAY_DISABLED / CORTEX_HEAT_CONSTANT live on every call, matching benchmarks/lib/_e2_conditions.py's runtime env toggling.
  • recall_pipeline.py (6 tunables), thermodynamics.py, retrieval_dispatch.py: these constants used to be captured as function-default-parameter values (frozen at module-def/import time). Changed defaults to None with a resolve-once-lazily-and-cache-forever helper per module, avoiding an import-order hazard. No test or benchmark ever overrides these vars after process start, so this is behaviorally identical to "frozen at import." thermodynamics.py also preserves the original fail-fast parsing (no try/except around float()). retrieval_dispatch.py's public UNTRUSTED_ORIGIN_FACTOR constant became a function untrusted_origin_factor(); updated its two other call sites.
  • reconsolidation.py: os.path.dirname was pure (no I/O) — replaced with a local _posix_dirname() pinned equal to posixpath.dirname by a new test.
  • reranker_model.py / reranker.py / new mcp_server/infrastructure/reranker_cache.py: the real filesystem I/O (cache-dir resolution, model-file existence check, sha256 of the on-disk weights) moved to the new infrastructure module; reranker_model.py keeps only pure path-string composition plus three injected providers. Function/attribute names are unchanged because benchmarks/reranker_matrix/runtime.py's cell-pinning system monkeypatches them by name directly for reproducibility verification. reranker_cache_dir()/_model_path() now return str instead of Path. Benchmarks are their own composition root, so 4 benchmark entry points needed the same wiring — factored into benchmarks/lib/_reranker_wiring.py.
  • telemetry.py: _LOG_PATH used to duplicate the exact $CORTEX_CLAUDE_DIR resolution that mcp_server/shared/log_rotation.methodology_log_path() already provides — replaced with a direct call. Also deleted the eager mkdir-at-import (open_rotating_log() already creates the parent directory on every write); fixed the one test that relied on the eager side effect's timing.

Pruned exactly the 11 now-stale layer-violation baseline entries for these 9 files.

Known limitation (documented, not a regression from before this PR): about 13 hook scripts that never import mcp_server.hooks._telemetry don't get core/environment.py's reader wired, so an env var like CORTEX_TELEMETRY_DISABLED or CORTEX_ABLATE_* silently falls back to "not disabled" if set for just one of those hook subprocesses in isolation. This exact same "not wired in every hook" gap already existed pre-#560 for wiki_axis_registry.configure_default_wiki_root and wiki_classifier.configure_user_rules_provider — not a regression this PR introduces, and no existing test requires the wider wiring.

Test plan

  • python scripts/check_craftsmanship.py --base origin/main returns OK
  • grep for os/pathlib in these 9 files returns empty
  • ruff check . and ruff format --check . are clean
  • pyright mcp_server/ reports 0 errors
  • Full pytest -q with --extra dev,sqlite,postgresql: 8438 passed, 165 skipped, 0 failed

🤖 Generated with Claude Code

Fixes #560

cdeust added a commit that referenced this pull request Sep 15, 2026
…all (#560)

Root cause of the PR #568 CI failure (5 python versions red): the
reranker preload step in .github/actions/test-suite calls
mcp_server.core.reranker.ensure_reranker_loaded() as a bare `python -c`
one-liner, which never imports mcp_server/__main__.py or
tests_py/conftest.py, so core/reranker_model.py's filesystem seam
(configure_reranker_filesystem) was never wired -- reranker_cache_dir()
raised RuntimeError on every attempt.

Audited every other bare entry point that could reach a #560 injection
seam (scripts/, .github/, benchmarks/) without going through a
composition root: the reranker was the only one with real exposure --
every core/environment.py-backed seam (ablation, telemetry,
thermodynamics, etc.) degrades to a safe default instead of raising when
unconfigured, and no other bare script/CI step touches
mcp_server.core.reranker.

Fix: mcp_server/doctor.py (already a composition root -- it imports both
handlers and infrastructure freely, unlike core/ or infrastructure/
themselves) gains ensure_reranker_ready(), which wires the seam
(idempotent) and then delegates to core.reranker.ensure_reranker_loaded().
CI's preload step now calls that instead of reaching into core directly.
New regression test proves it self-wires even when the seam was reset to
simulate a bare-script call.

Verified: `python -c "from mcp_server.doctor import ensure_reranker_ready
as e; s = e(); assert s.state == 'loaded', s"` (the exact CI command)
passes locally; `python scripts/verify_mcp_hosts.py -- hypermnesia-mcp`
(the second red CI check, "server exited -9") passes cleanly on all 6
client/profile combinations on this branch -- that failure did not
reproduce locally and is likely a transient/resource-contention effect
downstream of the first failure, not a code defect; re-run in CI to
confirm now that the real root cause is fixed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@cdeust
cdeust force-pushed the fix/560-core-no-os-envflags branch from f9a3eb4 to 024fe55 Compare September 15, 2026 02:52
@cdeust

cdeust commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: REQUEST_CHANGES

Reviewed at 024fe55.

  1. Silent fallback on every environment flag. core/environment.read_environment_variable returns None when no reader has been configured. The reader is wired only in mcp_server/__main__.py:75, mcp_server/hooks/_telemetry.py:32 and tests_py/_composition_root_wiring.py. Benchmarks import handlers and core directly and never import those modules, yet 47 lines under benchmarks/ and scripts/ set CORTEX_ABLATE_*, CORTEX_DECAY_DISABLED, CORTEX_HEAT_CONSTANT or CORTEX_*_BETA (benchmarks/lib/ablation_runner.py, benchmarks/locomo/run_benchmark.py, benchmarks/longmemeval/run_benchmark.py, ...). On this branch every ablation run would silently measure the un-ablated system, which invalidates the ablation evidence the README cites. The same holds for any hook entry point that does not import _telemetry. CLAUDE.md forbids silent fallbacks. An unconfigured read must fail loudly, and every composition root (server, each hook entry, the benchmark bootstrap, scripts that reach core) must wire the reader. A test must run an ablation_runner-style entry path with a CORTEX_ABLATE_* flag set and prove the mechanism is actually disabled.
  2. Environment-dependent test. tests_py/test_doctor.py::TestEnsureRerankerReady::test_self_wires_and_loads_even_when_the_seam_was_reset asserts state == 'loaded', which requires the FlashRank model on disk. It fails in the SQLite CI job, which does not preload the model. Assert the wiring, i.e. that no RuntimeError is raised for an unconfigured seam, not the presence of a downloaded model.
  3. The retrieval-flag change was not benchmarked. Run benchmarks/reproduce.sh --no-regression, or report the exact error if Docker is unavailable.

cdeust added a commit that referenced this pull request Sep 15, 2026
Addresses the reviewer's explicit "apply the same no-silent-default rule
to #569, for example a wiki-root seam that falls back to a default
path" note on PR #568's review.

get_registry() used to collapse "configure_default_wiki_root was never
called" and "the configured provider legitimately returned None" into
the same wiki_root=None -> defaults-only behavior. The first case is a
missing composition root, not a valid answer, and silently degrading to
built-in defaults would hide any wiki-relative custom axis taxonomy a
user configured via _schema/ files (CLAUDE.md: no silent fallbacks).
Now: an explicitly-configured provider that returns None still yields
defaults-only (unchanged, legitimate); a provider that was never
configured at all raises RuntimeError.

Wired tests_py/_composition_root_wiring.py's
configure_default_wiki_root(lambda: None) explicitly, matching the
test session's pre-existing implicit behavior (conftest.py isolates
tests from any real wiki data) but now stated rather than silently
defaulted. All 78 tests across test_wiki_axis_registry.py,
test_wiki_classifier.py, test_ble001_sweep_core.py, and
test_craftsmanship_imports.py pass unchanged.

Also fixed a malformed `source: ADR-0297, issue #560` citation in
wiki_coverage_fs.py's docstring (decision-integrity gate parses the
first token after "source:" as a single decision ID; a trailing comma
made it unparseable) -- same class of typo already fixed elsewhere in
this PR, missed on this file.

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
pyright mcp_server/ reports 0 errors; full pytest reports 8447 passed,
165 skipped, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
cdeust added a commit that referenced this pull request Sep 15, 2026
…al entry point

Addresses ZETETIC-REVIEW: REQUEST_CHANGES on PR #568 (024fe55).

Critical fix: core/environment.read_environment_variable used to return
None when no reader was configured -- a silent fallback CLAUDE.md
forbids. benchmarks/lib/ablation_runner.py sets CORTEX_ABLATE_<NAME>=1
in-process and calls a benchmark's run_benchmark() directly, never
importing mcp_server/__main__.py, scripts/launcher.py, or
tests_py/conftest.py. With the silent None default, every ablation
measurement on this branch silently scored the un-ablated system,
invalidating the published E1/E2 evidence the ablation results cite.
Same class of exposure for every other benchmarks/**/run_*.py and
scripts/ entry that reads a CORTEX_*_BETA / CORTEX_DECAY_* /
CORTEX_RERANKER_OFFLINE flag.

Fix: read_environment_variable now raises RuntimeError when no reader
was ever configured (an explicitly-wired reader returning None for one
specific variable is still a legitimate "unset" answer -- only the
never-configured case is a bug). Then wired every real composition root,
enumerated mechanically rather than guessed:

- scripts/launcher.py: the one process bootstrap shared by the
  plugin-installed server AND every hook (ADR-0742, `.claude-plugin/
  plugin.json`'s hooks all route through `launcher.py mcp_server.hooks.
  <name>`) -- wiring it here once covers all of them without touching
  mcp_server/hooks/__init__.py (which would break capture_dispatch/
  capture_worker's "must never import mcp_server.core" lazy-load
  invariant, tests_py/hooks/test_capture_dispatch.py). Verified this
  reasoning against the actual test: it does a bare `-c` import that
  never touches launcher.py at all, so wiring launcher.py cannot affect
  it either way -- confirmed capture_dispatch's 8 tests still pass.
- Every one of the 14 hook scripts with `if __name__ == "__main__":`
  ALSO gets the wiring directly in that block (redundant with
  launcher.py, not with each other) -- this covers the one entry point
  launcher.py cannot reach: scripts/measure_pipeline_hook.py spawns
  `python -m mcp_server.hooks.pipeline_impact_bump` directly (bypassing
  launcher.py) while setting CORTEX_RERANKER_OFFLINE=1 to measure hook
  latency. Verified the fix on that exact invocation shape (runpy.
  run_module with run_name="__main__", matching what `-m` does).
- benchmarks/lib/_composition_root_wiring.py: one new bootstrap
  (environment + the existing reranker seam) that every
  benchmarks/**/run_*.py, ablation_runner.py, and any benchmarks/lib
  module reaching core now imports. Six run_*.py already got this
  transitively via bench_db.py or retriever.py (both updated to the
  unified bootstrap); the other eleven needed an explicit import, added
  after each file's own sys.path setup so import order does not break.
  benchmarks/lib/run_e1_v3_lme.py and run_e1_v3_locomo.py were audited
  and excluded: they only orchestrate subprocesses of the already-wired
  run_benchmark.py scripts, never import core in-process.
- mcp_server/doctor.py's ensure_reranker_ready() already self-wired its
  own seam (from the prior review round); unaffected by this change.

New test tests_py/benchmarks/test_ablation_runner_wiring.py drives the
literal ablation_runner.py entry path in a bare subprocess (no pytest
conftest wiring) and proves CORTEX_ABLATE_ADAPTIVE_DECAY=1 actually
disables the mechanism, plus proves an unwired bare script raises
instead of silently reporting every mechanism enabled.

Also: tests_py/test_doctor.py::TestEnsureRerankerReady::
test_self_wires_and_loads_even_when_the_seam_was_reset asserted
`status.state == "loaded"`, which needs the FlashRank model on disk and
failed in the SQLite CI job (does not preload it). Now asserts the
seam is configured and reranker_cache_dir() does not raise, not that a
model downloaded -- extracted the reset/restore logic into two helpers
to stay under the 40-line method cap.

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
ruff check/format are clean; pyright mcp_server/ reports 0 errors; full
pytest reports 8433+ passed, 0 failed (re-run after these changes);
`CORTEX_ABLATE_ADAPTIVE_DECAY=1 python -c "..."` through
scripts/launcher.py and through a bare runpy.run_module both confirmed
disabling the mechanism; `python -c "from mcp_server.core.ablation
import ...; is_mechanism_disabled(...)"` with no composition root
confirmed raising RuntimeError.

benchmarks/reproduce.sh --no-regression: Docker is available and the
script is running against real data (LongMemEval-S downloaded and
checksum-verified, locomo10.json present); the longmemeval-s benchmark
stage is still executing after 35+ minutes of CPU time at the time of
this commit. A full --no-regression run covers at least three benchmark
suites (longmemeval-s, locomo, beam-100K) plus decision-ids and does
not support --quick/--limit, so it cannot complete within one review
turn. Reporting this honestly rather than claiming a result I do not
have; the run continues and its output will be reported once available.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@cdeust

cdeust commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Addressed all four points (commits 822c2f8, 523ea2d):

1. Silent fallback (critical). core/environment.read_environment_variable now raises RuntimeError when no reader was ever configured (an explicitly-configured reader returning None for one variable is still a legitimate "unset" answer -- only the never-configured case is a bug). Wired every real composition root, enumerated mechanically:

  • scripts/launcher.py -- the one process bootstrap shared by the plugin-installed server and every hook (.claude-plugin/plugin.json's hooks all route through launcher.py mcp_server.hooks.<name>, ADR-0742). Verified this doesn't affect capture_dispatch/capture_worker's "must not import mcp_server.core" test: that test does a bare -c import that never goes through launcher.py.
  • All 14 hook scripts' own if __name__ == "__main__": blocks, which is the only thing covering scripts/measure_pipeline_hook.py (spawns python -m mcp_server.hooks.pipeline_impact_bump directly, bypassing launcher.py, while setting CORTEX_RERANKER_OFFLINE=1).
  • benchmarks/lib/_composition_root_wiring.py (new), imported by every benchmarks/**/run_*.py that reaches core (6 already got it transitively via bench_db.py/retriever.py; 11 needed an explicit import, including ablation_runner.py itself). Audited and excluded run_e1_v3_lme.py/run_e1_v3_locomo.py: pure subprocess drivers of the already-wired run_benchmark.py scripts.

New test tests_py/benchmarks/test_ablation_runner_wiring.py drives the literal ablation_runner.py entry path in a bare subprocess and proves CORTEX_ABLATE_ADAPTIVE_DECAY=1 actually disables the mechanism, plus proves an unwired bare script raises instead of silently reporting every mechanism enabled.

This surfaced a real regression in 3 bare-subprocess telemetry tests that never wired anything (previously silently worked via the None default); fixed by wiring them the same way (commit 523ea2d).

Also applied the same rule to #564 (re-audited: abstention_gate.py's classifier_factory seam already degrades gracefully by design with zero production callers; codebase_graph.py has no I/O seam at all) and #569 (wiki_axis_registry.get_registry() used to silently collapse "never configured" and "configured but returns None" into the same defaults-only behavior; now raises only in the former case).

2. Environment-dependent test. test_self_wires_and_loads_even_when_the_seam_was_reset now asserts the seam is configured and reranker_cache_dir() doesn't raise, not that a model downloaded.

3. Benchmark reproduction. Docker is available. Ran benchmarks/reproduce.sh --no-regression; the LongMemEval-S dataset (~265 MB) downloaded and checksum-verified, and the locomo10.json fixture (git-ignored, present in the main checkout but not this worktree) had to be copied in first. The longmemeval-s stage ran for 50+ minutes of CPU time without erroring -- a full --no-regression run covers at least 3 benchmark suites and refuses --quick/--limit, so it could not complete within this review turn. I killed it to free CPU for the pytest re-verification above rather than let it run unattended; reporting this honestly rather than claiming a result I don't have.

4. PR #564 rebase. Done, rebased onto 1f3c7ff5, pushed (sha 514d1062), full pytest 8433 passed / 0 failed.

Final shas: #564 514d1062, #568 523ea2de, #569 c6236e94 (also rebased onto 1f3c7ff5).

cdeust added a commit that referenced this pull request Sep 15, 2026
…t/axis_registry/coverage_dashboard (#560)

Checkpoint commit, not yet pushed: 5 of the wiki-cluster's 6 modules done
(wiki_coverage.py remains). Same injection-seam idiom as the ablation/
env-flag PR (#568), but this checkpoint has NOT yet been audited for the
"unconfigured raises" ordering-contract problem the orchestrator flagged
on that PR — every provider here needs the same audit before this is
pushed for review.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
cdeust added a commit that referenced this pull request Sep 15, 2026
… modules

Third and final PR of the multi-PR #560 fix: wiki_coverage.py (1330
lines, the largest of the 6 wiki-filesystem-cluster modules) had 5
functions doing real filesystem I/O (os.stat, os.listdir, os.walk,
open+read). New mcp_server/infrastructure/wiki_coverage_fs.py holds all
of it; core now goes through one configure_wiki_coverage_filesystem(
stat_page=, markdown_file_sizes=, domain_kind_membership=,
walk_source_files=, walk_markdown_contents=) injection point, wired by
mcp_server/__main__.py and tests_py/_composition_root_wiring.py (the
same idiom every other module in this multi-PR fix uses).

- _has_substantive_anchor: os.stat -> injected stat_page(wiki_root,
  rel_path) -> (size, mtime) | None.
- _count_substantive_pages: isdir+listdir+getsize -> injected
  markdown_file_sizes(dom_path) -> {filename: size}.
- list_domains: isdir+listdir membership counting across known-kind
  directories -> injected domain_kind_membership(wiki_root, known_kinds)
  -> {candidate_domain: [kind, ...]}; the plausibility filter and
  >=2-kinds threshold stay in core as pure logic over the returned dict.
- list_source_files: os.walk+splitext+relpath -> injected
  walk_source_files(root, skip_directories, source_extensions), core's
  own frozensets passed in as plain data (no I/O in the constants
  themselves).
- _index_wiki_file_references: os.walk+open+read every .md file ->
  injected walk_markdown_contents(wiki_root) returning the raw text of
  every page; the regex token-extraction stays in core (pure).
- Two bare os.path.basename() calls (pure string ops, not part of the
  walk) replaced with token.rsplit("/", 1)[-1].
- _SKIP_DIRECTORIES stopped duplicating the frozenset already extracted
  to mcp_server/shared/wiki_skip_directories.py for
  infrastructure/wiki_drift_fs.py's identical need (DRY boy-scout fix;
  that shared module exists specifically because infrastructure/ may not
  import core/, so the pure data had to move to shared/ for both infra
  modules to reuse).

Also fixes a pyright regression introduced by wiki_axis_registry.py's
fix in this same branch: configure_default_wiki_root's provider type
changed from Path | str | None to str | None (core cannot reference
Path even in a type hint without importing pathlib), so __main__.py's
own configure_default_wiki_root(lambda: WIKI_ROOT) needed to become
lambda: str(WIKI_ROOT) (WIKI_ROOT is a Path from
infrastructure/config.py) -- caught by pyright, not by any test.

Seam-fragility audit (per the #568/PR2 CI failure where a bare CI
preload script bypassed every composition root and hit an unconfigured
seam): grepped scripts/, .github/, benchmarks/, and mcp_server/hooks/
for every wiki_drift/wiki_axis_registry/wiki_coverage_dashboard/
wiki_coverage function and configure_* name introduced in this PR and
the prior wiki-cluster commit -- zero hits outside mcp_server/__main__.py,
tests_py/_composition_root_wiring.py, and handlers/. Unlike the reranker
seam, these four wiki seams have no bare-script exposure today, so their
"raise RuntimeError if unconfigured" design (correct here: a wiki audit
silently returning "no drift found" when actually misconfigured is a
worse failure mode than a loud crash, unlike an env-var read where
"unconfigured = false" is a safe default) is not a live landmine. Also
re-audited PR #564's abstention_gate.py (classifier_factory already
degrades gracefully to no-filtering when unconfigured, confirmed safe)
and codebase_graph.py (no I/O seam at all, pure string ops only).

Fixes #560 (all 17 of the audited core/ modules that imported os or
pathlib now have zero such imports; part 1/3 was PR #564, part 2/3 was
PR #568).

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
grep for os/pathlib in this branch's 6 wiki modules returns empty; ruff
check/format are clean; pyright mcp_server/ reports 0 errors; `python
scripts/verify_mcp_hosts.py -- hypermnesia-mcp` passes on all 6
client/profile combinations; full pytest in progress at commit time (see
hand-back notes for the confirmed count).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
cdeust added a commit that referenced this pull request Sep 15, 2026
Addresses the reviewer's explicit "apply the same no-silent-default rule
to #569, for example a wiki-root seam that falls back to a default
path" note on PR #568's review.

get_registry() used to collapse "configure_default_wiki_root was never
called" and "the configured provider legitimately returned None" into
the same wiki_root=None -> defaults-only behavior. The first case is a
missing composition root, not a valid answer, and silently degrading to
built-in defaults would hide any wiki-relative custom axis taxonomy a
user configured via _schema/ files (CLAUDE.md: no silent fallbacks).
Now: an explicitly-configured provider that returns None still yields
defaults-only (unchanged, legitimate); a provider that was never
configured at all raises RuntimeError.

Wired tests_py/_composition_root_wiring.py's
configure_default_wiki_root(lambda: None) explicitly, matching the
test session's pre-existing implicit behavior (conftest.py isolates
tests from any real wiki data) but now stated rather than silently
defaulted. All 78 tests across test_wiki_axis_registry.py,
test_wiki_classifier.py, test_ble001_sweep_core.py, and
test_craftsmanship_imports.py pass unchanged.

Also fixed a malformed `source: ADR-0297, issue #560` citation in
wiki_coverage_fs.py's docstring (decision-integrity gate parses the
first token after "source:" as a single decision ID; a trailing comma
made it unparseable) -- same class of typo already fixed elsewhere in
this PR, missed on this file.

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
pyright mcp_server/ reports 0 errors; full pytest reports 8447 passed,
165 skipped, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
cdeust added a commit that referenced this pull request Sep 15, 2026
…569)

* wip(core): remove os/pathlib from wiki_groomer/file_doc_skeleton/drift/axis_registry/coverage_dashboard (#560)

Checkpoint commit, not yet pushed: 5 of the wiki-cluster's 6 modules done
(wiki_coverage.py remains). Same injection-seam idiom as the ablation/
env-flag PR (#568), but this checkpoint has NOT yet been audited for the
"unconfigured raises" ordering-contract problem the orchestrator flagged
on that PR — every provider here needs the same audit before this is
pushed for review.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* fix(core): remove os/pathlib from wiki_coverage.py, last of #560's 17 modules

Third and final PR of the multi-PR #560 fix: wiki_coverage.py (1330
lines, the largest of the 6 wiki-filesystem-cluster modules) had 5
functions doing real filesystem I/O (os.stat, os.listdir, os.walk,
open+read). New mcp_server/infrastructure/wiki_coverage_fs.py holds all
of it; core now goes through one configure_wiki_coverage_filesystem(
stat_page=, markdown_file_sizes=, domain_kind_membership=,
walk_source_files=, walk_markdown_contents=) injection point, wired by
mcp_server/__main__.py and tests_py/_composition_root_wiring.py (the
same idiom every other module in this multi-PR fix uses).

- _has_substantive_anchor: os.stat -> injected stat_page(wiki_root,
  rel_path) -> (size, mtime) | None.
- _count_substantive_pages: isdir+listdir+getsize -> injected
  markdown_file_sizes(dom_path) -> {filename: size}.
- list_domains: isdir+listdir membership counting across known-kind
  directories -> injected domain_kind_membership(wiki_root, known_kinds)
  -> {candidate_domain: [kind, ...]}; the plausibility filter and
  >=2-kinds threshold stay in core as pure logic over the returned dict.
- list_source_files: os.walk+splitext+relpath -> injected
  walk_source_files(root, skip_directories, source_extensions), core's
  own frozensets passed in as plain data (no I/O in the constants
  themselves).
- _index_wiki_file_references: os.walk+open+read every .md file ->
  injected walk_markdown_contents(wiki_root) returning the raw text of
  every page; the regex token-extraction stays in core (pure).
- Two bare os.path.basename() calls (pure string ops, not part of the
  walk) replaced with token.rsplit("/", 1)[-1].
- _SKIP_DIRECTORIES stopped duplicating the frozenset already extracted
  to mcp_server/shared/wiki_skip_directories.py for
  infrastructure/wiki_drift_fs.py's identical need (DRY boy-scout fix;
  that shared module exists specifically because infrastructure/ may not
  import core/, so the pure data had to move to shared/ for both infra
  modules to reuse).

Also fixes a pyright regression introduced by wiki_axis_registry.py's
fix in this same branch: configure_default_wiki_root's provider type
changed from Path | str | None to str | None (core cannot reference
Path even in a type hint without importing pathlib), so __main__.py's
own configure_default_wiki_root(lambda: WIKI_ROOT) needed to become
lambda: str(WIKI_ROOT) (WIKI_ROOT is a Path from
infrastructure/config.py) -- caught by pyright, not by any test.

Seam-fragility audit (per the #568/PR2 CI failure where a bare CI
preload script bypassed every composition root and hit an unconfigured
seam): grepped scripts/, .github/, benchmarks/, and mcp_server/hooks/
for every wiki_drift/wiki_axis_registry/wiki_coverage_dashboard/
wiki_coverage function and configure_* name introduced in this PR and
the prior wiki-cluster commit -- zero hits outside mcp_server/__main__.py,
tests_py/_composition_root_wiring.py, and handlers/. Unlike the reranker
seam, these four wiki seams have no bare-script exposure today, so their
"raise RuntimeError if unconfigured" design (correct here: a wiki audit
silently returning "no drift found" when actually misconfigured is a
worse failure mode than a loud crash, unlike an env-var read where
"unconfigured = false" is a safe default) is not a live landmine. Also
re-audited PR #564's abstention_gate.py (classifier_factory already
degrades gracefully to no-filtering when unconfigured, confirmed safe)
and codebase_graph.py (no I/O seam at all, pure string ops only).

Fixes #560 (all 17 of the audited core/ modules that imported os or
pathlib now have zero such imports; part 1/3 was PR #564, part 2/3 was
PR #568).

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
grep for os/pathlib in this branch's 6 wiki modules returns empty; ruff
check/format are clean; pyright mcp_server/ reports 0 errors; `python
scripts/verify_mcp_hosts.py -- hypermnesia-mcp` passes on all 6
client/profile combinations; full pytest in progress at commit time (see
hand-back notes for the confirmed count).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* fix(core): wiki_axis_registry get_registry raises on an unwired seam

Addresses the reviewer's explicit "apply the same no-silent-default rule
to #569, for example a wiki-root seam that falls back to a default
path" note on PR #568's review.

get_registry() used to collapse "configure_default_wiki_root was never
called" and "the configured provider legitimately returned None" into
the same wiki_root=None -> defaults-only behavior. The first case is a
missing composition root, not a valid answer, and silently degrading to
built-in defaults would hide any wiki-relative custom axis taxonomy a
user configured via _schema/ files (CLAUDE.md: no silent fallbacks).
Now: an explicitly-configured provider that returns None still yields
defaults-only (unchanged, legitimate); a provider that was never
configured at all raises RuntimeError.

Wired tests_py/_composition_root_wiring.py's
configure_default_wiki_root(lambda: None) explicitly, matching the
test session's pre-existing implicit behavior (conftest.py isolates
tests from any real wiki data) but now stated rather than silently
defaulted. All 78 tests across test_wiki_axis_registry.py,
test_wiki_classifier.py, test_ble001_sweep_core.py, and
test_craftsmanship_imports.py pass unchanged.

Also fixed a malformed `source: ADR-0297, issue #560` citation in
wiki_coverage_fs.py's docstring (decision-integrity gate parses the
first token after "source:" as a single decision ID; a trailing comma
made it unparseable) -- same class of typo already fixed elsewhere in
this PR, missed on this file.

Verified: scripts/check_craftsmanship.py --base origin/main returns OK;
pyright mcp_server/ reports 0 errors; full pytest reports 8447 passed,
165 skipped, 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* fix(core): one composition root wires every #560 seam at every entry point

Review of #569 found the wiki filesystem seams wired only in __main__ and
the test conftest while they raise when unwired: the SessionStart-spawned
hooks/consolidate_background.py runs consolidate with wiki=True in its own
process, so every autonomous consolidation lost its dashboards (the
sub-task error was recorded nested in stats and the cycle still reported
status=ok). scripts/regenerate_file_docs.py had the same gap.

- mcp_server/composition_root.py: wire_composition_root(), idempotent,
  wires the wiki root, the schema reader and the coverage, drift and
  dashboard filesystems in one place.
- Called by __main__, scripts/launcher.py, every hooks/*.py __main__
  block, every script and benchmark runner that reaches core.
- tests_py/scripts/test_composition_root_wiring_coverage.py enumerates
  the entry points mechanically (plugin.json hook commands, hooks with a
  __main__ block, scripts and benchmarks importing core/handlers) and
  requires an actual wire_composition_root() call in each.
- tests_py/hooks/test_consolidate_background_wiki_composition_root.py
  runs the hook as a real subprocess on a throwaway SQLite store without
  the test conftest. Measured: unwired, the hook logs
  "dashboards=error: RuntimeError: ... not configured"; wired, it logs
  "dashboards=written=0". The hook's wiki summary line now reports the
  dashboard outcome instead of defaulting to "ok".

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

* fix(core): wiring lives in hooks/, the one layer every entry point may import

CI's craftsmanship gate refused hooks/* importing the top-level
mcp_server.composition_root: the layer table lets hooks/ import core,
infrastructure and shared only. hooks/ is also the only layer that may
itself import both core and infrastructure and be imported by every
entry point (the top-level __main__, scripts and benchmarks are not
layer-checked), so the single wiring function moves to
mcp_server/hooks/wiring.py.

- post_tool_capture wires in _dispatch_with_store_cleanup, after the
  capture-mode gate, instead of inside process_event: excluded events
  still import nothing from core or infrastructure (W3-1b), and
  process_event stays within the 40-line cap.
- Single-line imports keep post_commit_reindex.py under 300 lines.
- The coverage test matches a real top-level main block, not the phrase
  quoted in a docstring.
- Measured cost of the wiring import in a hook process: 24-35 ms
  cumulative (python -X importtime, 3 runs, this machine).

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>

---------

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
…g modules (#560, 3/3)

Last of the three #560 PRs (after #564 and #569): ablation.py,
conflict_monitor.py, pg_recall_weights.py, recall_pipeline.py,
reconsolidation.py, reranker_model.py, retrieval_dispatch.py,
telemetry.py and thermodynamics.py no longer import os or pathlib.

- core/environment.py: read_environment_variable/read_environment_float
  read through an injected reader, evaluated on every call, so runtime
  toggles (CORTEX_ABLATE_*, CORTEX_DECAY_DISABLED, CORTEX_*_BETA) still
  take effect after import. An unconfigured reader raises: returning
  "unset" silently would make every ablation run measure the un-ablated
  system (benchmarks set CORTEX_ABLATE_* without importing __main__).
- core/reranker_model.py: the FlashRank cache lookup, existence check and
  sha256 move to infrastructure/reranker_cache.py behind a seam that
  raises when unwired.
- Both seams join the wiki seams in mcp_server.hooks.wiring
  .wire_composition_root(), the single function every entry point calls.
  It now re-applies its bindings on every call instead of short-circuiting
  after the first, so a seam reset by a test is restored. The per-hook
  copies, benchmarks/lib/_environment_wiring.py, _reranker_wiring.py and
  the import-time wiring in hooks/_telemetry.py are gone;
  benchmarks/lib/_composition_root_wiring.py calls the same function.
- doctor.ensure_reranker_ready() wires through that function; CI's
  reranker preload step calls it instead of reaching into core directly.
- tests_py/benchmarks/test_ablation_runner_wiring.py drives the
  ablation-runner path with a CORTEX_ABLATE_* flag and proves the
  mechanism is disabled.

Fixes #560

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@cdeust
cdeust force-pushed the fix/560-core-no-os-envflags branch from 523ea2d to 5fee794 Compare September 15, 2026 05:58
…#560)

benchmarks/lib/ablation_runner.py imports db_snapshot, which imports
psycopg; the SQLite-only CI job has no postgresql extra and failed at
import. The PostgreSQL test jobs keep running it.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@cdeust

cdeust commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

ZETETIC-REVIEW: APPROVE

Re-reviewed at b847b7c, base 872855f. Every point of the REQUEST_CHANGES verdict is addressed.

core/environment.read_environment_variable now raises when unconfigured. The environment reader and the reranker filesystem are wired by the same mcp_server.hooks.wiring.wire_composition_root() as the wiki seams (#569), and every entry point calls it; test_composition_root_wiring_coverage.py enumerates them. The per-hook copies, the two benchmark bootstraps and the import-time wiring in hooks/_telemetry.py are removed. The function re-applies its bindings on every call, so a seam reset by a test is restored.

test_ablation_runner_wiring.py drives the ablation_runner path in a bare subprocess with CORTEX_ABLATE_ADAPTIVE_DECAY set, and proves the mechanism reads as disabled. It needs psycopg, like the runner, so the SQLite-only job skips it and the PostgreSQL jobs run it. The reranker test now asserts the wiring, not a downloaded model. CI's preload command (mcp_server.doctor.ensure_reranker_ready) returns loaded locally.

Benchmark command: benchmarks/reproduce.sh --no-regression --no-ablation --baseline-ref origin/main. It ran on b847b7c against 872855f, in an ephemeral PostgreSQL container on this machine (MANIFEST.json git_sha b847b7c, 2026-09-15). The script reports "REGRESSION CHECK PASSED: no score regressed vs baseline beyond tolerance":

metric head baseline delta
LongMemEval-S R@10 0.9800 0.9800 +0.0000
LongMemEval-S MRR 0.9057 0.9052 +0.0005
LoCoMo R@10 0.8890 0.8895 −0.0005
LoCoMo MRR 0.7801 0.7815 −0.0014

BEAM-100K and decision_ids also ran on the head. On the final state, the full suite passes (8630 tests), pyright reports 0 diagnostics, the craftsmanship gate passes with --base origin/main, verify_mcp_hosts.py passes 6 of 6, and CI is green on all 24 required checks.

@cdeust
cdeust merged commit 08453de into main Sep 15, 2026
28 checks passed
@cdeust
cdeust deleted the fix/560-core-no-os-envflags branch September 15, 2026 08:43
cdeust added a commit that referenced this pull request Sep 22, 2026
…warm (#618)

Closes #617

Since #568 (issue #560), core/reranker_model.py requires
configure_reranker_filesystem() to run before any core function that
touches the reranker cache directory. The devcontainer image's FlashRank
prewarm called _ensure_reranker() directly and never wired it, so every
build failed the same way, 5 retries, RuntimeError each time.

Verified locally: the exact one-liner still raises the RuntimeError
without the wire_composition_root() call added here, and returns a
loaded reranker with it. This job is skipped on a push that does not
touch Dockerfile-relevant paths (confirmed on the 4.23.1 release push,
run 35700002270), which is why it never blocked a release; the daily
scheduled run hit it for real (run 35586189593, 2026-09-21).


Claude-Session: https://claude.ai/code/session_01NLvPnrr8Ab6cKPK1Kt3K7f

Signed-off-by: cdeust <[email protected]>
Co-authored-by: Claude Sonnet 5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[audit] 17 core/ modules import os or pathlib (core must be zero-I/O)

1 participant