Skip to content

feat(widgets): v4 request-origin primitives (E1 · #181) - #189

Merged
hellno merged 1 commit into
mainfrom
hellno/v4-widget-foundation
Jul 3, 2026
Merged

feat(widgets): v4 request-origin primitives (E1 · #181)#189
hellno merged 1 commit into
mainfrom
hellno/v4-widget-foundation

Conversation

@hellno

@hellno hellno commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Implements E1 · v4 widget foundation of the v4 request-origin epic. Adds the v4 widgets.rs
vocabulary + supporting tokens.rs so no later view (E2–E7) hand-rolls a primitive — the epic's
Implementer Contract rule "reuse, never hand-roll."

Closes #181. Refs #179. Golden ref: designs/deckard-v4.html; spec: docs/research/13-v4-build-plan.md (E1).

What's added (widgets.rs)

The v4 request-origin primitives the issue names, plus the DESIGN-referenced-but-missing ones:

primitive what it is
key_cap(cap, armed, …) Platform-aware key-cap chip — on macOS, Ctrl elsewhere via std::env::consts::OS; the ⌘↵ chord renders as one cap; armed = amber border + amber text, no fill
origin_header(origin, trust, theme) the request-origin rail: You (round mark, amber "You are …"), Agent (cyan squircle + handle), Dapp (neutral favicon + domain); optional state-color trust badge. A dapp is a NEUTRAL identity + a state-color badge — never a third signal color
action_tag(kind, …) the SWAP/SHIELD/SEND/SUPPLY uppercase chip (neutral, not a signal color)
status_glyph(state, theme) one status vocabulary — success check / danger x / amber+cyan loader ring (pending/live) / muted minus
kv_row · page_header · meta_rail/meta_section/meta_obj · balance_diff · stop_brake the DESIGN-referenced primitives the v4 views need (metadata rail scaffold, ± "what changes" rows, the STOP brake, the one page-header anatomy)
agent_mark handle-aware bordered cyan squircle (added during review — see below)

tokens.rs gains the object-size ladder (MARK_MD/MARK_LG), ICON_MD, ALPHA_TINT, and
RAIL_W, each landing with its first consumer here (an unused pub const is a build error).

Contract compliance

  • Colors via theme.* + theme::amber/agent only — no raw hex.
  • Sizes/spacing/radii via the tokens module + gpui utilities — no magic px() that duplicates a named token.
  • Money via money.rs (balance_diff renders each signed amount through money::money).
  • Reuses identity_mark / section_label / divider; a shared monogram() helper backs identity_mark + agent_mark.
  • Two signal colors only (amber = human, cyan = agent); a dapp/state is neutral identity + a state-color badge.
  • Atomic primitives take explicit Hsla (pure, unit-tested); composite ones take &Theme (the convention DESIGN §Build notes sanctions).

A note on "consumed by ≥1 view" vs "widgets.rs + tokens.rs only"

The AC asks each primitive be consumed by a view, but E1 is scoped to widgets.rs+tokens.rs and
must not touch the E2–E7 views that consume these. I resolved this the way the codebase already
does (money::usd): every primitive carries a scoped #[allow(dead_code)] + a // reason: naming
its consuming child, and the pure logic is unit-tested. Each E2–E7 PR drops the allow as it wires the
real call site. No view file was edited.

Adversarial review

Ran a multi-dimension review (fidelity / DESIGN-tokens / reuse / correctness / scope) + a codex
cross-model pass, then verified each finding. 2 real findings, both fixed in this branch:

  1. (medium, fidelity) the agent origin mark was borderless — dropped the cyan border that defines
    the squircle. Fixed by adding agent_mark: a handle-aware bordered cyan squircle (matches the
    golden .squircle; shows K for Kyoto, not a fixed A).
  2. (low, corroborated by codex) the amber "New site" trust badge tinted at .12 instead of the
    amber-only .14 (alpha-tint-warm). Fixed to use theme::amber_tint.

Definition of Done

  • cargo fmt --all --check — clean
  • just check — green (workspace + --features tray + signerd dev-signerd-bin, all -D warnings)
  • cargo test --workspace — green; 4 new widget unit tests incl. key_cap asserting Ctrl on a forced-Linux path and on macOS
  • No new/changed deps (Cargo.toml/Cargo.lock untouched)

Screenshots

None — E1 is the widget layer, not a view (the issue's golden-ref fidelity note: "No view / see AC").
Nothing is wired into a running screen yet; the primitives become visually demoable as E2–E7 consume them.

Do not touch (honored)

No view files (send/shield/swap/activity/settings/commit/transaction) touched — diff is widgets.rs + tokens.rs only.

Add the v4-added `widgets.rs` vocabulary so no later view hand-rolls it, per
the Implementer Contract in epic #179 ("reuse, never hand-roll"):

- `key_cap(cap, armed, …)` — PLATFORM-AWARE (`⌘` on macOS, `Ctrl` elsewhere via
  `std::env::consts::OS`), the `⌘↵` chord as ONE cap; armed = amber border+text,
  no fill. Pure `primary_mod_label`/`key_cap_label` helpers are unit-tested.
- `origin_header(origin, trust, theme)` — the request-origin rail: You (round
  mark, amber), Agent (cyan mark + handle), Dapp (neutral favicon + domain), each
  with an optional state-color trust badge. A dapp is a NEUTRAL identity + a
  state-color badge, never a third signal color.
- `action_tag(kind, …)` — the SWAP/SHIELD/SEND/SUPPLY uppercase chip.
- `status_glyph(state, theme)` — one status vocabulary (success check / danger x /
  amber+cyan loader ring for pending+live / muted minus). No `clock` icon ships →
  the ring carries pending; color separates awaiting-you (amber) from agent (cyan).
- `kv_row`, `page_header`, `meta_rail`/`meta_section`/`meta_obj`, `balance_diff`,
  `stop_brake` — the DESIGN-referenced primitives the v4 views need.

tokens.rs gains the object-size ladder (`MARK_MD`/`MARK_LG`), `ICON_MD`,
`ALPHA_TINT`, and `RAIL_W`, each with its first consumer here.

Composite widgets take `theme: &Theme` and resolve colors internally (the
convention DESIGN §Build notes sanctions); atomic ones take explicit `Hsla` and
stay pure/testable. Colors via `theme.*` + `theme::amber/agent` only (no raw hex);
sizes via the tokens module; money via `money.rs`; reuses `identity_mark` /
`section_label` / `divider`.

E1 is scoped to `widgets.rs` + `tokens.rs` and must not touch the E2–E7 views that
consume these, so each primitive carries a scoped `#[allow(dead_code)]` + a
`// reason:` naming its consuming child (the `money::usd` precedent); E2–E7 drop
the allow as they wire the real call site.

DoD: `cargo fmt --all --check` clean; `just check` green (both feature configs);
`cargo test --workspace` green (4 new widget unit tests). No dep changes.

Refs #179. Closes #181.
@hellno
hellno merged commit 42ab414 into main Jul 3, 2026
5 checks passed
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.

E1 · v4 widget foundation

1 participant