Session: pool checkout and return — the steady-state slot cycle #31
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Meta/Campaign
Meta/Epic
Meta/Session
Priority/Critical
Priority/High
Priority/Low
Priority/Medium
Reviewed/Confirmed
Reviewed/Curated
Reviewed/Duplicate
Reviewed/Invalid
Reviewed/Won't Fix
Scope/Campaign
Status/Abandoned
Status/Blocked
Status/Conflicted
Status/In Progress
Status/In Review
Status/Need Grooming
Status/Need More Info
Status/Ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Depends on
Reference
Ting/Vedanta#31
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Proposal
The steady-state loop over an already-provisioned pool: allocate a slot to a session, and return it afterwards carrying nothing forward.
Session review boundary
One PR, one verdict over the cycle: allocation, the assignment stamp, ordinary completion, and the guarantee that a returned slot inherits no prior authority. Bring-up is #30 — a one-time act with a different reviewer question and a different blast radius.
Design
Checkout binds a slot to a session under a new immutable grant. It inherits no prior lease, token, or authority. It stamps the occupancy onto the slot's OpenBao entity alias
custom_metadata, which is what makes the swarm KV path per-assignment rather than per-slot — R4's requirement, whose consumer is already written in flake-ops#471. That path shape is this Session's acceptance for the stamp.custom_metadata, not a claim, and the reason is structural rather than stylistic: a kanidm claim map isvaluesByGroup, so a claim carries only what the directory asserts about an account, and occupancy has no group to hang on. Aliasmetadatais rewritten from claim mappings on every login;custom_metadatais written out of band and a login does not touch it, which is the lifetime this value needs.Return is ordinary completion: revoke the session capability, rotate the checkout credential, advance the generation, and return the same
worker-<UUID>slot to the pool. The principal survives — deletion, suppression, tombstoning and recreation are reserved for compromise or irrecoverable retirement, and are not this Session's.A slot is freed by an explicit release and by nothing else. Per the freeholder direction on Ting/Ting#2 Q2 (2026-09-04), the liveness mechanism stays undefined until incidents show what evidence is actually available. Rather than leave a gap, the cycle takes the conservative shape: nothing infers liveness, so no timeout, staleness rule, or unreachable runtime frees a slot. #37 owns that rule and is specifiable today — the deferral costs no acceptance.
The chosen failure is pool exhaustion: a drone that dies without releasing holds its slot, and ten such deaths stop the swarm. Loud, bounded, recoverable, and it produces the incident record a real liveness mechanism will be designed against.
Do not reach for the contract's
assignment_idfor the stamp. That names the queen's tenure assignment that authorized a request — one value shared by every drone under a queen. It cannot separate two occupants of one slot, which is the stamp's entire job, and a path built on it looks isolated and is not.Tasks
custom_metadata, against flake-ops#471's path shape.Specification Delta
Requirement: a returned slot carries nothing forward
Scenario: a session completes and the slot is reused
Requirement: occupancy is what isolates, not the slot
Scenario: two successive occupants of one slot
Requirement: the principal survives ordinary completion
Scenario: a session ends normally
Requirement: only an explicit release frees a slot
Scenario: a holder disappears without releasing
OpenSpec
OpenSpec 30 — agent identity pool lifecycle, which projects from ratified OpenSpec 61 v0.1.4, whose amendment 0.1.2 is the return path. This Session is its steady-state half; #30 is the other.
Structural parent
Ting/Ting#2 — Epic: agent identity pool lifecycle. Session split ratified there as Q3 (2026-09-03).
Absorbs
#9 — R4's per-assignment isolation. The stamp has no caller until checkout exists, so it is a requirement of this Session rather than a Deliverable of its own.
Delivered by PR #39, merged at
7b9b5ba. All three leaves closed: #35, #36, #37.src/checkout.rscarries binding under a new grant with thecustom_metadataoccupancy stamp, ordinary completion that preserves the worker, and the explicit-release rule. 96 lib tests, gate green.Two guarantees are structural rather than asserted, which is worth knowing before anyone edits the module:
Occupancyhas no delete, suppress, or tombstone method. Adding one would silently remove the proof.One gap this Session did not cover, now filed as #40.
Cycle::newstarts every slot available — correct for a pool that has never run, wrong for every restart after the first. A process that restarts while drones hold slots comes back believing the pool is empty. That is #37's failure arriving through a door #37 does not watch: the safety rule is stated per-transition, and the gap is in the initial state.Not a scope miss by this Session — OpenSpec 30 does not specify restart recovery at all, so the package wants an amendment alongside #40.
src/checkout.rsmust not run against a real pool until #40 lands.