Skip to content

refactor(core): extract the protected-path classifiers from _hooklib (#321, slice 2/4) - #557

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

refactor(core): extract the protected-path classifiers from _hooklib (#321, slice 2/4)#557
SUaDtL merged 1 commit into
mainfrom
refactor/321-protectedlib

Conversation

@SUaDtL

@SUaDtL SUaDtL commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Second of four slices on #321. _hooklib goes 1,050 → 880 lines — it was 1,263 before the partition began, so two slices have taken 30% off the god module.

What moved

_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.

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 _pathnorm floor rather than being imported back (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.

Parity

_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.

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/hooks 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. That is precisely the self-perpetuating false positive #279 diagnosed and closed, resurrected because the enforcement actually running was older than the fix.

refs to the #279 exemption
installed ca-codex 0.3.0 enforcer 0
current repo copy 4

Filed as #556 — same family as #530, but with sharper teeth, because the stale payload here is the enforcement, wired into .git/hooks and 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 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 and intentional, not collateral from this slice.

Versions

ca 2.10.5 → 2.10.6, ca-codex 0.3.4 → 0.3.5, ca-pi 0.1.40 → 0.1.41. All three gates verified locally.

Remaining

_scopelib and _activationlib. _activationlib last — set_host has 20 consumers.

…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
@SUaDtL
SUaDtL merged commit 45f5046 into main Jul 30, 2026
51 checks passed
@SUaDtL
SUaDtL deleted the refactor/321-protectedlib branch July 30, 2026 18:30
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.

1 participant