The per-beamline allocation: budget BC, award-window envelope, campaign seal#560
Merged
Conversation
The eighteenth bounded context and the paper's last big component made domain code. An Allocation is the envelope a beamline receives and spends: a USD ceiling, an optional campaign reference that will bind the award window, and a lifecycle whose shape IS the paper's temporal argument, Granted (the award's dormant phase) -> Active (spending) -> Sealed (books closed with a final-spend snapshot), with Voided from the non-terminal states for a mistaken grant. Balance is never stored: it will fold from the same inference ledger every enforcement tier already sums. Five slices ship with routes and MCP tools: grant (genesis, idempotency-wrapped), activate, amend-ceiling (PUT semantics, the cost-overrun tightening lever), seal, and void (reason required). The seal handler takes a total-spend reader at bind time and threads the allocation's own [activated_at, now) window into it; this stage binds a documented zero reader, and the gate stage swaps in the real instance-total query, so the slice's shape never changes. Attribution halves (granted_by / activated_by / sealed_by) ride every fact event per the fold-symmetry convention. AllocationGranted takes the genesis-deviation allowlist's fifth slot: granted is the paper's and HPC accounting's exact verb for an award, and it names the FSM's initial state. Count pins and BC enumerations updated honestly (18 BCs, 43 aggregates; budget graduates from the planned rows to the resource group in the architecture pages). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stages B and C of the allocation arc: the Allocation stops being a declaration and becomes the instrument-wide control the paper claims. Read side: proj_budget_allocation_summary + the AllocationLookup port (no-envelope-declared means no-envelope-constraint, the family's opt-in posture) with the budget BC's Postgres adapter picking the single Active envelope, newest-activated wins. SpendLookup gains find_total_spend, summing every costed row regardless of attribution: the envelope bounds the whole instrument's LLM spend, agent and operator paths alike, which is the paper's one-balance claim. Gates: find_envelope_breach carries both refusal arms, the pre-estimate projection (spent plus pending exceeds ceiling) and the post-hoc exhaustion (spent has reached ceiling), documented side by side. Both subscriber agents defer with AllocationExhausted after their per-agent cap check; the pre-estimate guard gains the envelope arm and now gates even agents with no stream or declared budget, because the envelope is the instrument's bound, not the agent's. The seal slice's reader seam swaps from the stage-A zero reader to the ledger fold, exactly the one-line change the seam promised. The books close themselves: a CampaignClosed subscriber seals the Active allocation bound to that campaign, stamping the final spend from the same ledger fold, authored as SYSTEM via the same-BC decider (the enclosure permit monitor precedent; the wired handler's authorize gate would rightly deny a system principal under real Trust). Deterministic event id and expected-version guard make replay a no-op; mismatched, unbound, or non-Active allocations skip with a log. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd hardening Security. The one real bug: activating a second envelope silently stopped enforcing the first's ceiling and orphaned its automatic seal, and the docstrings claimed a guard that did not exist. activate_allocation is now longhand (the seal precedent) and consults find_active before the transition, refusing with AllocationAlreadyActiveError when a DIFFERENT envelope is Active; the subscribers' remediation text now steers operators to seal or void before activating a replacement rather than orphaning the exhausted one. cost_usd gained a 100k upper bound at the inference write edge, so one poisoned entry can no longer exhaust the whole instrument's envelope or corrupt a sealed books figure. build_kernel raises in its Postgres branch when a financial factory is missing, rather than silently metering zero and disarming the envelope. The BC docstring names the instrument-admin authz tier (the five commands plus CloseCampaign, which transitively disarms via the auto-seal). Correctness. The sealer no longer forfeits the automatic seal on a benign concurrent amend: it re-loads and retries at the fresh version (bounded, deterministic event id keeps it idempotent), and it documents the stale-negative projection-lag window whose recovery is the manual seal slice. The fold-divergence skip logs at WARNING. Naming (per the panel): AllocationCannotAmendCeilingError (full verb phrase), AllocationBreach / find_allocation_breach (the fourth meaning of "envelope" was one too many; the paper word stays in prose), AllocationLookupResult (rejoins the LookupResult family), and note / AllocationNote (a name that needed a disclaimer in its own docstring). Conventions. Purged eleven build-stage markers that had leaked into source and test docstrings, rewording each to name the mechanism; the no-phase-markers fitness regex gains a lowercase-stage arm so letter-only markers cannot slip through again (Title-Case "Stage A" spared, it is the shape of real device names). Tests close the panel's mutation survivors: the single-Active guard both directions, the sealer retry and event-id determinism, gate ordering (cap before envelope, envelope not consulted) in both subscribers, the allocation_lookup factory wiring, the wire_budget ledger-reader binding, the Postgres projection apply arms, the daily-token equality edge, and the build_kernel fail-loud raise. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Coverage reportClick to see where and how coverage changed
The report is truncated to 25 files out of 62. To see the full report, please visit the workflow summary page. This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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
The R1/R2 component of the facility-LLM-budget reference architecture, and the last big one: LLM spend becomes an allocatable, enforceable, self-sealing envelope. Three commits (aggregate, read side + gates + sealer, five-reviewer panel batch) on the new
budgetbounded context. Design locked per the memo: beamline-total envelope,AllocationGrantedgenesis, USD-only ceiling, campaign-scoped debiting deferred to its trigger.What the allocation is
The 18th BC, one aggregate. An
Allocationis the envelope a beamline receives and spends: a USD ceiling, an optionalcampaign_idreference binding the award window, and a lifecycle that IS the paper's temporal argument,Granted(dormant) ->Active(spending) ->Sealed(books closed with a final-spend snapshot), withVoidedfrom the non-terminal states. Balance is never stored: it folds from the sameentries_decision_inferencesledger every enforcement tier already sums. Five slices (grant, activate, amend-ceiling as the cost-overrun tightening lever, seal, void) plus the read side (proj_budget_allocation_summary, theAllocationLookupport,find_total_spendsumming every costed row regardless of attribution, the one-balance claim).The three behaviors that make it the paper's component
[activated_at, sealed_at)lifecycle is the window, event-bound, no calendar.CampaignClosedsubscriber seals the bound envelope automatically, freezing the final-spend snapshot as a SYSTEM-authored event (the enclosure-permit-monitor precedent).Review panel highlights (all applied in eec4404)
Security found the arc's one real bug before merge: the single-Active invariant was claimed in docstrings but enforced nowhere, so activating a second envelope silently stopped enforcing the first and orphaned its seal, and the subscribers' own remediation text steered operators straight into it.
activate_allocationis now longhand with afind_activeguard (AllocationAlreadyActiveError), and the remediation text says seal-or-void-first. Also applied: acost_usdwrite-edge cap (one poisoned entry can no longer halt the instrument or corrupt sealed books),build_kernelfail-loud when a financial factory is missing, the sealer's bounded reload-retry on a benign concurrent amend, four naming renames (incl.AllocationBreachretiring the fourth meaning of "envelope"), a purge of eleven leaked build-stage markers with a fitness-regex arm so they cannot recur, and the mutation-survivor test gaps (gate ordering, factory wiring, wire-binding, Postgres projection arms).Known debt (recorded)
Contract-tier tests for the five endpoints are allowlisted with removal obligations. The at-most-one-Active guard is best-effort (projection-read race, documented). The flat Trust-policy shape cannot yet express the instrument-admin tier the BC docstring names; pre-existing, not introduced here.
Test plan
Unit 12571 · architecture 29520 · contract 3338 (run because the lifespan gained registrations and a Field bound changed) · integration touched suites green · pyright + tach clean. New coverage spans the aggregate trios, evolver, projection (unit + Postgres apply), both lookups, the sealer (seal/skip/retry/determinism/metadata), the envelope gate arms and ordering in both subscribers and the guard, and the fail-loud raise.
🤖 Generated with Claude Code