docs: our side of the cross-project gate register
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.
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user