fix: isolate standalone bridge process generations

Merged
LL
2mo ago
+239-22

Summary

Follow-up to #233 and the two post-review P1 findings:

  • ignore stdout/stderr callbacks from retired child generations so a stale end cannot flush replacement output
  • fence configure completion to the child that received configure, preventing an old continuation from marking a replacement configured
  • retire the child and clear pending state for both synchronous and asynchronous stdin write failures
  • classify in-flight standalone failures as outcome-unknown so bash host fallback cannot blind-replay a possible mutation

Request outcome contract

  • a child already known to be unwritable before a request is queued can still be replaced before dispatch
  • after write initiation or an in-flight child teardown, the outcome is UNKNOWN; callers receive verification guidance and host fallback is ineligible
  • no request is replayed across process generations

Review findings addressed

Verification

  • bun test packages/aft-bridge/src/__tests__ — 488 passed, 14 skipped
  • bun run --filter @cortexkit/aft-bridge typecheck
  • Biome check on all five changed files
  • public barrel driver: unknown-outcome error exported, fallback ineligible, UNKNOWN/no-blind-retry guidance present

All commits are SSH-signed and based on merge commit 7ea58ee2.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Isolates bridge process generations to prevent stale-child output, cross-generation configure completion, and blind replay after stdin write failures. Previously, retired children could flush replacement stdout, configure completion could carry over, and in‑flight standalone failures were treated as retryable; now we fence I/O and configure to the owning child, retire on write errors, and surface an unknown‑outcome error that blocks bash fallback.

  • Introduces BridgeTransportUnknownOutcomeError and BRIDGE_TRANSPORT_UNKNOWN_OUTCOME_DISPOSITION; exported from aft-bridge.
  • Treats stdin write failures (sync and async), crashes, and signals as unknown outcome: clears pending, rejects with unknown‑outcome error, and invalidates the current child; no request is replayed across generations.
  • Ignores stdout/stderr data/end from retired children; only the current child can mutate buffers.
  • Fences configure: ties warnings, version check, and completion to the child that started configure; if the child changes, throws BridgeTransportUnavailableError instructing a retry on the replacement.
  • Updates error adaptation to append unknown‑outcome guidance and to exclude unknown‑outcome errors from isBashTransportDeadError, making bash host fallback ineligible.

Migration

  • If you special‑case transport failures, handle BridgeTransportUnknownOutcomeError explicitly: verify actual state before retrying and never blind‑retry mutations; do not route these errors to bash fallback. No other changes required.

Greptile Summary

This PR isolates standalone bridge process generations and introduces an explicit unknown-outcome error contract to prevent unsafe mutation replay.

  • Fences configure completion and stream callbacks to their originating child.
  • Retires children after synchronous or asynchronous stdin write failures.
  • Prevents bash host fallback for standalone requests that may already have executed.
  • Exports and tests the new unknown-outcome error contract.

Confidence Score: 4/5

The timeout-escalation gap should be fixed before merging because an in-flight mutation can be rejected without the required outcome-unknown guidance.

Generation fencing and write/crash handling are improved, but handleTimeout still emits an untyped sibling-abort error after requests may have reached the child, bypassing the new no-blind-retry contract.

Files Needing Attention: packages/aft-bridge/src/bridge.ts, packages/aft-bridge/src/error-contract.ts

Important Files Changed

FilenameOverview
packages/aft-bridge/src/bridge.tsAdds process-generation guards and unknown-outcome handling, but timeout escalation still rejects in-flight siblings with a plain Error.
packages/aft-bridge/src/error-contract.tsAdds unknown-outcome guidance and disables bash fallback for the new error type, but cannot recognize the plain sibling-timeout rejection.
packages/aft-bridge/src/index.tsCorrectly exports the new error class and disposition constant.
packages/aft-bridge/src/tests/bridge-transport.test.tsAdds focused generation and write-failure regressions but does not assert unknown-outcome classification for timeout-aborted siblings.
packages/aft-bridge/src/tests/error-contract.test.tsVerifies fallback ineligibility and safety guidance for explicitly typed unknown-outcome errors.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Standalone request written] --> B{Response received?}
  B -->|Yes| C[Resolve request]
  B -->|Write or child failure| D[Retire child generation]
  D --> E[Reject pending as outcome UNKNOWN]
  E --> F[Verify state; never blind-retry]
  B -->|Sibling timeout escalates| G[Reject siblings with plain Error]
  G --> H[SIGKILL child]
  H --> I[Unknown-outcome guidance is omitted]

Reviews (1): Last reviewed commit: "fix: block fallback for unknown bridge o..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used: