Skip to content

Approvals: a sheet's "Needs you" notification goes with its sheet line - #282

Merged
ymote merged 1 commit into
mainfrom
fix/approval-toast-withdrawn
Oct 2, 2026
Merged

ymote merged 1 commit into
mainfrom
fix/approval-toast-withdrawn

Conversation

@ymote

@ymote ymote commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

A headless instrument run of the desktop shell (main f52620c, scenario S11, frame 35) found a stale approval toast. "Needs you: Calendar · calendar.remove_event … Open the sheet to approve or deny." stayed up after the sheet's Stop had withdrawn the sheet. It pointed at a sheet that was gone. The phone shade's copy of that notification stays until the person clears it.

Cause. Every sheet line posts a "Needs you" notice (Router::surface), which the shell shows as a desktop toast and a phone shade notification (App::notify). Nothing linked that notification to its request, so stopping, answering, withdrawing or expiring the line left it up.

Fix.

  • The router's notice now names the request it asks about (Notice::request). It is set only for the sheet's "Needs you" notice.
  • The shell records where it showed such a notice (approvals::RequestNotices: the toast id and the shade notification id).
  • On every approvals change, the shell withdraws the notifications of each request that no longer waits: stopped, answered on the sheet, withdrawn because its turn ended, or expired. It logs approvals: <id> no longer waits; its notification is withdrawn.
  • Every other notice stays as it was, including the expiry's own "Expired: …" notice.

Tests (Linux build host, from phone/; this branch alone):

  • cargo test --locked --features mobile-apps -p octosense-shell approvals: 59 passed, including the new a_sheets_notification_is_withdrawn_with_its_line. It covers Stop, an answer on the sheet, the turn's own end and the deadline. Each notification is withdrawn once, and the expiry's own notice stands alone.
  • … app_chat: 9 passed. … system_chat: 65 passed. … questions: 9 passed.
  • The two-lane scenario against the real kernel (pinned ae230ce): 5 passed.
  • The whole shell suite as phone.yml runs it (cargo test --locked --features mobile-apps -p octosense-shell, with OCTOS_SHELL_TEST_KERNEL): 776 passed in 2 of 4 runs. The other 2 runs each failed one test, apps::tests::bundled_apps_open_without_catalog_files_or_child_processes.
    • That failure comes from main, not from this branch: the glance_card tile tests register test apps (os.glancetile, os.glancequiet, …) that the catalog test then sees.
    • Run together with those tests, the catalog test fails on main 4f73ab3 as well: 7 of 10 runs on main, 8 of 10 on this branch.
    • This PR does not touch that race.

