Expand description
The plan gate: the front door’s one question before the bytes.
authorise_service (see crate::server::Dispatch) is the ONE choke point
SSH and smart-HTTP share, and it is where a push is refused before any
pack bytes, which is the rule that makes this a front-door check and not a
gunnar-policy gate (a gate runs after the pack is read; that is a 1 GB
upload accepted and then refused). This crate does not know what a plan is,
what monetize is, or how a fact is signed; it asks the PlanGates the
server hands in and does what the verdict says.
§Two implementations, one chain (decided 2026-09-04)
two implementations: 1) the free lunch, basically checking disk has size before a new repo is created; 2) the monetize-bound one
crate::headroom::DiskHeadroomGate— always compiled, no monetize dependency. Refuses a push and aRepos.Createwhen the store root’s filesystem would drop under a floor. The community binary has this one link.gunnar-server::entitlement::EntitlementSlot(meteredonly) — the ladder: Suspended, Retention, the pack quota. The decision ismonetize_embed::EntitlementCache’s, one atomic load and a map lookup.
crate::Control holds them as a chain, asked in order, disk first;
the first Refuse wins and is the line the client is told. A box that is
full is told it is full, not that its plan lapsed — the disk is the fact
nobody can pay their way past. A gate that always answers Allow is
invisible to a request that only pushes valid things (measured, not asserted), which is why
every gate’s refusal has a test that sets the condition and watches the
push die before a byte.
§What is asked, and when
| request | asked | may be refused |
|---|---|---|
git-receive-pack, LFS upload | PlanAction::Write, then PlanGate::pack_quota and PlanGate::pack_ceiling | Suspended, Retention, over caps["pack_bytes"] — before the bytes, and (receive-pack only) DURING them |
anonymous git-upload-pack / LFS download | PlanAction::AnonymousRead | Suspended, Retention |
the owner’s, or any authenticated reader’s, git-upload-pack | nothing | never — data is never held hostage |
Asked only for a request the grant check already admitted, so a refusal here never tells a stranger anything about a repository they could not already see; and asked AFTER the standby freeze, so a standby stays a standby whatever the plan says.
§The one answer that is not a verdict
PlanGate::pack_ceiling is the exception to “the front door decides
before the bytes”, and it is the exception because it has to be: a pack
header carries an object count, not a byte count, so the size of a push
is not knowable here. The gate therefore answers with a NUMBER rather than a
verdict, the number rides on crate::ServiceRequest::pack_ceiling, and
the refusal happens in gunnar-wire’s receive loop the moment the count
passes it. That is still the front door’s decision — it is just carried to
where the bytes are.
Structs§
- Pack
Ceiling - A byte ceiling for one push, and the line the client is told past it.
Enums§
- Plan
Action - What the request is about to do to the namespace’s data.
- Plan
Verdict - The gate’s answer.
Traits§
- Plan
Gate - One link of the front door’s chain: “may this namespace do this, right now”.