Decision records
ADR 0032 — Resource dimensions + bounded negotiation
- Status: Accepted (2026-07-10) — accepted item #5 in the Execution-OS evaluation (
loom/docs/requirements/2026-07-10-execution-operating-system-evaluation.md). Implemented: R1 memBytes/wallMs/netBytes onResourceDelta/Budget/ResourceSnapshot+ fold (EVENT_SCHEMA_VERSION 1.10.0 → 1.11.0, byte-identical when unused) +nestedBudget; R2ctx.negotiateBudget(dimension, request, opts?)via the decision seam. “Energy budget” dropped. - Date: 2026-07-10
- Builds on: ADR 0016 (K3 metering),
@loom/middleware(meteringMiddleware,nestedBudget), M2 decision seam
Context
K3 already meters tokens / cost / ms (RESOURCE_METERED → EffectContext.resources,
per-execution and nested budgets, QUOTA_EXCEEDED). The requirements’ “Runtime Resource Manager”
(P1) asks for more dimensions and dynamic negotiation. Two caveats from the evaluation:
- Extra dimensions are only worth metering where they can be measured/enforced — memory (peak RSS of an isolated K7 child), wall time, and network bytes are feasible; “energy budget” is not and is dropped.
- Unbounded “negotiation” invites non-determinism. Negotiation must be bounded and logged: a
request for more budget resolves against a fixed ceiling via
ctx.decide, so the grant is a durable decision, replay-safe (P9).
Decision
- R1 — dimensions. Extend the metering
ResourceDelta/ResourceSnapshotwith optionalmemBytes?,wallMs?,netBytes?. Additive under K5; unset dimensions behave exactly as today. Memory/network are metered only for effects that can report them (e.g. the K7 isolated executor); others leave them undefined (no false zeros). - R2 — bounded negotiation.
ctx.negotiateBudget(dimension, request)resolves viactx.decideagainst a policy-supplied ceiling: grant =min(request, ceiling - spent), recorded as aDECISION_RECORDED. On replay the recorded grant is served — no live renegotiation. Exceeding a granted budget still raisesQUOTA_EXCEEDED(K3 enforcement unchanged).
Consequences
- Budgets can reflect memory/wall/network where they matter, without touching flows that don’t declare them.
- Determinism preserved (G1): negotiation is a logged decision, not a hidden input; enforcement stays in metering middleware.
- Zero-overhead when unwired (G2): no new dimensions declared and no negotiation call ⇒ identical.
Verification
- Metering a K7 child records
memBytes; a token-only effect leaves it undefined (not0). negotiateBudgetgrantsmin(request, remaining ceiling), records a decision, and replays the same grant; over-spend past the grant raisesQUOTA_EXCEEDED.
Amendments (from the Execution-OS evaluation)
- “Energy budget” dropped — unmeasurable in-kernel.
- “Dynamic negotiation” constrained to bounded + logged — an unbounded/mutating negotiator was rejected as a determinism hazard.
Source: docs/adr/0032-resource-dimensions-bounded-negotiation.md in the loom repository.