Instrument (the same harness, on the Linux build host; before = main, after = this branch):

  • Before (main 4f73ab3; the same on f52620c): Stop at log line 4699 (approvals: the person stopped os.calendar's agent (2 turn(s))). The "Needs you" toast (id 3) stayed in the stack until its own lifetime ran out, and frame 35 shows it 2 s after Stop.
  • After (this PR's head, S11): straight after Stop the log reads approvals: hostappr:… no longer waits; its notification is withdrawn. The stack's next layout is notifications: 1 toast(s) 2@…: toast 3 is gone. Only "Mail · Hello" stays, the glance card's toast from S10, which Glance: a card's toast always shows; cards and the panel close #273 now always shows (frame 35).
  • The harness check "no toast at all 3 s after Stop" cannot pass on this main, because of that unrelated card toast (30 s). The log line and the stack layout above are the exact check.
  • Harness note: on this main, System apps: every one has its own agent that can notify #274 gave Photos an agent, so the harness now uses AI providers as its app without one (S2). Its S9 step presses the switch on the third agent row in Settings, which is now Maps's rather than News's, so S9 fails on main and on every branch alike.

Overlap. This branch is on main 4f73ab3, after #272, #273 and #274 merged; the rebase had no conflicts. #273 is the nearest. It changed how toasts stack (notifications.rs, keep_clear_of) and lib.rs glance_notify, a few lines below notify, which this PR splits into notify_shown and withdraw_notification. This PR removes toasts through the existing ShellNotifications::dismiss. The open #230 (Router::withdraw) and #255 (Router::answer) edit other hunks of router.rs; both merge with this branch cleanly. The four fixes from the same run are independent, and each pair merges without conflicts: this one, #279, #280 and #281.

🤖 Generated with Claude Code

Each approval sheet posts a notification, "Needs you: Calendar ·
calendar.remove_event / Calendar's agent asks. Open the sheet to approve
or deny." (a desktop toast, a phone shade notification). It stayed after
the sheet's Stop had withdrawn the sheet (instrument run, S11, frame 35):
the toast until its lifetime ran out, the shade's until the person
cleared it, both pointing at a sheet that was gone. Nothing linked a
notification to its request.

The router's notice now names the request it asks about
(Notice::request, set for the sheet's notice only). The shell records
where it showed such a notice (approvals::RequestNotices) and, on every
approvals change, withdraws the toast and the shade notification of each
request that no longer waits: stopped, answered on the sheet, withdrawn
because its turn ended, or expired. Other notices, the expiry's own
"Expired: …" among them, stay as they were.

Tests: approvals (each way a line leaves its sheet withdraws its
notification once; the expiry notice stands on its own).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ymote
ymote force-pushed the fix/approval-toast-withdrawn branch from 203114c to f6ec4a0 Compare October 2, 2026 18:53
@ymote

ymote commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Local CI passed on f6ec4a0 (tools/ci-local.sh --only all --linux-host, 20m17s, Darwin arm64; the ubuntu jobs on the Linux build host, Linux x86_64).

GitHub would run for this PR: desktop.yml, phone.yml, apps.yml. Merged on this local pass (macOS runner queue); GitHub CI runs on the merge commit on main.

Job Step Result Time
ci-local / drift The local mapping fits the workflows PASS -
desktop.yml / desktop Prepare the pinned framework sources PASS 1s
desktop.yml / desktop Compile the desktop with the shared runtime PASS 2m04s
desktop.yml / desktop One copy of every shell source PASS -
desktop.yml / desktop Desktop tools and scripts PASS 8s
desktop.yml / desktop One Makepad, App Hub, octos and Rinx in the locked graph PASS 4s
desktop.yml / desktop The native apps' generated places match native-apps.json PASS 0s
phone.yml / home Prepare pinned sources and the reviewed runtime patch PASS 0s
phone.yml / home Compile Home and its bundled modules PASS 1m29s
phone.yml / home Verify the single runtime graph PASS 1s
phone.yml / home The native apps' generated places match native-apps.json PASS -
phone.yml / home The pinned octos revision PASS -
phone.yml / home Build octos (unless cached) PASS -
phone.yml / home Build Home, App Hub admission and runtime policy tests PASS 2m43s
phone.yml / home Test Home, App Hub admission and runtime policy PASS 8m33s
phone.yml / home Two-lane scenario (real kernel, scripted model) PASS 58s
apps.yml / services (linux) python3 tools/setup.py PASS 0s
apps.yml / services (linux) Kernel service PASS 10s
apps.yml / services (linux) App peers PASS 23s
apps.yml / services (linux) AI providers config PASS 4s
apps.yml / services (linux) L0 in-card chat (sys.chat, host side) PASS 9s
apps.yml / services (linux) System toolbox (workflow templates) PASS 1m35s
apps.yml / kernel-security (linux) python3 tools/setup.py PASS 1s
apps.yml / kernel-security (linux) The pinned octos revision PASS -
apps.yml / kernel-security (linux) Build octos (unless cached) PASS -
apps.yml / kernel-security (linux) Real-kernel tests PASS 30s
apps.yml / apps python3 tools/setup.py PASS 1s
apps.yml / apps Host services (Mail, AI providers, News) PASS 1m14s
apps.yml / apps Shell AI services (crates/ai-host) PASS 2m02s
apps.yml / apps AppCard runtime setup safeguards PASS 0s
apps.yml / apps AppCard clippy (own crates; shared runtime compiles) PASS 40s
apps.yml / apps AppCard transport and store PASS 13s
apps.yml / apps One Makepad, App Hub, octos and Rinx in the locked graph PASS 6s
rom.yml / product (linux) python3 -m unittest discover -s tests -v SKIPPED (!) -
rom.yml / product (linux) Check generated Agent Binder client SKIPPED (!) -
rom.yml / product (linux) bash -n scripts/stage-forks.sh scripts/publish-release.sh scripts/apply-to-tree.sh scripts/build-rom.sh PASS -
rom.yml / web-installer (linux) npm ci --ignore-scripts --no-audit --no-fund SKIPPED (!) -
rom.yml / web-installer (linux) npm test SKIPPED (!) -
rom.yml / web-installer (linux) npx playwright install --with-deps chromium SKIPPED (!) -
rom.yml / web-installer (linux) npm run test:browser SKIPPED (!) -
rom.yml / web-installer (linux) python3 -m unittest discover -s tests -p test_installer_manifest.py -v SKIPPED (!) -
rom.yml / web-installer (linux) bash -n scripts/release.sh SKIPPED (!) -
linux-host / sandbox (linux) python3 tools/setup.py PASS 0s
linux-host / sandbox (linux) Process sandbox on Linux (Landlock, seccomp) PASS 1m20s

Skipped (these did NOT pass; (!) marks a skip that blocks tools/ci-local-merge.sh):

  • rom.yml / product (linux): python3 -m unittest discover -s tests -v: javac -version does not work here: install a JDK (17 or newer) and put its bin/ on PATH or set JAVA_HOME
  • rom.yml / product (linux): Check generated Agent Binder client: needs build-tools/35.0.0/aidl, platforms/android-35/framework.aidl in the Android SDK (no Android SDK found): install the SDK packages 'build-tools;35.0.0' and 'platforms;android-35' (sdkmanager) and set ANDROID_HOME
  • rom.yml / web-installer (linux): npm ci --ignore-scripts --no-audit --no-fund: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npm test: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npx playwright install --with-deps chromium: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): npm run test:browser: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): python3 -m unittest discover -s tests -p test_installer_manifest.py -v: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH
  • rom.yml / web-installer (linux): bash -n scripts/release.sh: no node, npm, npx on PATH (the workflow uses node 24); put node on PATH

Notes:

  • GitHub runs Python 3.12; this run used Python 3.9.6
  • GitHub runs Python 3.12; the Linux host used Python 3.14.4

@ymote
ymote merged commit c7b0249 into main Oct 2, 2026
5 checks passed
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.

1 participant