Skip to content

Show durable app activity dots - #140

Closed
hamzamerzic wants to merge 4 commits into
mobius-os:mainfrom
hamzamerzic:fix/durable-app-activity-dots-20260722
Closed

Show durable app activity dots#140
hamzamerzic wants to merge 4 commits into
mobius-os:mainfrom
hamzamerzic:fix/durable-app-activity-dots-20260722

Conversation

@hamzamerzic

Copy link
Copy Markdown
Collaborator

What changed

  • derive a durable unread marker from app-attributed notifications
  • show the existing quiet activity dot for apps with unseen background work
  • acknowledge only the exact activity version the visible shell observed, so a late acknowledgement cannot erase newer work
  • remove markers before hard-deleted app IDs can be reused

Why

Background apps can finish while their UI is closed. Their notification was durable, but the shell had no durable, app-specific nudge after reconnect. This reuses that canonical completion edge rather than adding a second signaling path.

Existing work checked

Searched Möbius PRs and issues for app activity, unread notifications, and drawer dots; no overlapping work was found.

Verification

  • 30 affected backend tests
  • 76 focused shell tests
  • production Vite/PWA build
  • race regression for newer activity arriving before an older acknowledgement
  • git diff --check

Co-authored-by: Möbius Agent mobius-agent@users.noreply.github.com

Preserve newer completion signals when an older visible-app acknowledgement arrives late.

Co-authored-by: Möbius Agent <mobius-agent@users.noreply.github.com>
@hamzamerzic hamzamerzic added area: ui User interface and interaction design enhancement New feature or request labels Jul 22, 2026
@hamzamerzic

Copy link
Copy Markdown
Collaborator Author

Blocking exact a6d8b7f: mark_from_notification accepts any Python int() and passes it to SQLite. An owner/API caller can send {source_type:"app", source_id:"999999999999999999999999999999999999"}; db.get(App, app_id) raises OverflowError: Python int too large to convert to SQLite INTEGER, so an otherwise valid notification returns 500 before the existing persist-failure handling. Please reject non-positive/out-of-SQLite-range ids (or catch bind/overflow errors) and add a route regression proving malformed/huge app attribution still saves/sends the notification without an activity marker.

The version-bounded backend acknowledgement and version-keyed frontend in-flight keys otherwise correctly preserve a notification that races an older acknowledgement.

hamzamerzic and others added 3 commits July 22, 2026 18:03
Co-authored-by: Möbius Agent <mobius-agent@users.noreply.github.com>
Co-authored-by: Möbius Agent <mobius-agent@users.noreply.github.com>
@hamzamerzic

Copy link
Copy Markdown
Collaborator Author

Round-2 fix complete on exact head 8e65a392. The malformed-attribution blocker is closed: app ids are now rejected unless they fit the positive signed 64-bit SQLite key range, before Session.get can bind them. The route regression covers zero and an arbitrarily huge source id and proves all four notifications still persist while no activity marker is created. Rechecked the version-bounded acknowledgement race and version-keyed frontend in-flight ownership; no further finding. Focused tests: 3 passed; pre-push frontend gate passed. Hosted CI is the final gate.

@hamzamerzic

Copy link
Copy Markdown
Collaborator Author

One exact-head API-boundary blocker remains before merge: AppActivitySeenRequest.activity_version is an unbounded Python integer. A request such as {activity_version: 999999999999999999999999999999999999} reaches the SQLite comparison in mark_seen and can raise OverflowError: Python int too large to convert to SQLite INTEGER, returning 500. Please constrain this field to the valid positive signed-64-bit version range (or reject before binding) and add a route regression for zero/negative/huge values. The optimistic failure path otherwise converges: invalidation restores server truth and the version-keyed effect retries when the unseen row refetches.

@hamzamerzic

Copy link
Copy Markdown
Collaborator Author

Final exact-head review on 2baca389cd1592f3975ead35423e4b7314f89099: the acknowledgement API boundary is now closed as well. Pydantic rejects zero, negative, >signed-64-bit, and arbitrarily huge versions with 422 before SQLite binding, and the regression proves the unread marker remains intact. I also rechecked the extracted frontend acknowledgement owner: exact app/version dedupe, optimistic clear bounded by observed version, success re-clear without hiding newer work, failure key release before authoritative refetch, and retry convergence all preserve the race invariant. No remaining finding; hosted checks are the final gate.

@hamzamerzic

Copy link
Copy Markdown
Collaborator Author

Landed on protected main through reviewed integration #147 (merge 226106c). The integrated patch matches this PR's reviewed head; closing the superseded source PR to keep the queue truthful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ui User interface and interaction design enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant