refactor(core): extract the protected-path classifiers from _hooklib (#321, slice 2/4) - #557
Merged
Merged
Conversation
…321, slice 2/4) Second of four. _hooklib goes 1,050 -> 880 lines; it was 1,263 before the partition began, so two slices have taken 30% off the god module. _protectedlib owns one question - "what class of protected thing is this path?" - across append-only audit logs (H-05), ADR decision files (H-11), the activation manifest, and the gate-marker directory. They belong together because the guards branch on the answer as a SET. classify_protected returns EVERY class a path hits, which is load-bearing: #528/#529 showed that adding decision-log.md to the audit set while leaving it in the decisions set STILL blocked, because pre-write.py checks the classes independently. Splitting these across modules would let one classification move without the others and reopen exactly that. Same measurement as slice 1: the cluster referenced exactly ONE symbol from the rest of _hooklib, and NOTHING in the rest referenced the cluster. That one symbol was repo_rel, which moved to the _pathnorm floor rather than being imported back (which would have been a cycle). It earns its place there on the same test norm_path did: it references no module symbol at all, and the remaining slices need it too. Its docstring is also the canonical statement of why a LEXICAL relpath is wrong here - the 8.3-short-name and symlink divergence that independently produced #539 and #541 this week. _hooklib re-exports every moved name, so consumers are UNCHANGED and parity rests on 1,185 pre-existing hook tests that did not move. Public surface verified against origin/main: nothing lost, nothing gained. No crypto moved. H-09b nevertheless blocked this commit, and the cause turned out to be worth more than the slice: the .git hook was running a ca-codex 0.3.0 cached enforcer that PREDATES #279, so it scanned the audit log and matched the detector's own "Crypto/TLS pattern detected" message text - the exact self-perpetuating false positive #279 closed. Filed as #556; the shim is repointed at this checkout's enforcer, which carries the exemption. That STRENGTHENS the backstop rather than bypassing it - no override was used. `import subprocess` in _hooklib now looks dead to a naive scan but already carries a noqa explaining it is kept so an external consumer referencing _hooklib.subprocess keeps resolving. Pre-existing, not collateral. ca 2.10.5 -> 2.10.6, ca-codex 0.3.4 -> 0.3.5, ca-pi 0.1.40 -> 0.1.41. 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.
Second of four slices on #321.
_hooklibgoes 1,050 → 880 lines — it was 1,263 before the partition began, so two slices have taken 30% off the god module.What moved
_protectedlibowns one question — "what class of protected thing is this path?" — across append-only audit logs (H-05), ADR decision files (H-11), the activation manifest, and the gate-marker directory.They belong together because the guards branch on the answer as a set.
classify_protectedreturns every class a path hits, which is load-bearing: #528/#529 showed that addingdecision-log.mdto the audit set while leaving it in the decisions set still blocked, becausepre-write.pychecks the classes independently. Splitting these across modules would let one classification move without the others and reopen exactly that.The seam, measured the same way as slice 1
Exactly one outward reference, zero inward.
That one symbol was
repo_rel, which moved to the_pathnormfloor rather than being imported back (a cycle). It earns its place there on the same testnorm_pathdid — it references no module symbol at all, and the remaining slices need it too. Its docstring is also the canonical statement of why a lexical relpath is wrong here: the 8.3-short-name and symlink divergence that independently produced #539 and #541 this week.Parity
_hooklibre-exports every moved name, so consumers are unchanged and parity rests on 1,185 pre-existing hook tests that did not move. Public surface verified againstorigin/main: nothing lost, nothing gained.H-09b blocked this, and the cause was worth more than the slice
No crypto moved — yet the git backstop blocked the commit. The cause:
.git/hookswas running a ca-codex 0.3.0 cached enforcer that predates #279, so it scanned the audit log and matched the detector's ownCrypto/TLS pattern detectedmessage text. That is precisely the self-perpetuating false positive #279 diagnosed and closed, resurrected because the enforcement actually running was older than the fix.ca-codex 0.3.0enforcerFiled as #556 — same family as #530, but with sharper teeth, because the stale payload here is the enforcement, wired into
.git/hooksand cross-host (a Codex session wrote the shim; a Claude Code session never repointed it).The shim now points at this checkout's enforcer, which carries the exemption. That strengthens the backstop rather than bypassing it — no override was used, and the commit went through a healthy gate.
Also
import subprocessin_hooklibnow looks dead to a naive scan, but already carries anoqaexplaining it is kept so an external consumer referencing_hooklib.subprocesskeeps resolving. Pre-existing and intentional, not collateral from this slice.Versions
ca2.10.5 → 2.10.6,ca-codex0.3.4 → 0.3.5,ca-pi0.1.40 → 0.1.41. All three gates verified locally.Remaining
_scopeliband_activationlib._activationliblast —set_hosthas 20 consumers.