Repository navigation
fix(sandbox): carry a full-pool capacity notice into sandbox.get (#649) - #655
Merged
Merged
Conversation
`sandbox.get`'s `daemon_capacity` model is absent exactly when the daemon
pool is full: the capacity read needs the same slot, so the only source of
the counts is the pre-handshake `LAYERFS-CAPACITY` notice. `direct::unanswered`
re-coded every refusal that was not `Busy`/`StaleSandbox` to `Unavailable`
and dropped the notice's `detail`, so the get could only show prose in
`down_reason`.
Keep the `Capacity` detail (tagged with its code) through `unanswered`, and
surface it from `sandbox.get` as a new explicit, **partial** `down` field:
down: { code, resource, pool_vacant, reserved_vacant, retained }
It is not mapped into `daemon_capacity` (`CapacityModel::parse` would fill
missing fields with zero). It is absent when the refusal had no counts: a
legacy bare EOF, a malformed record, or a remote refusal collapsed to
`{phase}` by `values::refusal`. `Capacity` still does not pass through
`unanswered` as `Capacity`, so the get keeps answering with `down_reason`.
Tests (layerfs-api/tests/sandbox_capacity.rs, 8/8):
- full pool -> get shows `down` with the notice counts, after the measured
60 s admission window, and no `daemon_capacity`;
- legacy EOF -> `down_reason`, no `down`;
- normal get -> no `down`, `daemon_capacity` intact;
- collapsed remote refusal `{phase}` -> `Down::of` is `None`.
Docs: sandbox/get.md, sandbox/README.md, daemon-channel.md.
This was referenced Nov 12, 2026
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.
Summary
sandbox.getomitsdaemon_capacityexactly when the daemon pool is full, because the capacity read needs the same slot. The only source of the counts then is the pre-handshakeLAYERFS-CAPACITYnotice, anddirect::unanswereddropped itsdetailwhen it re-coded the refusal toUnavailable. This exposes the notice as a new explicit, partial field instead of fakingdaemon_capacity:control/crates/layerfs-sandbox/src/direct.rs::unansweredkeeps theCapacityrefusal'sdetail(it already carriesresource,pool_vacant,reserved_vacant,retained,retryable,retry_after) and tags it withcode: "Capacity". Every other refusal keeps no counts.control/crates/layerfs-sandbox/src/get.rsbuilds theDownmodel only when all five fields are present. A legacy bare EOF (detailNull), a malformed record, or a remote refusal collapsed to{phase}byvalues::refusal()yieldsNone, sodownis absent rather than zeros.api/crates/layerfs-api/src/sandbox/get.rsshowsdownnext todown_reason. It is never mapped intodaemon_capacity:CapacityModel::parsefills missing fields with 0, so a partial notice would read aspool_running: 0/ no failures.Capacitystill does not pass throughunanswered, sosandbox.getkeeps answering withdown_reasoninstead of failing.Test evidence
Dell
aluminium(x86_64, 88 cores),rustc 1.85.1, branch on mergedlayerfs_v2_0_0@dbd633fac(#650/#651/#652):The full-pool test reproduces the measured behaviour: the get waits the whole 60 s admission window (asserted
>= 55 s; the run took 60.34 s) and then answers withstate: running,down_reason, anddown = { code: "Capacity", resource: "daemon_control_slot", pool_vacant: 0, reserved_vacant: 1, retained: 3 }, withdaemon_capacityabsent.Full log:
/home/dell/649-final.logonaluminium. The suite runs as the non-rootdelluser (the daemon slot tests need it);cargo test -p layerfs-daemon --test daemon_slots --test slot_stateis 27/27 on this base. Nothing that needs a real kernel mount is touched by this change.Docs:
docs/architecture/api/sdk/sandbox/get.md,sandbox/README.md,docs/architecture/control/routing/daemon-channel.md.Closes #649.