fix(supervise): a retained child's settlement names why it is pending, as a value - #1266
Merged
Merged
Conversation
…, as a value One reason string covered a safety refusal and a provider contract violation, which call for opposite operator responses (#1204: six exhibits in three days, five of them contract violations wearing the refusal's name). The runtime made it worse by minting one RetainedRunProviderContractError both when the provider answered wrongly and when a read of the provider merely failed. RetainedExecutionPendingError carries pendingCause — unobservable, provider-contract, request-rejected, transport, nested-recovery — classified from the typed cause's structure (class name, code, HTTP status, Zod issues, AggregateError members), never its message text. Classification is phase-aware: a 4xx, a not-found or a client deadline AFTER admission is the provider failing to resolve what it admitted (unobservable), not a rejected request. A read-failed contract error is a wrapper and what it wraps decides; the event-stream catch splits READ_FAILED from INVALID so the runtime's own checks keep their verdict; the live stream's event-binding check mints RETAINED_EVENT_BINDING_INVALID; every driverExecutor nested-recovery throw states its cause. retainedPendingCause rides beside retainedExecution on Settled, the reconciled and terminal records (one shared spread, so live and healed released records agree), NodeSnapshot, replay, both agent.child payloads and the observer projection. Exhibits 3 and 6 are plain provider Errors a structure-only classifier cannot name; they stay unobservable and the CHANGELOG says so. Refusal behaviour unchanged. 0.235.0: exported shapes moved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
Author
|
Cutting v0.235.0 at the merge commit now (tip of |
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.
Closes #1204.
The hole
retained provider execution requires reconciliation before replacementwas the settle reason for two situations that call for opposite operator responses: an execution whose status genuinely cannot be determined (refuse to replace; reconcile first or pay twice), and a provider that broke its contract (nothing to reconcile; fix or report the provider). Six exhibits in three days wore the first name for the second fault. The runtime made it worse: it minted oneRetainedRunProviderContractErrorboth when the provider answered wrongly and when a read of the provider merely failed, so even exhibit 4 (the one genuine "unknown") looked like a contract violation from the inside.The fix
RetainedExecutionPendingError.pendingCause: RetainedPendingCause—'unobservable'(the safety refusal),'provider-contract','request-rejected','transport','nested-recovery'— and the message names which one. Classified from the typed cause's structure (class name,code, HTTPstatus, Zod issues,AggregateErrormembers), never message text: the provider is not a dependency of this package.'unobservable'.'request-rejected'is named only at admission. The first draft of this got that inverted and the independent check caught it; the unit test now pinsREAD_FAILED → NotFoundError(404)asunobservable.RETAINED_EVENT_STREAM_READ_FAILEDfor the iterator,RETAINED_EVENT_STREAM_INVALIDfor the runtime's own checks); the live stream's event-binding check mintsRETAINED_EVENT_BINDING_INVALID, so an event bound to another run classifies as the contract violation it is (e2e test). EverydriverExecutornested-recovery throw states its cause instead of inheriting whatever the driver threw.retainedPendingCausebesideretainedExecutiononSettled's down arm, thereconciledand terminal records (one shared field spread, so live and healed released records agree),NodeSnapshot, replay, bothagent.childpayloads,PursuitNodeProjection.event arrived without a stable id) and 6 (value exceeds its JSON bound) are thrown by agent-provider-tangle as plainErrors with no code. A structure-only classifier cannot name them; they land on'unobservable', the safe side, until the provider types them. The CHANGELOG says so; no test pretends otherwise.down,infra: true, retained-pending, and counts infleetYield.releasedUnrecoveredonce released.Process
Three independent checkers (exhibit truth, every-surface agreement, wrapper rule) on the first commit: sound-with-corrections, five confirmed defects, all fixed — including two invented error codes the first test suite certified but no code path produces, now deleted. Every shape in
retained-pending-cause.test.tsis one the runtime or the Sandbox SDK actually throws.Evidence
unobservableon every surface; SDKServerError{502}→transport; foreign-run event →provider-contract).typecheck,biome,build,api-surface,docs:api(0 warnings),docs:freshness,check:version-bump(5 export changes → 0.235.0,release:prepareapplied),check:testing-fixture,check:publish-workflowall exit 0.merge-treeclean againstmain.disco reportreads the reason only as fixture text; nothing there changes.🤖 Generated with Claude Code