Skip to content

Conversation

@samholmes
Copy link
Contributor

@samholmes samholmes commented Nov 20, 2025

CHANGELOG

Does this branch warrant an entry to the CHANGELOG?

  • Yes
  • No

Dependencies

none

Description

none

Note

Persists WIP login stash changes before server calls, heals/reconciles them on startup, and accelerates sync while changes are pending.

  • Login stashes:
    • Add LoginStash.wipChange (cleaners updated) and clear it on authoritative server payloads.
    • applyKit: write WIP changes to disk before network call; on failure, attempt syncLogin then rethrow; finalize by saving resolved stash.
    • New healLogins(ai): on startup, reconcile WIP stashes using /v2/sync and save the correct state.
    • Selectors (getStashById, getStashByUsername) and login.localUsers reducer now read from rootStash.wipChange ?? rootStash.
  • Context/Account timers:
    • Run one-time loginHealer in context-pixie.
    • In account-pixie, reduce sync interval to 5s when a stash has wipChange; dynamically adjust periodic tasks.
  • Docs:
    • CHANGELOG: “Recover WIP login stashes if login-server network requests fails.”

Written by Cursor Bugbot for commit acc9a41. This will update automatically on new commits. Configure here.


await saveStash(ai, newStash)
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Inverted logic in WIP stash recovery condition

The healLogins function determines whether the server accepted a pending change by inverting the sync response with !asBoolean(reply). However, the /v2/sync endpoint returns true when the client is current/synced, meaning the server has the change. The inversion causes the logic to be backwards: when the server has the change (true), serverHasIt becomes false, and when the server doesn't have it (false), serverHasIt becomes true. This causes pending changes to be discarded when they succeeded and committed when they failed.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed this issue in a fixup! commit

const { stashes } = ai.props.state.login
for (const stash of stashes) {
for (const rootStash of stashes) {
const stash = rootStash.wipChange ?? rootStash
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong, but it was there to figure out why it wasn't working during sanity test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swansontec Should I keep this or should I go with another approach to solve the problem where pin-login will no longer work on the light-account when there is a wipChange and that the login server has?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what you are asking. How is this line wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have said "I don't know if this is right". I don't know if it's wrong, but it solved the issue with pin-login, but I wasn't sure if this is the correct solution. I felt uncomfortable always assuming wipChange is the correct stash to use.

Now that I think about why I felt uncomfortable, there is a case where pin-login will break if the login-server doesn't have the changes that wipChange has. In this case, pin-login will break because wipChange is the wrong stash according to the login server. So perhaps the correct solution is to pick wipChange depending on if the login-server has the changes or not. This would require that we query the login-server to determine this and then drill this information down to the selector.

@samholmes samholmes marked this pull request as draft November 20, 2025 22:54
Copy link
Contributor

@swansontec swansontec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks generally correct. I would say, "debug it yourself" now, except that the AI may have noticed something worth double-checking.

// Start once the EdgeAccount API exists:
dataTask.start({ wait: SYNC_INTERVAL * (1 + Math.random()) })
loginTask.start({ wait: SYNC_INTERVAL * (1 + Math.random()) })
dataTask.start({ wait: interval * (1 + Math.random()) })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change the dataTask frequency. The problem is with the login server, so we just need to increase that task's frequency.

fixup! Recover WIP login stashes

Fix inverted logic in healLogins sync check
fixup! Recover WIP login stashes

Only increase loginTask frequency, not dataTask
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants