fix(ui-12b): push modal surfaces karasu watch inline (VAPID-null)#123
Conversation
Closes phase-4-dogfood Finding #3 sub-friction 3 (logged in PR #118's resolution): the UI-12b push modal's VAPID-null foot copy used to read "VAPID keys not provisioned. See docs/local-dogfood.md for manual setup." That works at a terminal but FAILS in the operator's standalone PWA window (installed via UI-14) where there is no terminal handy, no clickable doc link, and the chip text is the operator's only context. Fix: replace the doc-pointer with the runnable CLI command inline. New foot copy reads "VAPID keys not provisioned. Run `karasu watch` in a terminal once to bootstrap." The command goes IN the chip so the operator can copy + paste it directly without leaving the window. The watcher's auto-provisioning discipline (UI-12c §3-G + local-dogfood §First-start) is unchanged; only the in-PWA hint shape moves. Pin §11.6.14 carry-forward: the primary button stays DISABLED in the VAPID-null state, so this change only touches the foot copy. The defensive setPushModalError('VAPID keys not provisioned.') guard later in the file (line 250) is untouched — it covers a separate race-against-stale-payload path and should stay terse. Brief §3-H amended in-place to seal the new operator-actionable copy and document the regression risk. Tests: - tests/test_ui_sw.py::test_push_modal_vapid_null_foot_copy_surfaces_cli_hint — parses push.js and asserts the inline `karasu watch` hint is present, plus a guard that the old "See docs/local-dogfood.md" pointer was not reintroduced. Test surfaces touched: 18/18 in test_ui_sw.py, 13/13 across test_ui_push_modal + test_ui_modal. No code paths exercised by the Playwright modal flows changed shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 326b63e3e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| footCopy.textContent = | ||
| 'VAPID keys not provisioned. See docs/local-dogfood.md ' + | ||
| 'for manual setup.'; | ||
| 'VAPID keys not provisioned. Run `karasu watch` in a ' + |
There was a problem hiding this comment.
Make the CLI hint pasteable as shell input
When the modal is shown in the VAPID-null state, the visible text now includes literal backticks around karasu watch. If an operator follows the new copy/paste workflow and pastes that visible command including the backticks into a POSIX shell, the shell treats it as command substitution rather than running karasu watch normally, which can hang or fail instead of bootstrapping VAPID. Since this change is specifically meant to make the modal copy actionable, render the pasteable command without shell metacharacters or style it separately while keeping the copied text as karasu watch.
Useful? React with 👍 / 👎.
Reconciles the cross-PR references that the individual fix PRs could not touch because they branched off main while the hygiene items only existed in PR #116's resolution block. Updates: - Hygiene #5(a) (login chip text per status) marked resolved by PR #122. - Hygiene #5(b) (`!unknown:` sentinel for direct loopback) marked resolved by PR #121. - Finding #3 sub-friction 3 (modal does not surface CLI command) marked resolved by PR #123. The "Outstanding sprint items" section is rewritten as "Sprint items closed 2026-05-16" — an audit trail of the five items addressed in one session, each linked to its landing PR. Adjacent housekeeping (the Karasu- → Karasu rename + PR #120 reference cleanup) is also captured for the historical record. Final line marks path C VPS deploy as unblocked at the code surface; remaining gate is operational (domain + VPS + caddy/Let's Encrypt per docs/deploy-runbook.md). Pure docs change — no code, no tests, no brief touched. Co-authored-by: Victor Del Puerto <VDP89@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
karasu watch) inline instead of pointing at a doc.Fix
src/karasu/ui/static/js/push.jsline 193-195:Before:
After:
Invariants preserved
Notification.requestPermissionandPushManager.subscriberemain unreachable from VAPID-null.setPushModalError('VAPID keys not provisioned.')guard at push.js:250 (race-against-stale-payload path) is untouched and stays terse.Files
src/karasu/ui/static/js/push.js— foot copy + extended comment linking the change to the dogfood finding.tests/test_ui_sw.py::test_push_modal_vapid_null_foot_copy_surfaces_cli_hint— new static text pin in the existing "UI artefact source-level checks" pattern. Asserts the inlinekarasu watchhint is present + guards against reintroducing the old doc pointer.docs/ui/ui-12b-design-brief.md— §3-H amended in-place to seal the new operator-actionable copy and document the regression risk.What's NOT in this PR
Test plan
pytest tests/test_ui_sw.py— 18/18pytest tests/test_ui_push_modal.py tests/test_ui_modal.py— 13/13 (no flow regression)karasu uiwithoutkarasu watchand opening the push modal from the standalone PWA window should see thekarasu watchhint inline and be able to copy it without switching to a browser tab.Relation to other Phase 4 PRs
Independent of #116-#122. The new test only reads push.js source; no other surface touched.
🤖 Generated with Claude Code