UX foundation: DESIGN.md v2 + W1 (fonts + widgets.rs + slop kill) - #120
Merged
Conversation
Re-grounds the visual language (editorial: type + whitespace + hairlines, no card-default; oversized mono hero; cockpit row layout) and makes the foundation enforceable so agents stop drifting: - Enforcement model: bundle the fonts (they were never embedded, the app ran in the OS system font), one shared widgets.rs vocabulary, a visual definition-of-done checklist. - Confirm pattern: cmd+enter key-cap (no hold-to-confirm) + arm-delay, tiered by risk. - Clear-signing redesigned transaction-as-hero. - Agent interaction model: agents first-class standalone in the sidebar, a dedicated agent surface owning editable policy + controls + activity, a compact agent presence on the home, the data-driven expandability contract (agent = policy + activity). - Activity lean scope (audit log + STOP) with triage/keyboard/drill-in documented for later. Grounded in an 8-agent source audit + golden-reference HTML (deckard-editorial-v3 / deckard-agent-v4).
Make the foundation real and consistent (DESIGN.md v2 §Enforcement). Fonts (the C1 fix): embed General Sans + JetBrains Mono in assets/fonts/ and uncomment add_fonts in main.rs. The app rendered in the OS system font before this; now it uses Deckard's real type (mono-for-money + weight hierarchy actually apply). Verified live on the onboarding screen. widgets.rs (the shared vocabulary): short_addr (one first-6+last-4 rule), caution_line / error_line (one Lucide-icon caution language, kills the `⚠` emoji), section_label (one tracked-label treatment), identity_mark (monogram, never a blank square). Routed all views through it, deleting the 3-4 divergent copies of each helper that were the root cause of drift. Slop kill: removed the on-canvas keyboard-hint chip row; caution boxes -> inline icon+text lines; raw provider error -> humanize_read_error; orphan `—` hero placeholder -> "Syncing…"; em-dash sweep in UI copy; "Welcome to Deckard" -> the product promise; honest settings copy (dead display_name, dropped tray-feature leak); "broadcast" -> "sent"; stale GPUI-starter doc comment. DoD: cargo fmt --all --check clean; just check green (default + tray); cargo test -p deckard-app -p deckard-core green (53 + 55); no new deps.
Apply the editorial language (DESIGN.md v2: type + whitespace + hairlines, no card-default; oversized mono hero; cockpit rows). Verified live on the wallet home (10,000 ETH hero, monograms, Shield-primary action row, de-carded agent section, de-jargoned captions, in the bundled fonts). - widgets.rs: add budget_gauge (4px threshold gauge, neutral->amber>=90->red>=100) and truncated_address (identicon + ENS + short_addr). - welcome.rs: oversized balance hero (64px mono); agent fence DE-CARDED to a frameless section + budget_gauge under the spent/daily rows; action row = Shield primary + divider + Send/Receive/Swap ghost cluster; section_label for Holdings + the fence header. - activity_view.rs: editorial dense rows, per-row hairlines (not card boxes), left cluster min_w_0 + truncate so nothing overflows the pane (the historical horizontal-overflow bug), amber NEEDS YOU band, section_label day bands. - commit_view.rs: transaction-as-hero review (amount as the big mono hero, recipient via truncated_address, quiet supporting facts), hold_to_confirm wiring preserved (the cmd+enter swap is a focused follow-up). - swap_view.rs: editorial compose (sell/receive large mono + asset chips + quote/route strip) + transaction-as-hero review; fixed a borrow-across-mut-cx. DoD: cargo fmt --all --check clean; just check green (default + tray); cargo test -p deckard-app -p deckard-core green (53 + 55); no new deps.
…ibsted Grotesk (#116) Make the agent first-class (DESIGN.md v2 §The agent interaction model). Verified live: sidebar AGENTS group + Atlas, the agent surface (Personal › Atlas), in the bundled font. Agent model: - New Selection::Agent + (Selection::Agent, Surface::Home) dispatch + a standalone sidebar AGENTS group (Atlas: cyan squircle + name + status dot) that select()s the agent and kicks the live policy. - New agent_view.rs render_agent_surface: identity + acting status + Revoke & STOP (the existing two-step brake) + a plain-language autonomy statement (cap derived from policy) + LIMITS (the live policy rows) + budget_gauge + controls (Pause / Rotate / Adjust shown disabled until wired; honest, not no-ops) — built entirely from agent_policy (the expandability contract). - welcome.rs: the home's full policy fence -> a COMPACT agent presence row (squircle + Atlas + status + thin budget_gauge + chevron) that links to the surface. Deleted render_agent_fence; agent_policy_rows + fraction are now pub(crate) and reused by the surface. - palette.rs + shell_chrome breadcrumb: Selection::Agent arms ('Atlas'). Font: swap the UI face General Sans -> Schibsted Grotesk (OFL-1.1, ships in a public repo); JetBrains Mono unchanged. theme.rs + main.rs + assets + DESIGN.md. Scope: the ⌘↵ confirm interaction + onboarding split are the next wave. DoD: cargo fmt --all --check clean; just check green (default + tray); cargo test -p deckard-app -p deckard-core green (53 + 55); no new deps.
The hold-to-confirm gesture was an anti-pattern (user feedback). Replace it with a keyboard-first key-cap confirm (DESIGN.md v2 §The confirm pattern): a deliberate click — or ⌘↵ — confirms, never a press-and-hold. - commit_view hold_to_confirm now renders a key-cap button (label + ⌘↵), not the amber hold-sweep. Its click routes to the existing confirm handlers. - A COMMIT_ARM_DELAY (450ms): the confirm is gated until the review has been on screen long enough, so a keypress/click carried over from compose can't approve (commit_review_at set on proposal install; commit_armed() checks it). - ⌘↵ is a ConfirmCommit action scoped to a key context on the focused Send/Shield/Swap review (focused only on the review step, so compose inputs still type). It never shadows Activity's own ⌘⏎ approve. - The signing handlers (confirm_send/shield/swap) are UNTOUCHED — only the trigger changed. Removed the dead hold machinery (begin_hold, hold_still_valid, the *_hold_start timers + *_hold_cancel handlers/adapters, the hold-label/fill-id descriptor fields, SHIELD_HOLD). Verified LIVE on the qa fork: composed a 0.01 ETH send, the review shows the 'Send ⌘↵' key-cap button, a click signed + broadcast it (Transfer sent, tx 0xb8ab…4a29, balance 10,000 -> 9,999.9899, block mined). (Synthetic ⌘↵ keys don't register with this GPUI app, same as synthetic Enter on unlock; the keybinding is wired for a real keyboard, the click path is the proof.) Known follow-ups (for code-review): the now-vestigial CommitFlow hold fields (holding/hold_epoch/cancel_hold + the open() leave-guards) and a couple stale 'hold-to-confirm' doc comments. DoD: cargo fmt --all --check clean; just check green (default + tray); cargo test -p deckard-app -p deckard-core green (52 + 55); no new deps.
DESIGN.md v2 Required states: amount > balance disables the action with an inline error, never a late raw provider string. can_review now gates on the parsed amount <= the wallet's native balance (self.portfolio.native_wei); an over-balance amount shows 'More than your wallet holds.' under the input and keeps Review disabled. Covers Send and Shield (both spend native ETH); a None balance (pre-sync) leaves the gate open. DoD: fmt clean, just check green both configs, tests green, no new deps. Remaining for /code-review: humanize_deny noun (send still says 'deposit'), the vestigial CommitFlow hold state, the onboarding backup/verify split + a strength meter, and a couple stale hold-to-confirm doc comments.
The high-effort review of the foundation PR caught real bugs; fixed:
- Arm-delay silent dead-zone: a click within 450ms of a review no-opped with
no feedback (nothing re-rendered at the boundary). New arm_commit() stamps
the time AND schedules a re-render at the 450ms mark; the key-cap is dimmed
(muted) while arming and brightens (amber) when live, so an early press reads
as 'not ready yet' instead of a dead button.
- Arm gate fail-open: commit_review_at was never cleared. open() now clears it
on every nav and re-arms (fresh delay) only when landing on a review that
already has a proposal, so a stale-but-elapsed timestamp can never fire.
- Duplicate STOP on the agent surface: the footer 'Revoke' shared the header
STOP's arming flag but its label wasn't state-aware, so a double-click could
fire the irreversible key-zeroize with no visible confirm. Removed it; the
header 'Revoke & STOP' is the one two-step brake.
- Stale policy on back-nav: on_go_back re-kicked the live policy only for
Selection::Wallet; now also for Selection::Agent (the agent surface shows the
same STOP-brake / budget fence).
- Recipient address on the Send/Shield confirm was the dimmest text (muted) and
6+4-truncated. It is the moment-of-authorization string: now the FULL address
in fg (wraps for a long 0zk), with the identicon.
- Honesty severity was substring-sniffed ('lost'/'can't be undone'); a reword
could silently downgrade a danger line. Now an explicit HonestyLine.danger.
- Softened the over-balance gate comment: the daemon's gas-aware check is the
backstop for the gas-leaves-nothing edge (no up-front gas estimate here).
DoD: fmt clean, just check green (default + tray), tests 52 + 55, no new deps.
…y screen Rework the create flow into the DESIGN.md §Onboarding stepped shape: - Secure: a live passphrase strength meter (length-dominant, dictionary-free so no new dep), an amber "if you forget it, no one can reset it" consequence, and the Argon2id/XChaCha20 algorithm names demoted to a muted line. - Back up: now reveal-only — hold-to-reveal grid + a "nobody can see your screen" caution + a demoted explicit-only Copy; the reveal auto-hides after 10s (epoch-guarded against stale timers). - Verify (new, separate step): the grid is hidden, confirm by position, and the primary stays disabled until the typed words match. backup_words_match is the single fail-closed predicate the button and the submit share. - Ready (new): a real "you're ready" interstitial showing the new address; finish_unlock is deferred to the explicit "Enter Deckard" click. Secret-lifecycle hardening (from an adversarial review of this change): - create_epoch guards the async Vault::create — a KDF that lands after the user backed out drops its freshly-derived secrets instead of staging them. - abandon_create() (Back / Import) invalidates the in-flight KDF, clears the busy flag, and wipes any staged phrase/pass/vault. - confirm_backup keeps the pending secrets on a write error on purpose (retry needs the same phrase); cleared on success, bounded by Zeroizing on exit. 6 new passphrase_strength unit tests. fmt + clippy (both configs) + workspace tests green.
Code-review (5 finder angles + verify) of the W4b change surfaced secret-hygiene and consistency gaps; verified-clean fixes: - Wipe the verify field (confirm_words) on leaving the verify step. It holds 3 real seed words the user typed, and InputState isn't Zeroizing — they no longer linger in memory after success/Back. - Disable the Verify "Back" button during the seal/unlock write, closing the "navigate away mid-flight then get force-jumped when the result lands" race. - Wrap BOTH passphrase reads in Zeroizing in do_create — the confirm-field copy (p2) was a bare String left un-zeroized in freed heap. - start_create() now calls abandon_create() (epoch bump + busy clear + secret wipe) instead of a bare epoch bump, so it's self-sufficient, not caller-reliant. - back_to_backup() bumps reveal_epoch, symmetric with advance_to_verify. Cleanup / design conformance: - Ready screen uses widgets::truncated_address (the canonical identicon + mono short address) instead of a hand-rolled copy (DESIGN §Trust). - passphrase_strength returns a PassBand enum that owns both the word and the colour, so the meter's label and bar colour share one set of cut-points and can't drift. Unit tests updated to assert bands. fmt + clippy (both configs) + workspace tests green; the fix delta re-reviewed clean (0 findings).
…iner Per design feedback: - Welcome headline: "Deckard, your new favorite wallet." (drop the "money on autopilot" framing). - Trim implementation/feature descriptions across the auth screens — remove the "Encrypted at rest with Argon2id + XChaCha20-Poly1305." line, the "encrypted / decrypt on this device" clauses, and the "length matters more than symbols" tip. - Keep the "Open source · AGPL-3.0 · no telemetry" subline on the first screen only. - De-em-dash every user-facing string (matches the W1 em-dash sweep).
…ocked type scale
From /design-review (cross-model: codex + screenshot audit) of the onboarding flow:
- Back up screen: demote Copy to a centered ghost action BELOW the full-width
"Hold to reveal" row, per DESIGN.md §Seed reveal ("Copy demoted below reveal").
It was sitting beside reveal in an h_flex.
- auth_heading: use the locked DESIGN §Typography scale — H1 22px/600 and
subtitle 13px/400, not gpui's text_2xl (24) / text_sm (14), which ran large.
Verified live (before/after screenshots). fmt + clippy (both configs) + tests green.
…s, steady meter From the scope clarification on this PR: - Step progress rail: "Secure · Back up · Verify · Ready" above the four create steps, active step in amber, the rest muted (labels only, no chrome). The user always knows where they are in the flow. - Ready screen: the new wallet address is now one-click copy with inline "Copied ✓" (DESIGN §Trust: every address is copyable). - Reserve the strength-meter's height so nothing below shifts when it appears on the first keystroke. - Remove the "Touch ID … (Phase 2)" note (roadmap language in production auth UI). All verified live (rail active-step on each screen, no meter shift, copy → Copied ✓ with the full address on the clipboard). fmt + clippy (both configs) + tests green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The first landable chunk of the UX foundation overhaul (epic #117).
DESIGN.md v2 — the enforceable foundation (a92fb0f)
Re-grounds the visual language as editorial (type + whitespace + hairlines, no card-default; oversized mono hero; cockpit rows) and makes it enforceable: bundled fonts, a shared
widgets.rsvocabulary, the⌘↵key-cap confirm spec (no hold), transaction-as-hero clear-signing, the agent interaction model (first-class standalone agents + a dedicated agent surface + compact home presence + the data-driven expandability contract), the lean Activity scope, and a visual definition-of-done checklist. Decisions log records every call.Golden references:
deckard-editorial-v3.html+deckard-agent-v4.html(in~/.gstack/projects/hellno-deckard/designs/).W1 implementation — Closes #114
add_fonts). The app rendered in the OS system font before this; verified live that it now renders in General Sans on the onboarding screen.widgets.rs: one shared vocabulary (short_addr6+4,caution_line/error_line,section_label,identity_mark) replacing the 3-4 divergent per-file copies that were the root cause of drift.humanize_read_error; orphan—→ "Syncing…"; em-dash sweep; "Welcome to Deckard" → the promise; honest settings copy; "broadcast" → "sent"; stale starter doc comment.Verification
cargo fmt --all --checkcleanjust checkgreen on both default and--features traycargo test -p deckard-app -p deckard-coregreen (53 + 55 pass)Follow-up: wallet-home screenshot (monograms + no hint chips + mono money) needs the qa-vault unlock path; capturing next. W2 (editorial layout) #115 and W3 (agent surface + swap + onboarding) #116 build on this.