Split from #16596 as the delivered actuator-half leaf — the close-target pattern #16603 established on this same family: the leaf carries what IS delivered, the parent keeps what isn't (the post-merge raise observation and the controller wiring that produces autonomous raise attempts).
Context
The diagnosis half shipped with PR #16597: a store-classed service at sustained memory saturation routes to a raise-ceiling action class — which nothing could perform. The actuator half was designed in #16596 comment 2 (@neo-opus-vega): the store path is NOT a reuse of reconfigure, because reconfigure couples its mutation to a restart, and for a store mid-ingestion the restart is the harm (a chroma restart mid-import killed a 59,754-row restore at 24,000 rows). #16596's handover transferred the lane on 2026-08-07 with three shipped ACs tree-verified and the open set enumerated.
The Problem
Five delivered concerns need one honest close target so the parent can stay open on its genuinely-remaining scope:
A container-memory-ceiling knob with registry-enforced bounds (violation, never clamp).
The store-variant actuator envelope: durable overlay + live activation, restart explicitly absent.
Anti-thrash: the ratchet terminates at the registry cap; the cadence envelope inherits.
ADR-0025/ADR-0026 amendments carrying the action class, the matrix row split, and the store/transient rationale — in the same change as the code they sanction (ADR-0026 AC-9).
The healthy-state classification projection (moved to the parent from #16603 at @neo-gpt cycle-4; new behaviour, not wording).
The Architectural Reality
ai/services/memory-core/helpers/recoveryKnobRegistry.mjs — the closed knob set; container-memory-ceiling with an 8–16 GiB derived band, serviceKey: 'chroma' binding, and a raise-not-lower invariant whose bound resolves only from the RUNTIME (inspect → HostConfig.Memory), which is what makes the restart-coupled reconfigure channel fail closed on this knob by construction.
ai/daemons/orchestrator/services/DeploymentRuntimeAccessService.mjs — update-memory-limit joins the frozen lifecycle-write operation set (POST /containers/{id}/update, MemorySwap pinned to Memory); the config allowlist leaf (ai/configBase.mjs) gains the same default.
ai/daemons/orchestrator/services/RecoveryActuatorService.mjs — raise-ceiling in DEFAULT_ACTIONS; admitted for store-classed compose services only; executor = knob-binding check → live-limit read → writeKnobOverride → live activation → NO restart (negative spec through the recorded lifecycle seam, mutation-verified).
ai/daemons/orchestrator/services/ContainerHealthDiagnosisService.mjs + DeploymentStateBridgeService.mjs — describeClassification, a verdict-free projection attached to every per-service snapshot.
learn/agentos/decisions/0025…/0026….md — the amendments, incl. the §2.8 store-variant envelope and the throttle-shed cross-world disclosure pointing at #16636.
Acceptance Criteria
container-memory-ceiling exists in RECOVERY_KNOBS with registry-enforced bounds; an out-of-band request is rejected with a violation, never clamped (parent AC-3).
The raise is bounded and anti-thrash: a raise past the cap is a thrown, recorded refusal; repeated refusals march the cadence envelope to alarm-only (parent AC-6 as restated).
A store-class ceiling raise does not restart its target — negative spec asserts the restart path uncalled on the store path (parent's folded comment-2 AC).
raise-ceiling is admitted for store-classed compose services only; transient compose, supervised-task, and deploy-target refusals asserted.
ADR-0025 and ADR-0026 carry the action class, the class-split matrix row, the §2.8 envelope, and the store/transient rationale (parent AC-7); the ADR-coherence spec stays green.
DeploymentStateBridge emits serviceClass, serviceClassDeclared, the applied threshold, and observedWindowMs beside requiredWindowMs for every service on every snapshot, independent of load — a healthy store at 10% memory carries all of them (parent AC-1).
Out of Scope
The reactive controller that turns a raise-ceiling diagnosis into an autonomous apply() call — no container-health decision consumer exists for ANY action class today; the parent's post-merge AC-8 depends on it and stays open there.
Consumption of the durable overlay's deploy.* subtree at the next up — the #16452 activation-kernel lane; the ADR amendment states the gap explicitly.
Service-class (non-store) ceiling routing, the throttle-shed cross-world reconciliation, and the undeclared-ceiling record — #16636, deliberately sequenced blocked_by #16596.
Decision Record impact
amends ADR-0025 · amends ADR-0026 (delivered by this leaf's PR, in the same change as the sanctioned code).
Live latest-open sweep: checked latest 20 open issues at 2026-08-07T14:30Z; no equivalent found (#16636 is the adjacent service-side half, split deliberately). A2A in-flight sweep: no competing claim on the store-side actuator half; lane claimed 13:53Z.
Admit only chroma ceiling raises strictly above the live limit and within 8–16 GiB; values are bytes and never clamped.
Missing/unreadable/non-positive live context, non-chroma re-aim, partial/extra leaves, below-floor, above-cap, or equal/lower proposals refuse before any write.
Registry JSDoc + ADR-0026
L2 registry and full-actuator negative/positive specs.
RecoveryActuatorService.apply(serviceKey, 'raise-ceiling') (new action)
For the declared store compose target: inspect live limit → validate/write durable knob overlay → issue one live memory update → record previous/new ceiling; never restart.
Target/action mismatch rejects before the executor; validation/runtime failure records a failed attempt and follows the persisted cadence envelope to alarm-only.
DeploymentRuntimeAccessService.applyLifecycle(... update-memory-limit ...) (new operation)
ADR-0026 §2.8 + AC-9/AC-12
Resolve exact Compose identity and expose only the bounded store-ceiling capability needed by the validated raise action; send typed JSON with MemorySwap === Memory and no restart.
Disabled/unallowlisted operation, wrong service class, lower-than-live, out-of-band/invalid value, ambiguous identity, self-target, or Docker failure refuses before the update endpoint.
Every service snapshot exposes declared class, applied memory threshold, measured/required window, sample count, and stamp coverage independent of load.
Unknown service reports declared: false; absent projection seam emits null; missing samples report a zero span without fabricating a verdict.
Diagnosis/bridge JSDoc
L2 healthy-store, transient sibling, unstamped/no-sample, accumulating-window, and null-degrade specs.
Recovery-run details.ceilingRaise (new additive receipt)
Parent #16596 post-merge observability AC + ADR-0026 performed-vs-in-effect provenance bound
An actioned raise records the previous and requested byte ceilings beside the runtime proof.
Failure records executor failure without claiming the raise holds; later recreate may reverse the live effect until #16452 converges the overlay.
Actuator JSDoc + ADR-0026
L2 ledger/outcome assertions; L3 parent #16596 live observation.
tobiu referenced in commit 82e2629 - "feat: A store's ceiling is raisable — bounded knob, live update, no restart (#16637) (#16638) on Aug 7, 2026, 7:21 PM
Split from #16596 as the delivered actuator-half leaf — the close-target pattern
#16603established on this same family: the leaf carries what IS delivered, the parent keeps what isn't (the post-merge raise observation and the controller wiring that produces autonomous raise attempts).Context
The diagnosis half shipped with PR #16597: a store-classed service at sustained memory saturation routes to a
raise-ceilingaction class — which nothing could perform. The actuator half was designed in #16596 comment 2 (@neo-opus-vega): the store path is NOT a reuse ofreconfigure, becausereconfigurecouples its mutation to a restart, and for a store mid-ingestion the restart is the harm (a chroma restart mid-import killed a 59,754-row restore at 24,000 rows). #16596's handover transferred the lane on 2026-08-07 with three shipped ACs tree-verified and the open set enumerated.The Problem
Five delivered concerns need one honest close target so the parent can stay open on its genuinely-remaining scope:
container-memory-ceilingknob with registry-enforced bounds (violation, never clamp).#16603at @neo-gpt cycle-4; new behaviour, not wording).The Architectural Reality
ai/services/memory-core/helpers/recoveryKnobRegistry.mjs— the closed knob set;container-memory-ceilingwith an 8–16 GiB derived band,serviceKey: 'chroma'binding, and araise-not-lowerinvariant whose bound resolves only from the RUNTIME (inspect→HostConfig.Memory), which is what makes the restart-coupledreconfigurechannel fail closed on this knob by construction.ai/daemons/orchestrator/services/DeploymentRuntimeAccessService.mjs—update-memory-limitjoins the frozen lifecycle-write operation set (POST /containers/{id}/update,MemorySwappinned toMemory); the config allowlist leaf (ai/configBase.mjs) gains the same default.ai/daemons/orchestrator/services/RecoveryActuatorService.mjs—raise-ceilinginDEFAULT_ACTIONS; admitted for store-classed compose services only; executor = knob-binding check → live-limit read →writeKnobOverride→ live activation → NO restart (negative spec through the recorded lifecycle seam, mutation-verified).ai/daemons/orchestrator/services/ContainerHealthDiagnosisService.mjs+DeploymentStateBridgeService.mjs—describeClassification, a verdict-free projection attached to every per-service snapshot.learn/agentos/decisions/0025…/0026….md— the amendments, incl. the §2.8 store-variant envelope and thethrottle-shedcross-world disclosure pointing at #16636.Acceptance Criteria
container-memory-ceilingexists inRECOVERY_KNOBSwith registry-enforced bounds; an out-of-band request is rejected with a violation, never clamped (parent AC-3).raise-ceilingis admitted for store-classed compose services only; transient compose, supervised-task, and deploy-target refusals asserted.DeploymentStateBridgeemitsserviceClass,serviceClassDeclared, the applied threshold, andobservedWindowMsbesiderequiredWindowMsfor every service on every snapshot, independent of load — a healthy store at 10% memory carries all of them (parent AC-1).Out of Scope
raise-ceilingdiagnosis into an autonomousapply()call — no container-health decision consumer exists for ANY action class today; the parent's post-merge AC-8 depends on it and stays open there.deploy.*subtree at the nextup— the #16452 activation-kernel lane; the ADR amendment states the gap explicitly.throttle-shedcross-world reconciliation, and the undeclared-ceiling record — #16636, deliberately sequenced blocked_by #16596.Decision Record impact
amends ADR-0025 · amends ADR-0026 (delivered by this leaf's PR, in the same change as the sanctioned code).
Related
#16603(the detection-half leaf precedent) · #16636 (service-side act half, blocked_by parent) · #16630 / PR #16634 (declared-heap detect half;collectStatsFactsseam — whichever merges second rebases) · #16452 (activation kernel).Live latest-open sweep: checked latest 20 open issues at 2026-08-07T14:30Z; no equivalent found (#16636 is the adjacent service-side half, split deliberately). A2A in-flight sweep: no competing claim on the store-side actuator half; lane claimed 13:53Z.
Origin Session ID: 46db6bad-18a4-4064-8bf3-a140cc9a6243
Retrieval Hint:
query_raw_memories("store ceiling raise-ceiling no-restart knob live activation")·RecoveryActuatorService.raiseComposeServiceCeilingAuthored by Clio (Claude Fable 5, Claude Code).
Contract Ledger
RECOVERY_KNOBS.container-memory-ceiling(new)RecoveryActuatorService.apply(serviceKey, 'raise-ceiling')(new action)DeploymentRuntimeAccessService.applyLifecycle(... update-memory-limit ...)(new operation)MemorySwap === Memoryand no restart.deployment-service-state.classification(new additive field)declared: false; absent projection seam emitsnull; missing samples report a zero span without fabricating a verdict.details.ceilingRaise(new additive receipt)