fix(provision): the credential mechanism stops naming one forge, and a gate says so - #899
Draft
wenzowski wants to merge 1 commit into
Draft
fix(provision): the credential mechanism stops naming one forge, and a gate says so#899wenzowski wants to merge 1 commit into
wenzowski wants to merge 1 commit into
Conversation
|
Warning Review limit reachedNext included review available in 16 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…a gate says so Non-negotiable rule 1 binds MECHANISMS, not only string literals, and it had failed twice in `crates/batten` — both in the same commit, both invisible for the same reason: each worked perfectly when tested in this repository, on this forge, in this container. THE NAMES. `CREDENTIAL_NAMES` was two GitHub-shaped literals in the engine. A consumer on another forge, or on a host injecting under a third name, has neither, so every candidate is absent, `credential_health` answers `Unusable`, and every removal is skipped FOREVER — a failure nothing can see, because skipping a removal is also the right answer for a genuinely bad credential. The names move to `[credential] names`, beside the `probe_url` that was already config for exactly this reason. An empty list is could-not-look and is now SAID: an undeclared table, an undeclared endpoint and an undeclared name list each get their own line, because a revoked token is the operator's to replace and the other three are the consumer's config to write. THE CONTROL TOKEN. `MUST_FAIL` was one forge's token prefix and a run of zeroes, which breaks the criterion its own doc states: the token must be plausible enough that the refusal is about the CREDENTIAL rather than about malformed input. Off that forge it IS malformed input, so `route_honours_credentials` returns "this route honours credentials" on evidence it has not earned, and every verdict downstream rests on a rubber stamp. It is now DERIVED from the credential about to be tested — structural prefix kept, body refilled at the same length and class — so it is plausible on whatever forge this is, needs no config, and stays un-nameable by a consumer who could otherwise pick one the route accepts. Deliberately not a config field for that reason. THE GATE (non-negotiable rule 2). `the_engine_names_no_consumer_of_its_own` scans every `.rs` under `crates/batten/src`; its fragments are assembled at runtime so the scanner's own corpus never carries the shape it hunts, and `the_agnostic_scan_would_find_a_violation` proves the instrument is not vacuous. It caught this commit's first draft, where a doc comment had quoted the banned literal back into the engine while explaining why it was banned. WITHDRAWN, and recorded rather than quietly dropped: `config.rs`'s schema path was inventoried as a third violation and is not one. `schema/batten.schema.json` is batten's own convention, the same class as `batten.toml` itself, and names no consumer. The real defect there was a hand-joined second spelling of `config::SCHEMA_PATH` — two authorities for one location — fixed by using the constant. The scan does not ban that path, because a ban on the constant would ban the convention. BREAKING CHANGE: `provision::CredentialProbe` gains a field. The probe now carries the credential variable names alongside its `probe_url`, because the names moved out of the engine and a consumer that declares an endpoint but no names has said only half of what the probe needs. Constructing the struct positionally no longer compiles. Refs: CLOUD-1615 Admits: 3596b860bfa558171666073c6853e37a0583335aa0ca91fb62bf4507035a3c24 Admits-rule: protected-mutation Admits-verdict: path write refused Admits-subject: batten.toml Admits-anchor: call:65f08f551acb6211ff2c7ffaa9fcc81a93b336d6 Admits-epoch: 1daa8dabaf28d2aa6e4474b819e192af29b36644cdbca699867b4e86de26e5f9 Admits-author: alec@wenzowski.com Admits-prev: 2cef7da5183edf69172ef195b344e858bf73c71d6d20b86851e0bffa4b615a12 Admits-answer-lost: The engine half lands without the consumer half. CLOUD-1615 removes the hardcoded credential variable names from crates/batten and reads them from `[credential] names` instead; with the key undeclared, credential_health() reports could-not-look and returns Unusable, so every `unset` and `reject_prefix` row in this file is skipped, the proxy variables stay, and this repository's own sessions keep the host's substituted credential. That is a live regression introduced by the fix, for as long as the two halves are apart. Admits-answer-precondition: The surface this class names is a pull request, and this IS a pull request: the change is on branch claude/new-session-2rp805 for CLOUD-1615 and lands as a reviewed diff, never as a restore. No other surface can express it — `[credential] names` is a new config key, so nothing but an edit to batten.toml can declare it, and the engine change that reads the key is in the same commit range, where a reviewer sees both halves together. Admits-answer-rejected-route: `config read first` — rejected because it is already satisfied rather than skipped: the `[credential]` table and every surrounding `[[provision.env]]` row were read this session (the new key's doc comment cites their reasoning), and reading again cannot produce a key that does not yet exist. `patch run first` — rejected because there is no patch surface for adding a TOML key; the applying tool is the same Edit this rule refuses, so it would relabel the write rather than replace it.
wenzowski
force-pushed
the
claude/new-session-2rp805
branch
from
September 8, 2026 04:43
80558fb to
516072c
Compare
|
❌ The last analysis has failed. |
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.
Closes CLOUD-1615.
Non-negotiable rule 1 binds mechanisms, not only string literals, and it had failed twice inside
crates/batten— both in the same commit, both invisible for the same reason: each worked perfectly when tested in this repository, on this forge, in this container.The names
CREDENTIAL_NAMESwas two GitHub-shaped literals in the engine. A consumer on another forge — or on a host injecting under a third name — has neither, so every candidate is absent,credential_healthanswersUnusable, and every removal is skipped forever. Nothing can see that failure, because skipping a removal is also the right answer for a genuinely bad credential: the dead path and the working path are identical from outside.The names move to
[credential] names, beside theprobe_urlthat was already config for exactly this reason. Every could-not-look now says which one it is — an undeclared table, an undeclared endpoint and an empty name list each get their own line, because a revoked token is the operator's to replace and the other three are the consumer's config to write.The control token
MUST_FAILwas one forge's token prefix followed by a run of zeroes, which breaks the criterion its own doc states: the token must be plausible enough that the refusal is about the credential rather than about malformed input. Off that forge it is malformed input, soroute_honours_credentialsreports "this route honours credentials" on evidence it has not earned, and every verdict downstream rests on a rubber stamp — which is the one thing a control arm exists to prevent.It is now derived from the credential about to be tested: structural prefix kept, body refilled at the same length and character class. Plausible on whatever forge this is, needs no config, and deliberately not a config field — a consumer who could name the known-bad could name one the route accepts.
The gate (rule 2)
the_engine_names_no_consumer_of_its_ownscans every.rsundercrates/batten/src. Its fragments are assembled at runtime so the scanner's own corpus never carries the shape it hunts, andthe_agnostic_scan_would_find_a_violationproves the instrument is not vacuous.It caught this PR's own first draft, where a doc comment had quoted the banned literal back into the engine while explaining why it was banned.
Withdrawn, rather than quietly dropped
config.rs's schema path was inventoried as a third violation and is not one.schema/batten.schema.jsonis batten's own convention, the same class asbatten.tomlitself, and names no consumer. The real defect there was a hand-joined second spelling ofconfig::SCHEMA_PATH— two authorities for one location — fixed by using the constant. The scan deliberately does not ban that path: a ban on the constant would ban the convention.The portable-skew gap that arm still has in every consumer is unchanged and remains CLOUD-1572's.
Measured
The probe uses
get_direct, so it takes the direct column: junk refused, real accepted,Verdict::Live.api.github.comis absent from the ambientNO_PROXY— the exemption is a[[provision.env]]row and applies to processes the launcher starts, which is why a barecurlsees the proxy's identity and is not evidence about the fence.Note on the commit
commit-attributionrefused theClaude-Session:trailer this session's harness asks for;[attribution] trailer_denycarries it withtrailer_allow = []. Per AGENTS.md rule 8 the gate outranks the harness request, so the trailer is out and the durable record is the Linear row.https://claude.ai/code/session_014kQRLAmRkQKRawJTNCBt42