Client membrane: the client-repo declaration and the sticky-check waiver (ADR 0030 §11)#7
Merged
Merged
Conversation
…t-party, honor source_root, Node-24 action pins Four measured gate defects from the overnight burn's adversarial verifies, plus the Node-20 deadline, each with a control rod that MUST fail: 1. Kit-pin honor — github.job_workflow_sha was OBSERVED empty at run time: the kit checkout received no ref and floated to kit MAIN (git checkout -B main refs/remotes/origin/main), so SHA-pinned consumers were gauged by an unpinned gauge (counts irreproducible, twice in one night). The gate now re-anchors the kit checkout to the pin the consumer COMMITTED in its caller stub, refuses two distinct pins, and refuses to run when no pin is determinable — fail-safe, never a silent float. Rod: the step's script runs against a real git fixture whose floating checkout must be moved to the declared pin (tests/test_gate_hardening.py). 2. complexipy joins the gate — the watermark was runbook-only; now a workflow step in both quality-gate.yml and self-ci.yml with the mypy-style presence rule (a Python repo without its committed snapshot FAILS; Python-free repos skip visibly; never piped). The kit ratchets FIRST: its own snapshot is booted and gated. 3. known-first-party derived per consumer — a shared gauge file cannot name every consumer's packages, and ruff's on-disk detection mis-files first-party imports that do not resolve (measured: fixing the kit's two I001 created two NEW legacy-isort I001 in the same repo). cf-repo-config grows a first-party field (derived from the resolved source root) and the gate feeds it inline to the pinned ruff gauge. 4. cf-exemptions honors the declared source_root — the scanner discovered the repo-root src/ (JS in the measured case) and never visited the declared tree, making every registered exemption documentation-grade. The scan surface now resolves through cf-repo-config exactly like the gauges. Rod: an unregistered suppression under a declared server/src must fail (it silently passed before). 5. Node-24 action pins — GitHub forces Node 24 on 2026-06-16; both pinned actions bumped to their Node-24 releases (checkout v6.0.3, setup-python v6.2.0, full-SHA pinned, releases verified). The deprecated Node-20 SHAs are denylisted ratchet-style. Tests 310 -> 337; full self-ci battery green locally. Two test files split at the file budget's own refusal — the gate caught its maker, the split is the fix, not a baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ent membrane (ADR 0030 §11) The canon's client membrane and the gate contradicted each other: client repos receive gate-config only — never sticky/chrome — but cf-sticky-check failed STICKY_CLAUDE_MD_MISSING with no waiver knob (zero-inputs doctrine), so a client repo's gate could never go fully green. The waiver is COMMITTED state, never a knob: [tool.cf-quality] client_repo = true (same homes and typed validation as the layout keys; a tampered declaration — "yes", 1 — fails GATE_CONFIG_INVALID, never coerces). Three control rods, each pinned by test and proven against the real client shapes: - R1: declared client + no CLAUDE.md -> check passes and the CLI prints the loud membrane notice; waived visibly, never silently. - R2: no declaration -> behavior unchanged for the fleet, byte for byte; client_repo = false behaves exactly as undeclared. - R3: declared client carrying ANY sticky chrome (canonical block, chewed copy, older-vintage block, or the kit's mount-marker header) fails STICKY_CLIENT_MEMBRANE_BREACHED — the membrane is two-way. mount refuses a declared client repo outright (STICKY_MOUNT_CLIENT_MEMBRANE). Honest residue on the record (DESIGN.md §7): the gate cannot verify WHO is a client — adoption is a reviewed diff, the notice prints on every run, and a Constable-cadence declaration sweep is the candidate mechanical closure. Tests 337 -> 355; full battery green locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
STACKED ON PR #6 — MERGE PR #6 FIRST
This branch is cut from
fix/gate-kit-defects-node24(PR #6) because both lanes touchrepo_config.pyand its test contract. This PR's own diff is the last commit only (feat: client-repo declaration…); everything before it is PR #6. After #6 merges, this PR shows only the membrane work.What merging this blesses
The contradiction this resolves: canon ADR 0030 §11 (the client membrane) says client repos receive gate-config only — never sticky/chrome, but
cf-sticky-checkfailsSTICKY_CLAUDE_MD_MISSINGwhen no CLAUDE.md exists and the kit had no client-lane waiver (zero-inputs doctrine). A client repo's gate could therefore never go fully green — the doctrine forbade the very file the gate demanded. Evidence: the rov finish pass had everything green at the pinned kit with the sticky step the sole red (CI run 27370801157); notioncrm's gate red rides the same contradiction.The waiver is a committed declaration, never a knob:
Same homes and typed validation as the layout keys (
pyproject.tomlor.cf-quality.toml, one home only). Adopting it is a reviewed diff — Wizard-gated like any doctrine surface — and the gate honors it loudly: the CLI printsclient membrane declared — sticky intro not mounted per ADR 0030 §11 (client repos receive gate-config only, never chrome)on every green run. Impossible to adopt silently.The three control rods (each pinned by test, each proven against the real client shapes)
client_repo = trueand no CLAUDE.md → sticky-check exits 0 with the loud notice. Proven against the rov shape (no CLAUDE.md): exit 0, notice printed.STICKY_CLAUDE_MD_MISSING. Zero behavior change for the fleet;client_repo = falsebehaves byte-for-byte as undeclared.STICKY_CLIENT_MEMBRANE_BREACHED(the membrane is two-way). Chrome is recognized by the canonical heading line, the kit's mount-marker header (any vintage — the v1 header included), and exact/near block match in raw bytes (a buried copy is chrome too); prose merely naming the law is NOT chrome. Proven against the real notioncrm CLAUDE.md (which carries the v1-era sticky): BREACH, exit 1.Plus the hardening around the rods:
client_repo = "yes"or= 1isGATE_CONFIG_INVALID(exit 2), never coerced.cf-sticky-check mountrefuses a declared client repo outright (STICKY_MOUNT_CLIENT_MEMBRANE, typed, nothing written) — the kit never pushes chrome through the membrane.Honest residue (on the record, DESIGN.md §7)
The gate cannot verify WHO is a client: a non-client repo could commit the declaration to dodge the sticky mount. Defense as shipped: adoption is a reviewed diff, and the notice prints on EVERY gate run, so a wrongly-declared repo is loud in its own CI logs. The candidate mechanical closure (a Constable-cadence sweep of
client_repodeclarations against the known client list) is named, not built.Consumer-side decisions this does NOT make (Anta-gated, carved out)
Verification
sticky_check → repo_configis a downward edge inside the committed import contract;cf-import-contractgreen.Files
src/cf_quality/repo_config.py—client_repokey (strict TOML bool, typed failure on tamper)src/cf_quality/sticky_check.py— the waiver, the two-way breach, the mount refusal, the loud noticetests/test_repo_config.py·tests/test_sticky_check.py— the rodsDESIGN.md§7 — the membrane mechanism + honest residueCI state
Will be reported on this PR's checks (self-ci runs the full battery on this branch, which includes PR #6's commits underneath).
DO NOT MERGE without Anta's review — and merge PR #6 first.
🤖 Generated with Claude Code