Skip to content

Fix shared worker result boundaries, falsy outputs, and shutdown classification #701

Closed

Description

@jumski

Parent epic: #699. Independent first batch; applies to released v1 as well as the internal v2 proof.

Current defects

StepTaskExecutor.execute() catches handler execution, successful-handler logging, and completeTask() in one error path. A completion RPC failure therefore calls failTask() as if the handler failed. Its shutdown decision uses only the exception name. PgflowSqlClient.completeTask() serializes output || null, corrupting valid 0, false, and "".

Implementation

Separate the handler outcome from result reporting. Only an actual handler/execution failure belongs in the handler-failure path. Completion/failure RPC or result serialization errors, and logging errors after an outcome exists, must not relabel that outcome or execute the handler again. Preserve existing adapter/platform structure; do not add a generic retry framework.

Once a handler outcome exists, telemetry failure must not prevent its result-reporting attempt. Isolate completion/failure logging from settlement; retain the original outcome and surface telemetry errors separately. A logger failure is neither a business failure nor a reason to retry transport. Pre-handler logging failure must not manufacture a handler-failure settlement. This needs a local boundary, not a logging framework.

Use nullish output handling: undefined and null normalize to JSON null; the valid falsy outputs survive SQL serialization. Check the actual worker shutdown signal, not only error.name. An unrelated handler AbortError with a live shutdown signal is a handler failure. An arbitrary thrown reason with an aborted shutdown signal is interruption, not a new business failure.

If shutdown occurs after the handler returns success, keep that success separate; do not call failTask(). Document whether the reporting attempt proceeds or surfaces as interrupted/unknown acknowledgement. Do not promise recovery of in-memory results after process death.

For v1, surface/log acknowledgement failure without an automatic blind settlement-retry loop: its callbacks have no claim-replay contract. V2's bounded same-result replay belongs to #706, after #704 exists.

Tests and gate

  • Handler success plus completion RPC rejection never calls failTask(); handler invocation count remains one. Failure-RPC rejection does not cause a second failure report or handler execution.
  • A throwing completion logger still attempts completeTask() once with the original result. A throwing failure logger still attempts failTask() once with the original handler error when the shutdown signal is live. Pre-handler logging errors do not manufacture a handler failure.
  • Post-success logging/serialization/reporting failure never enters the business failure path. Preserve an observable error through the existing worker error boundary without suppressing the settlement attempt because telemetry failed.
  • Already-aborted execution does not start a handler or report a handler failure. Actual shutdown with a non-AbortError reason does not report failure; unrelated AbortError does.
  • Shutdown after a successful handler never reports business failure. A real failure without shutdown calls failTask() once with the original failure.
  • Actual SQL storage preserves 0, false, "", JSON null, and undefined→null; mocks alone do not prove SQL serialization.

Add unit checks using observable calls, not private methods, and focused SQL-client integration tests. Run current core unit/types and edge-worker unit/types plus the affected integration target. Preserve JSR Edge and npm Node/Bun runtime paths; add no new dependency.

Depends on: none. Not blocked by protocol design, #696, #697, or #694 diagnosis. Applicable final evidence still belongs to #706.

Activity

  1. added
    bugSomething isn't working
    priority:p1Next batch: current correctness, user blocker, or operational safety
    on Oct 14, 2026
  2. added a commit that references this issue on Oct 23, 2026
    f67145b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpkgs/corepkgs/edge-workerpriority:p1Next batch: current correctness, user blocker, or operational safety

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions