Kane Fabric recorded a gate register against this project at its 5df8801. This is the same instrument pointed the other way, plus the defects that review found in our own contract. A gate is a disagreement, an unmade decision, or an assumption two projects hold differently and have not had to reconcile. Recording one is not scheduling work on it. The failure this prevents is specific: when two systems meet, the pull is to fix the mismatch immediately, usually by one side quietly adopting the other's model in a commit that looks like integration and is actually a surrendered boundary. G-1 and G-2 are the two defects, corrected in the previous commit and recorded here because the class of mistake will recur. G-3 is the one that does not dissolve. This compiler records a stable identifier in a document built to stay legible for years; the civic direction is address-bound, opaque, epoch-scoped participation that deliberately avoids durable person identity. The mechanical part is already free -- Author.email takes an opaque token without a schema change. What remains is that a record naming a token whose epoch has closed has an author line nobody can ever resolve again. That may be exactly right as privacy policy and is still a permanent loss of provenance for a physical object somebody is holding. Two goods in conflict, owned jointly, settled by neither side writing its document second. G-4 and G-5 are the residue of the two new invariants: nothing verifies that exactly one hop decides, and fail-closed makes the eligibility endpoint a hard dependency of every gated route. Both recorded rather than designed around. G-6 notes that a shape is not a vocabulary -- two deployments can comply and still disagree about what "verified" means, which is tolerable only while the record states the method verbatim and claims nothing beyond it. N-1 through N-4 record what was raised against us that is correctly not ours: buildings against delivery-point geography, the local secure origin MS5-004 needs, the wg-pk fleet question, and credential hierarchies. Written down so a successor does not mistake them for work or rediscover them as new. Section 4 records that both projects independently drew the same junction -- geography, then a membership system, then a minimal decision, then this compiler, one direction only. That is the strongest evidence available that the shape is right. It also states where the two must not meet: if this compiler ever reads parcels, delivery points or buildings, the membership layer has been bypassed and every gate here is void.
11 KiB
CONSUMER_INTERFACE_GATES.md
Cross-project concerns raised by, or raised against, the systems this compiler expects to sit beside. Non-normative.
| Created | 2026-09-12 |
| Status | A register. Nothing here blocks current work. |
| Peer | Kane Fabric's docs/CONSUMER_INTERFACE_GATES.md, at 5df8801 |
| Normative counterpart | IDENTITY-CONTRACT.md |
0. What this file is for, and what it is not for
A gate is a disagreement, an unmade decision, or an assumption that two projects hold differently and have not yet had to reconcile. Recording one is not the same as scheduling work on it, and it is not an invitation to negotiate.
The failure this prevents is specific. When two systems meet, the pull is to fix the mismatch immediately — usually by one side quietly adopting the other's model, in a commit that looks like integration and is actually a surrendered boundary. A register makes the mismatch visible without making it urgent, so that when it does have to be resolved, both sides can see what was known at the time and who it belonged to.
Kane Fabric wrote the first of these against this project. This is the same instrument pointed the other way, plus the defects that review found in our own document.
Entries are not requirements on anyone. An entry owned by another project is a statement that we are waiting, not that they are late.
1. Defects in our own contract, found by external review
These are corrections we owe, not disagreements. Both are addressed in the same commit that adds this file; they are recorded because the class of mistake will recur.
G-1 — an illustrative value read as an expectation
IDENTITY-CONTRACT.md gave kane-fabric/oidc as an example authentication
method. Kane Fabric has no OIDC service, no user database, and no
person-authentication role. The example named a capability in another project
that does not exist and was never asked for.
An example in an interface contract is read as an expectation by the next person to implement against it. This is the same failure as the "acceptable for a development name" sentence that survived three documents: a plausible clause, never challenged, hardening into a constraint.
Corrected. Method strings are now specified by shape rather than by example.
Owner: this project. Blocks: nothing. Standing lesson: an interface document should contain no example that names a system outside it.
G-2 — a jurisdiction baked into the wire format
The headers were X-Kane-Auth-Email and X-Kane-Auth-Method.
Two things wrong. The contract insists at length that the compiler must never
learn a membership concept, then puts a county in the header name — a deployment
fact in an invariant place. And -Email names a format rather than a role, in a
field that is explicitly allowed to hold something else (see G-3).
Corrected to X-Mechcomp-Auth-Id and X-Mechcomp-Auth-Method. The receiver
is the invariant; the jurisdiction is not.
Residue: the header lands in design_record.Author.email, a field named for
what it holds today. Renaming it is a format change to every stored record and
is deliberately not done now. Noted so the mismatch is on record rather than
discovered.
Owner: this project. Blocks: nothing.
2. Open gates
G-3 — persistent person identity against epoch-scoped participation
The disagreement. This compiler records a stable identifier for the author of a design, in a document built to remain legible for years. The civic direction is address-bound, opaque and epoch-scoped participation, which deliberately avoids durable person identity.
These are not two spellings of one idea. They disagree about whether a person should remain identifiable over time.
What already accommodates it. Nothing in design_record.py requires the
string to be an email. Author.email holds an identifier; verified and
method state what it is worth. An opaque, epoch-scoped token fits the existing
field without a schema change, and Author.handle already exists for a display
name that is explicitly not the identity.
What does not dissolve. A design record is meant to be readable by someone who has none of this software, years from now. An epoch-scoped identifier is meant to stop resolving. A record naming a token whose epoch has closed has an author line that can never again be resolved to anyone — which may be exactly right as privacy policy, and is still a permanent loss of provenance for a physical object somebody is holding.
That is a conflict between two goods. It is not a bug in either design and it cannot be settled by whichever side writes its document second.
What this project will not do: pre-emptively adopt either model, or add an identity-mode switch to the record format before there is a second consumer to justify one.
Owner: joint — this project and whatever membership system reaches
production first. Blocks: nothing today. Becomes blocking at the first
implementation of IDENTITY-CONTRACT.md §7, and is cheap until then only
because no record with a verified author yet exists anywhere.
G-4 — the chain may grow, and exactly one hop may decide
IDENTITY-CONTRACT.md names CT 101 as the decider because CT 101 is what exists.
Additional containers are expected to insert themselves between the browser and
this application, possibly several, possibly owned by other projects.
The invariant that matters is not which box decides. It is that exactly one does, and that it is the last hop before the application. Two intermediaries both setting the identity headers is a forgery vector wearing the costume of a deployment change: the second one wins, the first one believes it decided, and nothing in the chain reports a conflict.
Corrected in the contract by restating the strip and the decision as properties of the chain rather than duties assigned to a named container.
Residue: nothing verifies the property. A check that the application is
reachable only from its declared decider would be a ct-baseline.sh-shaped
test — binary, checkable, not a matter of judgement — but that script is host
property covering three projects and adding to it is a CIVICVS decision. Carried
as HANDOFF.md open question 11, which asks the same thing about working-tree
ownership.
Owner: this project for the contract; CIVICVS for whether it is enforced. Blocks: nothing.
G-5 — what happens when the decider cannot answer
The contract specified 2xx and 401. It said nothing about the eligibility
endpoint being unreachable, slow, or returning something unparseable. Across a
chain of unknown length and multiple owners, unreachable is the ordinary case
rather than the exotic one.
Fail-open and fail-closed are both defensible and they are not the same system. Discovering which one was built during an outage is the worst way to find out.
Corrected in the contract: anything that is not an affirmative permission is
a refusal. Unreachable, timed out, malformed, and 5xx all deny.
Residue: this makes the eligibility endpoint a hard dependency for every gated route. Whether that is acceptable is a question for whoever operates the membership system, and the answer may be that gated routes need a degraded mode. Not designed. Recorded.
Owner: joint. Blocks: nothing today; /m/ is not yet gated.
G-6 — method strings need a vocabulary, not examples
If X-Mechcomp-Auth-Method is free text, every consumer invents its own, and a
record written by one deployment is uninterpretable by another. If it is an
enumeration, this project is dictating mechanisms to systems it refuses to know
anything about.
Corrected in the contract by specifying a shape — issuer, mechanism, and what was actually verified — while leaving every value open.
Residue: a shape is not a vocabulary. Two deployments can comply and still disagree about what "verified" means. That is tolerable while the record states the method verbatim and makes no claim beyond it, and it stops being tolerable the moment anything filters or aggregates on the field.
Owner: this project. Blocks: nothing.
3. Raised against us, and correctly not ours
Recorded so that a successor does not mistake them for work, and does not rediscover them as though they were new.
N-1 — buildings against delivery-point geography
Kane Fabric observes that membership is described as attaching to buildings while this compiler insists it must never know what a building is.
That is not a contradiction, it is the boundary working. The compiler receives a
decision, not the facts behind it. Whether "building" is the right primitive
against parcel and delivery-point geography is membership semantics, upstream of
anything here, and a correction there requires no change to
IDENTITY-CONTRACT.md.
Not ours. The compiler's only stake is that the answer stays an answer.
N-2 — the local secure origin
MS5 needs a browser to establish a secure context with a local edge while central infrastructure is unavailable. This project has centrally terminated public TLS and internal proxy TLS, which solves a different problem and offers nothing to that one.
Not ours. No claim is made that our TLS architecture is a model for it.
N-3 — the wg-pk fleet question
Peer lifecycle, key replacement, address allocation and hub ownership do not
extrapolate from the current manual administration. This project depends on the
hub as transport and deliberately refuses to make it an authorization authority
— IDENTITY-CONTRACT.md §2 — but the fleet design is estate work.
Not ours. Our only requirement is that the hub stays transport.
N-4 — credential hierarchies stay separate
Proxy TLS, edge TLS, WireGuard keys, membership credentials and signing authority have no reason to merge. We agree, and note it here so that nobody proposes a unification on our behalf.
Not ours, and not wanted.
4. The shape of the eventual junction
Recorded because both projects independently drew the same picture, which is the strongest evidence available that it is right.
geography facts
|
v
a membership or participation system
|
v a minimal authorization decision
|
v
this compiler
One direction. The compiler's need for authentication does not oblige the geography layer to acquire authentication, and the geography layer's model of participation does not reach this application except as a verdict.
Where the two must not meet: this compiler and geography, directly. If a future design has us reading parcels, delivery points or buildings, the membership layer has been bypassed and G-3 through G-6 are all void.