Repository navigation
fix(ocap-kernel): leave a settled result promise alone on delivery failure - #1084
Merged
Merged
Conversation
2 tasks done
sirtimid
force-pushed
the
sirtimid/reject-result-if-pending
branch
from
September 18, 2026 17:19
6086dce to
28accc1
Compare
Contributor
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||
sirtimid
force-pushed
the
sirtimid/reject-result-if-pending
branch
from
September 18, 2026 17:36
28accc1 to
4ad301b
Compare
…ilure A failed delivery may have settled its result on the way down: the vat resolved it and then lost its stream. Resolving a settled promise is a `Fail`, thrown from inside the catch that is handling the delivery's failure, so it escaped the crank and killed the run loop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tled Review follow-up. The caller then gets the endpoint's answer rather than `DELIVERY_FAILED`, and nothing else said so. The regression test runs the crank's reference count audit, and `KernelRouter.test.ts`'s shared store mock reports an unresolved promise by default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sirtimid
force-pushed
the
sirtimid/reject-result-if-pending
branch
from
September 18, 2026 19:22
4ad301b to
5f25173
Compare
sirtimid
enabled auto-merge
September 18, 2026 19:24
FUDCo
approved these changes
Sep 18, 2026
FUDCo
left a comment
Contributor
There was a problem hiding this comment.
Eventually it converges. It does eventually converge, right?
sirtimid
added a commit
that referenced
this pull request
Oct 1, 2026
…e test #1084 landed with a router built positionally, so the logger took the slot the new parameter added and the `already settled` assertions saw nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sirtimid
added a commit
that referenced
this pull request
Oct 1, 2026
…e test #1084 landed with a router built positionally, so the logger took the slot the new parameter added and the `already settled` assertions saw nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sirtimid
added a commit
that referenced
this pull request
Oct 2, 2026
…e test #1084 landed with a router built positionally, so the logger took the slot the new parameter added and the `already settled` assertions saw nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sirtimid
added a commit
that referenced
this pull request
Oct 6, 2026
…e test #1084 landed with a router built positionally, so the logger took the slot the new parameter added and the `already settled` assertions saw nothing. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
A delivery can fail after the endpoint has already settled the message's result promise: a vat resolves the result and then loses its stream, or the stream dies mid-delivery and retiring the vat rejects every promise it was deciding — this one included, its decider having been set just before the delivery.
#deliverSend's catch rejected the result unconditionally, and resolving a settled promise is aFail. So the kernel threw from inside the very catch that was handling the delivery's failure, the throw escaped the crank, and the run loop died naming the promise rather than the dead worker.#rejectResultIfPendingreads the promise's state first and leaves a settled one alone, logging that it did: the caller then gets the endpoint's answer instead ofDELIVERY_FAILED, and theerrorline above it is the only other trace of either outcome.This is one PR in the split of #1021–#1023 into single-defect changes.
Changes
KernelRouter#rejectResultIfPendingreplaces the directresolvePromisescall in the delivery-failure catch, returning early when the result is notunresolved.@metamask/ocap-kernelchangelog entry under Fixed.Testing
KernelRouter.result-promise.test.tsis new, becauseKernelRouter.test.tsmocksresolvePromisesand so cannot see a second resolution of one promise. It runs a real nodejs SQLite:memory:store and a realKernelQueuethrough the run loop's crank — same savepoint name, samecollectGarbageand reference count audit at the end, nocatch, so a throw escapes as it does in the real loop.The
it.eachover an endpoint that fulfils and one that rejects is the regression guard: with the production hunk reverted, both fail with"kp1" was already resolvedescapingKernelRouter.deliver. The positive case,rejects it once the delivery reports failure, stays green under that mutation and fails under a guard that always returns early.Full
@metamask/ocap-kernelsuite green locally (2534 tests); eslint,constraintsandchangelog:validateclean.🤖 Generated with Claude Code
Note
Medium Risk
Touches kernel message delivery and promise settlement on failure paths; incorrect handling could still crash the run loop or mis-report errors to callers.
Overview
Fixes a run-loop crash when message delivery fails after the vat has already settled the message’s result promise (e.g. resolve then stream loss).
KernelRouter’s delivery-failure handler no longer unconditionally rejects the result withDELIVERY_FAILED. New private helper#rejectResultIfPendingreads the kernel promise state first: only unresolved results getDELIVERY_FAILED; if the endpoint already fulfilled or rejected it, that outcome is kept and an error is logged instead of callingresolvePromisesagain (which wouldFailand escape the catch).Adds
KernelRouter.result-promise.test.tswith a real SQLite store and queue (existing router tests mockresolvePromises). Unit test setup defaultsgetKernelPromiseto{ state: 'unresolved' }. Changelog updated under Fixed.Reviewed by Cursor Bugbot for commit b7c95ea. Bugbot is set up for automated code reviews on this repo. Configure here.