MalloryEstate Briefing
M·006Approved
← All briefings

Foundations & UI

Small Wins Batch

Three independent, low-risk deck-clearing items built under one spec: an app-wide a11y contrast fix, per-message deep links so nudge taps land on the exact Slack/Gmail/Calendar item, and a full doc/estate refresh.

Dated 2026-06-19Programme Foundations & UI

Situation

Three roadmap items were small enough to bundle rather than spec separately: a global focus-ring/muted-text contrast failure flagged during Round A, nudges whose native_url field was populated in schema but never filled in (so taps always fell back to a generic https/chat view instead of the exact item), and estate docs that had drifted since 2026-06-15 while a lot of work shipped underneath them.

Build order is deliberate — a11y first, then deep links, then the doc refresh last, so the refreshed design guide can record the final token values and capture both other items plus everything recently shipped.

Key decisions

Per-theme --focus token

Dark theme uses brand gold (~6:1 on --panel/--bg), light theme uses deep oxblood (~7:1) — no single colour cleared 3:1 on both themes.

Bump --muted on dark

Dark --muted moves from #767b8a (~4.15:1, failing) to #8b909f (≥4.5:1 on both --panel and --bg); light-theme --muted is checked and bumped only if it's also under 4.5:1.

Per-source native_url construction

Slack uses the true slack://channel?...&message=<ts> custom scheme; Gmail uses an https://mail.google.com/mail/u/0/#all/<threadId> link that Android App Links route into the Gmail app; Calendar uses the connector's own htmlLink (simpler than hand-computing a base64 eid, discovered during planning) with an empty-string fallback so a missing id never emits a malformed scheme.

New SLACK_TEAM_ID config key

The workspace's T… team id (not derivable from the mathscircle subdomain or the Slack MCP) is added to config.env; an empty value falls back to the existing https permalink rather than breaking the scheme.

Docs stay self-contained, vault is a snapshot

docs/estate/* remains the single canonical source; the vault copy is re-synced after the PR merges to avoid three-way drift, and a new root AGENTS.md points coding agents (including the Q dev-driver) at it.

Risks & guardrails

Keyboard-only focus ring

The --focus swap stays scoped to :focus-visible, so pointer taps are unaffected — only keyboard navigation shows the ring.

Never a malformed deep-link scheme

Every native_url path (Slack team id, Gmail thread id, Calendar htmlLink) falls back to an empty string / existing https permalink when the source id is missing or odd, verified by offline jq/shell tests.

Deploys held for Alex

The a11y fix is a web deploy, the deep-link work is a Tower pull — both are review-then-deploy, not auto-shipped.

Delivery

Phase 1 — a11y pass

--focus token + --muted bump in web/src/app.css, verified by npm run check plus a recorded contrast computation.

Phase 2 — deep links

Slack/Gmail native_url in mention.jq, calendar-sync wired to pass team + native_url, Calendar native_url via the connector's htmlLink, new SLACK_TEAM_ID config key.

Phase 3 — doc refresh + grounding

Reconcile estate docs + ROADMAP, add design-guide examples + token values, new AGENTS.md, Hermes memory note + vault snapshot (Tower, after the PR merges).

Out of scope

Eval battery and model eval (depends on the battery) — separate brainstorm tracksweb-admin-for-OAuth (overlaps parked Round 1 token-hardening)The parked Round 1/2 security & architecture work
spec · docs/superpowers/specs/2026-06-19-small-wins-batch-design.md
plan · docs/superpowers/plans/2026-06-19-small-wins-batch.md
Mallory · Estate briefing