Skip to content

feat(ui): consent modal + boot UX fixes (hotfix)#50

Merged
dgokeeffe merged 2 commits into
mainfrom
feat/consent-modal
May 18, 2026
Merged

feat(ui): consent modal + boot UX fixes (hotfix)#50
dgokeeffe merged 2 commits into
mainfrom
feat/consent-modal

Conversation

@dgokeeffe
Copy link
Copy Markdown
Collaborator

Summary

First-run consent modal so users acknowledge CoDA's trust model before booting, plus two UX fixes for the boot screen that made CoDA look broken on first use. Visually verified on live daveok deployment before push.

Commits

1. `feat(ui): first-run consent modal for risk acceptance` (`24cec95`)

Adds a first-load risk-acknowledgement dialog that blocks the rest of `init()` until the user clicks "I understand and accept". Persists acceptance in `localStorage` under `coda:risks-accepted-v1` so returning users see it once.

The modal is deliberately framed around user authority and accountability — not system weaknesses. It does NOT name specific endpoints, describe exploitable conditions, or telegraph anything an attacker reading the disclaimer could use. Risks enumerated:

  1. Full workspace authority (commands + agents run with your creds)
  2. AI agents take real actions (Claude/Codex/OpenCode/Gemini/Hermes)
  3. Actions are irreversible (no staging/undo)
  4. You are accountable (audit log under your identity)
  5. Single-user app (don't share URL/screen/session)
  6. You are responsible for what you run

Plus a fine-print line linking the LICENSE + project-support notes, with the `CODA_TELEMETRY_DISABLED` opt-out hint.

Bump the `-v1` key suffix to re-prompt all users when the modal copy materially changes (new agent, new risk disclosure, new policy).

2. `fix(ui): hide loading indicator + live progress on PAT bootstrap` (`90ffbe6`)

  • Top-left overlap fix: `#status` (position: absolute, z-index 1000) stayed visible during the entire PAT prompt because `createTab()` blocks awaiting user input. "Initializing terminal…" overlapped the tab bar. Now hidden before `createTab()` runs; catch block re-shows it on error.

  • Live boot progress: token validation + 30–60s CLI install previously showed two static lines and looked dead. Replaced with a braille spinner (`⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏`) animating at 10fps, rewriting in place via `\\r\\x1b[K`. The spinner label updates each poll cycle to show the currently-running step + completion count (e.g. `Configuring Claude CLI (3/12)`) so the user sees real motion AND knows what's happening.

DRY'd the two duplicated setup-polling blocks (PAT bootstrap path + already-configured-on-load path) into a single `waitForSetup()` helper. Net: +64 / -38 lines.

Verification

  • 231/231 unit tests pass (frontend-only change, no Python regression)
  • Live visual verification on daveok deployment:
    • Consent modal appears in incognito session, dismisses on accept, persists across refreshes
    • Top-left overlap gone
    • Spinner animates during token validation + setup polling

Why this merge cadence

Same "PR → self-merge" pattern as #42 (configure-pat hotfix) — the boot-screen UX issues make CoDA look broken on first use, which is high-impact for any user opening the app for the first time. The consent modal is also a legal-coverage layer that's load-bearing for the broader trust model.

Sathish, requesting post-hoc review on the modal copy + spinner UX — flag anything you'd phrase differently.

Test plan

  • 231/231 unit tests pass
  • Visual verification on daveok (consent modal, overlap fix, spinner)
  • Sathish post-hoc review

This pull request and its description were written by Isaac.

dgokeeffe added 2 commits May 17, 2026 21:13
Adds a first-load risk-acknowledgement dialog that blocks the rest of
init() until the user clicks "I understand and accept". Persists
acceptance in localStorage under 'coda:risks-accepted-v1' so returning
users see it once.

The modal focuses on user authority and accountability — not system
weaknesses. By design it does NOT name specific endpoints, describe
exploitable conditions, or telegraph anything an attacker reading the
disclaimer could use. The risk-acceptance layer is for informed consent
about the trust model, not a vuln advisory. Specific risks enumerated:

  1. Full workspace authority (commands + agents run with your creds)
  2. AI agents take real actions (Claude/Codex/OpenCode/Gemini/Hermes
     can read, write, delete on your behalf)
  3. Actions are irreversible (no staging/undo)
  4. You are accountable (audit log under your identity)
  5. Single-user app (don't share URL/screen/session)
  6. You are responsible for what you run

Plus a fine-print line linking the LICENSE + project-support notes, and
the CODA_TELEMETRY_DISABLED opt-out hint.

Bump the '-v1' key suffix to re-prompt all users when the modal copy
materially changes (new agent, new risk disclosure, new policy).

Implementation:
- `<dialog>`-style overlay (`#consent-overlay`) inserted just after
  `<body>`, hidden by default, shown via `.visible` class.
- Matches existing `#shortcuts-overlay` styling conventions
  (border-radius, backdrop-filter, ARIA dialog role).
- `ensureConsent()` gates `init()` BEFORE any network call —
  no `/api/version` ping, no setup-status poll, no PAT prompt until
  the button is clicked. Resolves immediately on subsequent loads.
- `acceptBtn.focus()` for keyboard accessibility; one interactive
  element so no focus trap needed.

Co-authored-by: Isaac
Two UX fixes for the boot screen that made CoDA look broken on first use:

1. **Top-left overlap.** The #status element (position: absolute;
   top: 10px; left: 10px; z-index: 1000) stayed visible during the
   entire PAT prompt — createTab() blocks awaiting user input, so
   "Initializing terminal..." remained on screen overlapping the tab
   bar. Now hidden before createTab() runs; the catch block re-shows
   it on error so failures stay visible.

2. **Silent setup polling.** Token validation + 30–60s CLI install
   showed two static lines and then nothing. Replaced with a braille
   spinner that animates at 10fps and rewrites in place via \r\x1b[K.
   The spinner label updates each poll cycle to show the currently-
   running setup step + completion count (e.g. "Configuring Claude
   CLI (3/12)"), so the user sees real motion AND knows what's
   actually happening.

Also DRY'd the two identical setup-polling blocks (PAT-bootstrap
path + already-configured-on-load path) into a single waitForSetup()
helper. Net: +64 / -38 lines, less duplication.

Co-authored-by: Isaac
@dgokeeffe dgokeeffe merged commit 4950f0f into main May 18, 2026
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