Repository navigation
fix(client)!: one rule for host-callback exceptions, fix the adopted-save ghost, slim proposal 0009 - #55
Merged
sunib merged 4 commits intoOct 5, 2026
Conversation
adoptSaved went through the stream's upsert path, which marks the UID as seen in an open snapshot cycle. A save response that landed after a reconnect's reset therefore kept the object alive through a snapshot that no longer contained it: a deleted UID survived an empty synced and nothing would ever remove it. Only the stream's own upserts count towards a snapshot now. adoptSaved and accepted guarded reads share a private update path that never marks membership; a response is still adopted, and synced prunes it if the snapshot does not send it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the consumer's exceptions were handled precisely. A subscribe callback or onError that threw during a connection was swallowed as a network failure and retried until the budget ran out, so a buggy render function became a reconnect storm ending in exhausted. One thrown between connections rejected closed without publishing closed, and one thrown by the health timer's live escaped as an uncaught error. Every exception from host code now takes one path. The connector records the first, aborts the connection and stops without retrying, still notifies every subscriber of the state being published, ends in closed (unless it had already ended terminal or exhausted) and rejects closed with that exception after cleanup. The internal fetch loop no longer catches host code at all. The README says to attach a rejection handler to closed and not to pass an async consumer, which type-checks but can let live precede the applied synced and loses its exceptions. BREAKING CHANGE: an exception thrown by a subscribe callback or onError now stops the stream without retrying and rejects closed with that exception, as a consumer exception does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One page maps every removed browser and gateway name to its replacement: the connector's callback, state and subscribe in place of its lifecycle callbacks, a first-snapshot promise without onSynced, and the nested StreamConfig literal. It also says to attach .catch to closed, not to pass an async consumer, and that a protocol mismatch is terminal. The READMEs link to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review found change 2 bundled removals, the snapshot tracker, a new ResourceStore, entry points and new option shapes, and that the case for ResourceStore is thin: its reference use is the repository's own example, and krm-foyer, the one known consumer, edits. - Change 2 is now the editor removals and fixes only. - The adopted-save membership bug ships ahead of it as a fix:. - SnapshotTracker, ResourceStore and the read-only example, and the stream/editor entry points, are deferred with explicit triggers: a read-only view that should not load the merge engine, or an unbundled consumer that benefits from loading only the stream layer. - Exceptions from subscribe callbacks and onError follow the consumer's rule (stop, no retry, reject closed), replacing the earlier out-of-scope note, and async consumers are documented as unsupported. - Proposal 0010 records its implementation, the nested-literal cost and the one golden message line it changes. Both proposals are re-wrapped at 100 columns. The previous reflow left fragments such as `state` and `}` on lines of their own, one of them splitting an inline code span; only whitespace changes there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 19 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Stacked on #54, which is stacked on #53. This PR is based on
feat/proposal-0010-gateway-api-cleanupand adds four commits. #53 and #54 are unchanged. Each PR retargets as the one below it merges.It addresses the review of #53 and proposals 0009/0010.
Code
The adopted-save ghost, as its own
fix:(9b092d6)adoptSavedwent through the stream's upsert path, which marks the UID as seen in an open snapshot. A save response adopted after a reconnect'sresettherefore kept a deleted UID alive through an emptysynced. Now only the stream's own upserts count towards a snapshot.adoptSavedand accepted guarded reads share a private update path that never marks membership. A new regression test reproduces the ghost; it fails before the fix and passes after.Host-callback exceptions, one rule (
40955b1)Before, a
subscribecallback oronErrorthat threw had different effects depending on timing:exhausted;closedwithout publishingclosed;live, it escaped as an uncaught error.Now the consumer, subscribers and
onErrorall follow the consumer's rule. The first exception stops the stream without retrying, every subscriber still sees the state being published, the stream endsclosed, andclosedrejects with that exception after cleanup. The internal fetch loop no longer catches host code. Four new tests cover these cases, and all four fail against the previous connector.Docs
585baa1,docs/migrating.md, linked from both READMEs):onSyncedwith a first-snapshot promise..catchtoclosed.asyncconsumer: it type-checks, butlivecan then come before the snapshot is applied, and its exceptions are lost.StreamConfigliteral. Assignments still work through field promotion.0921657):SnapshotTracker,ResourceStorewith the read-only example, and thestream/editorentry points are deferred, each with an explicit trigger. The reference use forResourceStoreis the repository's own example, and the one known consumer edits.stateand}`sat on lines of their own, one of them inside a code span. Only whitespace changes; the text is identical with whitespace collapsed.Not done here
js/file-access-to-http) are false positives. The e2e wire test builds request URLs to the local replay server from fixture IDs in the committed corpus. They don't block (the CodeQL check passes). I've left dismissing them to a maintainer rather than change feat(client)!: deliver resource state events from one stream connector #53.Verification
task verifypasses on0921657: fixtures-check, lint, test (client 134/134, Vue 2/2, both Go modules), release-rehearsal, e2e-wire, e2e-browser (20/20) and pack-client. No Go code changes in this PR.BEGIN_COMMIT_OVERRIDE
fix(client): never count an adopted save response as snapshot membership
fix(client)!: stop the stream when any host callback throws
BREAKING-CHANGE: an exception thrown by a subscribe callback or onError now stops the stream without retrying and rejects closed with that exception, as a consumer exception does.
docs: add an upgrade guide from 0.7
END_COMMIT_OVERRIDE
🤖 Generated with Claude Code