Skip to content

refactor(core): extract activation from _hooklib, completing the partition (#321, slice 4/4) - #560

Merged
SUaDtL merged 1 commit into
mainfrom
refactor/321-activationlib
Jul 30, 2026
Merged

refactor(core): extract activation from _hooklib, completing the partition (#321, slice 4/4)#560
SUaDtL merged 1 commit into
mainfrom
refactor/321-activationlib

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Last of four. _hooklib finishes at 557 lines, from 1,263 — a 56% reduction — and #321's architecture-002 finding is closed.

module lines
_hooklib 557
_sensitivelib 270
_scopelib 262
_protectedlib 204
_activationlib 183
_pathnorm 44

What moved

_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

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 the owning module 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:

set via _hooklib       -> visible in _activationlib: Fake
set via _activationlib -> visible in _hooklib:       Fake
reset via facade cleared the owner global: True
SHARED-CACHE CONTRACT HOLDS

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.py also matches test_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_cache is re-exported; _HOST, _ROOT_CACHE and _root_cache_key are genuinely unreferenced.

Verification

Public surface against origin/main: nothing gained, and the only losses are those three verified-unreferenced privates.

hook test tree 1185 pass
test_hook_guards 176 assertions, 0 failed
test_hooks_cold_install 285 assertions, ca + ca-codex, REAL/STUB/PY2/NONE
test_codex_adapter, test_dual_host_store pass
sync-core --check 53 core files × 3 plugins byte-identical

Parity rests on tests that did not move — none were edited in any of the four slices.

Versions

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.

…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
@SUaDtL
SUaDtL merged commit b98c321 into main Jul 30, 2026
51 checks passed
@SUaDtL
SUaDtL deleted the refactor/321-activationlib branch August 4, 2026 01:56
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.

core: partition _hooklib.py god module (architecture-002)

1 participant