Expand description
Admin.Capacity: “if a tenant’s cap rose to N bytes, could you serve
it?” — the question monetize must ask before it buys a disk. Answers with
a verdict measured off the SAME statvfs the push door refuses under, and,
independently, whether this data set can ever grow at all: the appliance is
SEALED (an md set laid once at install, no runtime growth path, PID 1 with
no shell), so a disk bought for it is billed and invisible.
“If a tenant’s cap rose to N bytes, could you serve it?” — Admin.Capacity.
The question a seller must ask before the money moves. monetize grows an “increase my quota” button: a tenant on 10 GB asks for 100 GB and something upstream is about to buy 90 GB from a cloud vendor and charge for it. gunnar is the only component that knows whether those bytes can ever reach a repository, and on the appliance the honest answer is frequently no.
§Two facts, not one number
A single free-bytes answer is the dangerous one: a caller reads a small
number as “buy another disk”, and on the appliance that is money converted
into nothing. So answer returns a verdict — can this request be served
out of what exists right now — and, independently, a growth — can this
data set ever hold more than it does, and by whose hand. growth is
reported on the yes arm as well, because “yes, and this is the last capacity
this box will ever have” is a different sale from “yes, and there is more
where that came from”.
§When the appliance is SEALED — and when it is NOT
SEALED was once the only answer, on three facts:
/datais an md set laid once bykorp-installer’slay_set(edda/crates/korp-installer/src/install.rs), which runs only onInstallMode::Fresh.- gunnar had no data-set growth of any kind.
- gunnar is PID 1 with no shell, so nothing on the machine can
xfs_growfsa newly attached disk either.
The second is no longer true, and decide_growth must not say it is.
korp-start carries the boot-time grow engine
(korp_installer::grow, DATA-SET-GROWTH-DESIGN.md) and, under the
grow-runtime feature, THIS server links the same engine’s runtime half
(korp_installer::grow::runtime, driven by crate::grow). So the
verdict is a ladder over MEASURED facts — the journal on the box
(GrowthFacts::grow), this build’s engine (GrowthFacts::runtime_engine)
and the kernel’s PCI hot-plug (GrowthFacts::hotplug) — and SEALED is
only its bottom rung, reached when this box keeps no grow journal.
Nothing here may claim “no such path in any build”: that is a statement
about the binary, and the binary is measured one field away.
On that bottom rung a disk bought and attached to the box is billed and
invisible. That is what SetGrowth::GrowthSealed says, in those words,
in the reason line — so a caller that renders nothing but the sentence
still cannot mistake it for “not enough space right now”.
§Measured, never declared, and measured ONCE (one implementation)
The bytes are gunnar_ssh::DiskHeadroomGate::headroom — the same
statvfs the push door refuses under, so the capacity a seller is quoted
and the floor a push dies at cannot disagree. The set’s shape is
crate::dashboard::probe::disk_kind — the same /proc/mounts + md sysfs
read the console’s header band prints 4×75G raid0 xfs from. This module
opens no third spelling of either question; it decides over their output.
answer is pure over Question precisely so the SEALED arm can be
driven red on a developer box, where gunnar is never PID 1 and /data is
never an md set.
§The box: cores and RAM, measured (product scope)
Disk is a tenant’s: a cap is bytes in one namespace. Cores and RAM are the
box’s: no tenant owns a core, so the ceiling a seller may sell either
up to is whatever this machine has — and that must be read off the
machine, not declared in a config that was true of the plan somebody
ordered. MachineFacts reads them the way the rest of the server
already does (one implementation): available_parallelism is what
crate::budget::Machine sizes the thread pools from, /proc/meminfo
is crate::dashboard::probe::meminfo behind the header band’s ram
cell, the cgroup clamp is [crate::budget::cgroup_memory]’s, and the
load is the band’s load1.
Every box field on the wire is optional, and absent means unmeasured
— never 0. A 0 is a number a caller will divide by, sell against, or
read as “this box has no RAM”; an absence with machine_reason naming
the OS error is the same UNMEASURED discipline the disk half has.
Structs§
- Growth
Facts - What the machine says about the set under the data root. Two measured
facts and nothing inferred;
decide_growthturns them into a verdict. - Machine
Facts - What the box has: cores, RAM, and how busy it is. Product-scope facts,
each either measured or carrying the reason it was not;
machine_fieldsturns them into the wire’soptionalfields and themachine_reason. - Question
- Everything
answerdecides from. Built bycrate::control_plane::CoreControlPlaneout of the disk gate and the namespace’s meter; built by hand in the tests, which is the point.
Functions§
- answer
- The answer. Pure: every field below is arithmetic over
Question. - decide_
growth - The growth verdict and the clause the reason line carries for it.
- disk_
fields - The wire’s
disk_*fields out of onecrate::disktest::Outcome, and nothing else set — the same shape and the same contract asmachine_fields, so both arms ofanswerfill them the same way. - disks_
to_ wire - The snapshot, as the wire carries it. Pure, so a recorded snapshot can be
checked field by field: an unmeasured mount keeps
measured = falseand its reason, and its numbers stay 0 rather than being invented. - machine_
fields - The wire’s box fields out of
MachineFacts— and nothing else set, so a caller builds a response asCapacityResponse { ..., ..machine_fields(&m) }and both arms ofanswerfill these the same way (one implementation). - measure_
disks - Every disk on the box, for
Admin.Capacity { disks: true }(2026-09-28). - serialdat_
breakdown - What is on /serialdat, thing by thing — the known paths gunnar keeps
there, each measured as the blocks it holds (a directory summed), plus
other: the mount’s used bytes no known path accounts for.