Repository navigation
fix(stream): report one batch sink failure - #96
Conversation
Two BatchPublisher writes that each cross the batch limit before the sink settles attached two flush promises to one chain. The sink rejected once and onError ran twice. Report that failure once. Signed-off-by: Sebastien Tardif <sebtardif@ncf.ca>
|
Codex review: needs maintainer review before merge. Reviewed October 3, 2026, 1:08 AM ET / 05:08 UTC (Revision 3). ClawSweeper reviewWhat this changesThe PR makes terminal batch publishing report a sink failure once across overlapping flushes, adds regression coverage, and records the fix in the changelog. Merge readiness✅ Ready for maintainer review The PR remains necessary: current main and v0.3.8 still permit duplicate failure notifications. The resolved head has no actionable findings, and the supplied production-class terminal proof is sufficient. Priority: P2 Review scores
Verification
How this fits togetherThe shared streaming module accepts terminal bytes and batches them into a caller-supplied asynchronous sink. Its error callback lets consuming applications react when output delivery fails. flowchart LR
A[Terminal bytes] --> B[Batch buffer]
B --> C[Threshold or timer flush]
C --> D[Ordered sink calls]
D --> E[Sink failure]
E --> F[Single error notification]
E --> G[Stop and discard buffered output]
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Technical reviewBest possible solution: Keep one error notification for the terminally failed publisher while preserving ordered delivery, discarded later writes, and the original rejection for explicit flush callers. Do we have a high-confidence way to reproduce the issue? Yes: two threshold writes queued before one pending sink rejects reach separate error handlers on current main. Source inspection establishes the path, and the contributor supplies before/after compiled-class output; this review did not execute it. Is this the best way to solve the issue? Yes: a shared guard fits the publisher's existing terminal-failure lifecycle and covers all automatic error-reporting paths without changing exports or delivery ordering. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against ae63783b98a9. LabelsLabel changes: No label changes. Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
History |
* origin/main: fix(worker): finish the bridge when a socket is already closed (openclaw#95) build(deps-dev): bump the development group with 2 updates (openclaw#98) # Conflicts: # CHANGELOG.md
|
Maintainer conflict resolution pushed at
@clawsweeper re-review |
|
🦞👀 Re-review progress:
|
* origin/main: fix(stream): report one batch sink failure (openclaw#96) fix(worker): finish the bridge when a socket is already closed (openclaw#95) build(deps-dev): bump the development group with 2 updates (openclaw#98) # Conflicts: # CHANGELOG.md
What Problem This Solves
BatchPublishercan start a second flush while the first sink call is still running. Both flushes share one promise chain. When the sink rejects once,onErrorruns twice.Why This Change Was Made
Each threshold write calls
flush()and reports a rejection throughonError. The second call does not start a second sink invocation; it waits on the same failure. The publisher now reports that failure once.User Impact
A caller that disconnects or retries from
onErrorsees one notification for one sink failure, including when another full batch was queued behind it. Later writes are still dropped after that failure.Evidence
Terminal output from Node v26.10.0, constructing
BatchPublisherfromdist/stream.jswithmaxBatchBytes: 1. Two one-byte writes ran before the sink rejected.Before this patch:
After this patch:
Real behavior proof
BatchPublishersink rejection invokedonErrortwice when a second full batch was queued behind it.dist/stream.jsfromfix/batch-one-sink-error.maxBatchBytes1, reject the sink once, and countonErrorcalls.nodecommand:onErrorran once. The unpatched bundle ran it twice for the same rejection.