You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(control): drain admitted operations and result receipts before exit #943
Committed shutdown must close new effectful control admission, settle or explicitly preserve uncertainty for already-admitted operations, and await their durable result writes before releasing the state-process lock. Completion receipts required by that drain must remain writable.
Confirmed source seam
At 115e26fc9c67316a3b0b1b4318f47f7a2bea3606, createControlHost.dispose() synchronously retires waits/window registrations and IPC handlers. It does not join executor work or the private FileControlHistory append tail. Stopping an HTTP transport or disposing a renderer bridge is not evidence that the operation and its result persistence ended.
The executor's active map is populated only after the serialized received-intent append. Draining that map alone would miss pre-registration admission work. Nested observations/waits/batches call the executor directly, and the private main operations.start/operations.finish port must retain the ability to record results during shutdown.
Add a composed regression with an intent write still queued at commit, a dispatched effect awaiting completion, and delayed/rejected result persistence. Assert new effects cannot enter, existing results are still recorded, required failures hold the exit/lock boundary, and transport timeout does not authorize repeating a mutation. Cover nested waits/batches and internal completion receipts.
This is source-grounded follow-up work discovered during #919. The first disposal PR (fix/quit-service-lifecycle, source e9b88bf5) records the gap but does not implement this contract. No application crash/OS-exit reproduction has been run. Keep this issue and the complete B02 acceptance open after that PR.
Refs #919 and #918; coordinate with B05 mutation uncertainty and B02's revision-bound editor preparation.
PR #945 is ready for review at 3d382fb7 (both CI gates green; final-source test:package passed). It is not merged. It does not implement this issue. Revision-bound editor votes, participant revalidation and the control operation/result receipt drain remain open; the focused plan in #945 records the frontier this work must cover.
Fixed on main and never closed — the PR carried no Closes trailer.
b89de37efix(control): drain admitted operations and result writes before exit, then 64575726 (drain with the catalog intact, and bound it) and 0d86b019 (keep the drain deadline in the host, not the neutral SDK).
dispose() now closes admission first (reads still answer; an unknown capability id counts as effectful and is refused), retires the renderer-facing surface, then awaits every admitted operation and then the history tail — that order is the contract, because an operation finishing appends its own result and draining the file first would lose the last one.
Covered by src/main/control/controlDrain.system.test.ts and src/main/control/controlHostDispose.system.test.ts.
Found by cross-referencing open issues against commit messages on main.
Activity
Juliusolsson05 commentedon Sep 12, 2026
PR #945 is ready for review at
3d382fb7(both CI gates green; final-sourcetest:packagepassed). It is not merged. It does not implement this issue. Revision-bound editor votes, participant revalidation and the control operation/result receipt drain remain open; the focused plan in #945 records the frontier this work must cover.fix(control): drain with the catalog intact, and bound it
fix(control): keep the drain deadline in the host, not the neutral SDK
Juliusolsson05 commentedon Sep 20, 2026
Fixed on main and never closed — the PR carried no
Closestrailer.b89de37efix(control): drain admitted operations and result writes before exit, then64575726(drain with the catalog intact, and bound it) and0d86b019(keep the drain deadline in the host, not the neutral SDK).dispose()now closes admission first (reads still answer; an unknown capability id counts as effectful and is refused), retires the renderer-facing surface, then awaits every admitted operation and then the history tail — that order is the contract, because an operation finishing appends its own result and draining the file first would lose the last one.Covered by
src/main/control/controlDrain.system.test.tsandsrc/main/control/controlHostDispose.system.test.ts.Found by cross-referencing open issues against commit messages on main.