refactor(core): extract activation from _hooklib, completing the partition (#321, slice 4/4) - #560
Merged
Merged
Conversation
…ition (#321, slice 4/4) Last of four. _hooklib finishes at 557 lines, from 1,263 - a 56% reduction, and #321's architecture-002 finding is closed. _activationlib owns the three answers every hook needs before it can decide anything: which Host this process runs under, where the project root is, and whether the arbiter is switched on. They share two process-lifetime caches - splitting them would put a cache in one module and its only writer in another. The edge runs the OTHER way for the first time: _log_gate_event stays in _hooklib and calls get_host()/project_root(), so _hooklib imports from _activationlib and never the reverse. Still one-way, still no cycle. THE MUTABLE GLOBAL WAS THE REAL HAZARD, and it is why this slice went last. `_HOST` is deliberately NOT re-exported: `from _activationlib import _HOST` binds the VALUE at import time, so a later set_host() would rebind the name in _activationlib and leave _hooklib holding a stale None forever - a silent divergence in the host seam, which is the worst possible place for one. The three ACCESSORS are re-exported instead, because a function binding stays live. Proven rather than reasoned: a probe sets the host through the facade and reads it through the owner, sets through the owner and reads through the facade, and resets through the facade to confirm the owner's global cleared. One cache, both directions. That is the exact OPPOSITE of slice 3's lesson (re-export the privates), and the distinction is precise: re-export a private FUNCTION, never a private mutable VALUE. A METHODOLOGY BUG, worth recording because it caused three wrong calls this campaign. My "no external consumers" checks excluded the module with the pathspec `:!*_hooklib.py` - which also matches `test_hooklib.py`, the very file that consumes these symbols through `_hooklib.`. That is why reset_host, seven scope privates, and _reset_root_cache each read as unused and each broke a test on contact. Corrected here by excluding the module paths explicitly rather than by a suffix glob. `_reset_root_cache` is re-exported on that corrected evidence; `_HOST`, `_ROOT_CACHE` and `_root_cache_key` are genuinely unreferenced. Public surface verified against origin/main: nothing gained, and the only losses are those three. Parity rests on 1,185 pre-existing hook tests that did not move, plus the cold-install matrix (285 assertions, ca + ca-codex). Final shape: _hooklib 557, _sensitivelib 270, _scopelib 262, _protectedlib 204, _activationlib 183, _pathnorm 44. ca 2.10.7 -> 2.10.8, ca-codex 0.3.6 -> 0.3.7, ca-pi 0.1.42 -> 0.1.43. Closes #321. Claude-Session: https://claude.ai/code/session_01WJgVfZw7J81PB7mwpHyUxx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Last of four.
_hooklibfinishes at 557 lines, from 1,263 — a 56% reduction — and #321'sarchitecture-002finding is closed._hooklib_sensitivelib_scopelib_protectedlib_activationlib_pathnormWhat moved
_activationlibowns the three answers every hook needs before it can decide anything: which Host this process runs under, where the project root is, and whether the arbiter is switched on. They share two process-lifetime caches — splitting them would put a cache in one module and its only writer in another.The edge runs the other way for the first time:
_log_gate_eventstays in_hookliband callsget_host()/project_root(), so_hooklibimports from_activationliband never the reverse. Still one-way, still no cycle.The mutable global was the real hazard
It is why this slice went last.
_HOSTis deliberately not re-exported.from _activationlib import _HOSTbinds the value at import time, so a laterset_host()would rebind the name in the owning module and leave_hooklibholding a staleNoneforever — a silent divergence in the host seam, which is the worst possible place for one.The three accessors are re-exported instead, because a function binding stays live. Proven rather than reasoned:
That is the exact opposite of slice 3's lesson, and the distinction is precise: re-export a private function, never a private mutable value.
A methodology bug I should flag
Three times this campaign I concluded a symbol had "no external consumers" and was wrong on contact —
reset_host, seven scope privates, and_reset_root_cache.One cause: my exclusion pathspec
:!*_hooklib.pyalso matchestest_hooklib.py— the very file that consumes these symbols through_hooklib.. So the check silently excluded its own best evidence.Corrected here by excluding the module paths explicitly rather than by suffix glob. On that corrected evidence
_reset_root_cacheis re-exported;_HOST,_ROOT_CACHEand_root_cache_keyare genuinely unreferenced.Verification
Public surface against
origin/main: nothing gained, and the only losses are those three verified-unreferenced privates.test_hook_guardstest_hooks_cold_installtest_codex_adapter,test_dual_host_storesync-core --checkParity rests on tests that did not move — none were edited in any of the four slices.
Versions
ca2.10.7 → 2.10.8,ca-codex0.3.6 → 0.3.7,ca-pi0.1.42 → 0.1.43.Closes #321.