Tier 1 already shipped — 9 Google-token routes migrated to getGoogleTokenUserId
+ a cross-surface drift contract test in the guardrails suite. F1 and F2 are closed.
What remains is three subjective UX/product calls — pick one option per section and reply
with e.g. F3-B, F4-B, F5-B. I'll execute one fix per commit, push to prod after each.
getGoogleTokenUserId(session):
gmail/search, calendar (route+today+next), integrations/status,
auth/status, auth/google/revoke, tasks/google-lists,
tasks/google-config, tasks/google-sync. New drift guardrail in
tests/unit/contracts/cross-surface-drift.test.ts blocks the regression in CI.
Audit only flagged 5 of 9 — widened scope before fixing.
War Room HUD modules (priority heat, continuity banner, inbound callout, ambient telemetry) render
illustrative copy in non-demo builds. Source comments at app/(atlas)/voice/page.tsx:28-32
and :57-65 mark them as Phase 1.6.6 work. Risk: during a real debug session you read the
placeholder thought-stream as Shakeeb's actual reasoning. Pick how to make the staged content unambiguous.
Build out the priority-heat / continuity / inbound / telemetry feeds as Phase 1.6.6 originally planned. Removes placeholders by replacing them with truth.
?demo=1 mode.Zero risk, ~30 min. Wraps the placeholder cards in a styled pill that visually demotes them. Real cards stay full-fidelity. War Room shell stays true to the mockup, debug sessions can't be misled by staged copy.
?demo=1.Cards are present in demo mode for screenshot / video; absent in real builds. War Room loses a few modules until 1.6.6 wires them, but the layout shrinks gracefully.
?demo=1 in screenshots → support team sees stripped UI.
Today the Presence rail merges text + voice turns in-memory, but persistence splits them — voice
starts a fresh Voice session — HH:MM conversation row regardless of any active text
conversation (useVoiceSession.ts:80-130). Same in-the-moment thread, two saved
transcripts on /transcripts. Pick the persistence model that matches how you actually use the rail.
Every voice session creates its own Voice session — HH:MM row. Text conversations
stay text. Rail merges them in-memory for the current session; transcripts page shows two threads.
HH:MM) are uninformative.
If you've been typing in the rail and then hold Space, the voice turns append to the same
conversation row. Each turn carries a channel badge (text / voice)
so the transcript reader can show mode shifts. Cold-start voice (no active text) still creates a
Voice session — HH:MM as today.
atlas_messages.channel column + UI badge.Keeps a "session" feeling without forcing every voice burst to inherit a stale text conversation. Same channel-badge mechanic as B; the difference is the join condition.
Today text chat + voice can fire create_task, draft_reply,
extract_commitments, propose_*, sync_google_tasks_now
without a confirmation modal — they're classified as inert writes (no external send). External
Calendar writes already require an approval token. Pick the policy for the inert middle.
Quote from the audit: "User says 'I should probably call Sarah sometime' and the model
over-eagerly creates a task."
Trust the agent on internal mutations. External writes (Calendar create / update / delete) stay token-gated as today. Drafts, tasks, commitments, propose-only writes happen without a modal.
Inert write happens; toast appears bottom-right with the action label and an Undo button. Click within 8s rolls it back. After 8s the toast dismisses. Keeps the trusted-fast path; gives a visible "what just happened" surface; fixes the ghost-task surprise without a modal.
auto_create_tasks, auto_draft_replies, auto_extract_commitments
in Settings. When off, the tool requires a UI confirmation. When on (default), it fires immediately.
Power user gets full control; ghost-task fix requires the user to know to flip the toggle.