Repository navigation
Core: the Account owns its requests and responses; the reducer only carries what follows - #70
Merged
Merged
Conversation
…arries what follows The Account's session, pending request and status are private; it answers each account intent and response itself and returns an AccountChange. The listening ledger sends and settles its own push. Request ids come from one RequestIds source in core state. apply_account_change is the one place the write order is decided: listening before account, now for sign-out and 401 too, pinned by a new account test. ADR 0001 decision 6 records the order. Closes #69 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Summary
The Account now applies its own rules. The reducer only carries the
AccountChangeit returns through to listening and storage, in one place:Command::ServerResponse { id, status, body } - account.settle(id) -> PendingRequest - account_response(): 401 rule, status, session, persists # in reducer - listening.awaits(id) - sync_response(): parse body, sync_succeeded/sync_failed, 401 rule + if account.awaits(id) + account.settle(class, body) -> Option<AccountChange> + apply_account_change() # the one place write order is decided + else if listening.awaits(id) + listening.settle(class, body) -> Synced | Failed | Unauthorized | Dropped + Synced -> persist listening + Unauthorized -> apply_account_change(account.expire())The id peek and its
debug_assertare gone. Each module asksRequestIdsfor an id only when it sends.Within one update, the listening write now always comes before the account write. Sign-out and a 401 used to write the account first. ADR 0001 decision 6 gains the sentence that records this.
Evidence
a_401_writes_listening_before_the_accountfailed on the old reducer:an_account_delete_writes_listening_before_the_account. The diff to existing tests is additions only, and every existing core test passes unchanged throughCore::dispatch.cargo test --workspace,cargo clippy --workspace --all-targetsandcargo fmt --checkall pass.cascade-wasm(wasm32) andcascade-uniffibuild.Merge Danger
Door: two-way
No command, effect, snapshot field or wire shape changes. The one thing a shell can observe is the order of
PersistListening/PersistAccounton sign-out and on a 401. Each shell runs every effect it is handed, so none depends on that order.Blast Radius: core-internal
A regression here would show up in account or sync behaviour on every shell. The existing account, listening-sync, restore and property suites pin that behaviour.
Unaddressed findings
Standards
server.rs, but it now lives inAccount::settle/ListeningLedger::settle. Skipped: the spec says nothing else in the ADR changes. Endpoints, bodies and body parsing still live inserver.rs. Worth a follow-up amendment.delete_listening/delete_account, and a busy check in four methods. Skipped: the spec decided on one method per intent. The shared step is alreadybegin, so a further helper would hide each intent's guard.idsandeffectstravel together. Skipped: the spec gives the ledger "the session token and the id source". An outbox type would be a separate design change.FailedandDroppedare handled the same way by the reducer. Skipped: the spec names these four outcomes.new_device_id: String. Skipped: inherited from before this change, and out of scope.Account::is_signed_in()for the restore check. Skipped: the spec fixes the Account's interface, andsession_token()already covers this check.Spec
Closes #69
🤖 Generated with Claude Code