feat(registers): speaker-register token layer (--cp-*), lint rules, Presence voice register - #64
Conversation
…oice register Implements AMENDMENT-REGISTERS-AND-MOBILE-RECONCILIATION dispatch slice 1 (section 2.5): the cross-platform --cp-* speaker vocabulary, plus the section 2.4 Presence mark ruling and the section 5.1 census errata. - console register-bridge.css: --cp-human (oxblood, AA on chrome), --cp-agent (teal, AA and held hue-distant from the Int UI accent blue: 80.7 deg in oklch), --cp-memory (--ij-gold), --cp-destructive (reserved red), the typography trinity font tokens, and the Presence mark tokens; Tailwind @theme inline aliases so text-cp-* and font-cp-* resolve. - typography trinity (2.3): human rides Vollkorn and machine rides JetBrains Mono through the bridged Galley faces; the agent voice self-hosts IBM Plex Sans (fonts.ts, next/font/google) because Galley ships no @font-face and gy-bridge re-points --gy-font-ui at the chrome Inter. Verified in the running app: the three faces resolve distinct (serif / sans / mono). - register lint: the two spec rules (raw color functions fail outside register files; human ink on a destructive variant fails), both verified firing. - contrast gate: human, agent, and destructive receipts on chrome and editor. - PresenceMark: base voice teal, commit brightness lift, oxblood interrupt edge; gold removed from the mark (gold marks memory, not the mark). - mobile tokens.ts: additive speaker export mirroring the roles with computed contrast receipts. - census: PR 25 split from lane C to a C + F row (mobile foundation carried). Gates: fence, register, contrast, motion clean; console tsc and next build green; speaker tokens verified resolving in the running console. Playwright visual baseline for the mark needs regeneration in CI (the teal repaint is a spec ruling, not a downgrade).
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
📝 WalkthroughWalkthroughThis change adds speaker color and font registers across console and mobile themes, updates presence rendering to use presence tokens, expands contrast and register lint checks, and revises the console planning ledger. ChangesSpeaker register implementation
Planning ledger update
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant ThemeTokens
participant RegisterBridge
participant PresenceMark
ThemeTokens->>RegisterBridge: define speaker and presence tokens
RegisterBridge->>PresenceMark: provide resolved CSS variables
PresenceMark->>PresenceMark: render state-specific presence colors
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Implements the “speaker register” foundation for Console and Mobile by introducing cross-platform --cp-* tokens (and Tailwind utilities), updating the Presence mark to use the new voice/presence tokens, and extending CI-style gates (register lint + contrast) to cover the new register roles.
Changes:
- Add
--cp-*speaker/presence/font tokens in the Console register bridge, emitting Tailwindtext-cp-*/font-cp-*utilities. - Update
PresenceMarkto render with--cp-presence*tokens (teal base, teal brightness-lift on commit, oxblood on interrupt) and add IBM Plex Sans vianext/font/google. - Extend console “register lint” to forbid raw color functions outside register files, and extend the contrast gate with speaker-role pairs.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| docs/plans/console/20-STRANGLER-CENSUS.md | Splits PR 25 into lanes C + F per census errata. |
| apps/mobile/src/theme/tokens.ts | Adds speaker token export (light/dark) with documented contrast receipts. |
| apps/console/src/styles/register-bridge.css | Introduces --cp-* speaker/presence/font tokens and Tailwind @theme inline mappings. |
| apps/console/src/components/mark/PresenceMark.tsx | Switches Presence mark rendering from --ij-* to --cp-presence* tokens and updates rationale comments. |
| apps/console/src/app/fonts.ts | Adds IBM Plex Sans via next/font/google and includes it in global font variables. |
| apps/console/scripts/check-register-lint.mjs | Adds raw color-function linting and “human ink on destructive variant” rule. |
| apps/console/scripts/check-contrast.mjs | Adds contrast checks for --cp-human/agent/destructive against chrome/editor backgrounds. |
Comments suppressed due to low confidence (1)
apps/console/src/components/mark/PresenceMark.tsx:160
- The inline comment says the acting state uses an “accent slot” commit flash, but the implementation now uses the speaker presence tokens (PRESENCE / PRESENCE_COMMIT). This comment is now misleading and should be updated to match the new behavior.
// acting: the constellation condenses into a solid glyph with the
// commit flash on the accent slot, then releases.
drawCondense(t, cx, cy, flash > 0);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8286cc84e6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // co-occurrence fails on any single line. | ||
| HUMAN_INK_RE.lastIndex = 0; | ||
| DESTRUCTIVE_RE.lastIndex = 0; | ||
| if (HUMAN_INK_RE.test(line) && DESTRUCTIVE_RE.test(line)) { |
There was a problem hiding this comment.
Enforce destructive human-ink checks across JSX props
When a destructive/danger variant is written on one JSX line and text-cp-human or --cp-human is on another line of the same element, this gate passes because it only tests each line independently. That is a common formatting pattern for components, so the new register rule can be bypassed exactly where it is meant to prevent a destructive control from being painted in human ink; the check needs to reason over the element or at least a multi-line window instead of single-line co-occurrence.
Useful? React with 👍 / 👎.
| human: 'Vollkorn', // human authorship | ||
| agent: 'IBM Plex Sans', // agent voice | ||
| machine: 'JetBrains Mono', // machinery, regardless of speaker |
There was a problem hiding this comment.
Load speaker font families before exposing tokens
These mobile font tokens are meant to be used as React Native fontFamily values, but the app only registers the two Bricolage Grotesque families in apps/mobile/src/app/_layout.tsx:137 and has no packages or assets for Vollkorn, IBM Plex Sans, or JetBrains Mono. When a chat or approval surface consumes speaker.fonts, native text will fall back or fail to render with the intended authorship face, so the speaker register's typography distinction is not actually available on mobile until these families are loaded with the same names.
Useful? React with 👍 / 👎.
| is the second value of the same token, carried by the mobile light scheme | ||
| until the console light pass lands (two values, one role). */ | ||
| [data-register="intui"] { | ||
| --cp-human: #DE7C72; /* oxblood family, AA on chrome (4.76:1) */ |
There was a problem hiding this comment.
Retune human ink for raised message surfaces
The new token is only gated against --ij-chrome and --ij-editor, but the existing console thread renders user messages on bg-ij-raised (apps/console/src/views/ThreadView.tsx:46) and this same block says the speaker grammar governs chat messages and cards. On --ij-raised (#393B40), #DE7C72 is about 3.86:1, below the 4.5 body-text target, so switching those message/card surfaces to text-cp-human will ship insufficient contrast unless the token is lightened or --ij-raised is included in the contrast gate.
Useful? React with 👍 / 👎.
…le trinity strings Review findings on PR #64: - PresenceMark inkFor now chases the var() chain (--cp-presence-interrupt -> --cp-human -> hex) instead of relying on getComputedStyle to substitute nested custom-property references, which is engine dependent. Guarantees the interrupted oxblood edge on every engine, not just Chromium. - mobile tokens.ts: remove the speaker.fonts strings (Vollkorn/IBM Plex Sans/ JetBrains Mono). The Expo app loads only Bricolage Grotesque, so those bare family names would silently fall back to the system font. The trinity faces load with HANDOFF-MOBILE-EXCELLENCE (section 3.1); mobile speaker distinction is color-only until then.
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
… light mode Resolves the overlap on register-bridge.css, check-contrast.mjs, and check-register-lint.mjs; both concerns kept. Beyond the mechanical merge: - Added light-mode --cp-* values under [data-theme="light"] (--cp-human #7A2733, --cp-agent #2D5F6B, --cp-presence-commit), the "two values, one token" of amendment 2.2 that #62's light register unblocked. Var-chained roles (memory, destructive, presence, interrupt) follow --ij-gold/--ij-error/human/agent, which the light register already re-tunes. - check-contrast.mjs: declarationsFor now captures --cp-* alongside --ij-*, and a speaker-pairs pass runs on intellij-dark and intellij-light (speaker colors are register level, not preset varying). All pass: dark human 4.76/agent 5.46/ destructive 3.75; light human 9.13/agent 6.67/destructive 6.22. Gates green: fence, register, contrast (5 presets, 3 adversarial, speaker both modes), motion, icons; console tsc clean.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 86b44796ab
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| destructive: lightColors.destructive, // ink, never red | ||
| }, | ||
| dark: { | ||
| human: '#DE7C72', // oxblood lifted for AA as text on the dark well |
There was a problem hiding this comment.
Retune dark human ink for raised cards
When dark-mode conversational cards use the standard mobile raised surface, this new human speaker color falls below the text contrast target documented in the same block: #DE7C72 on darkColors.raised (#3A3A37) is about 3.93:1, under 4.5:1. Since the register is described as governing approval/proposal cards and other content surfaces, checking only bg leaves those raised dark cards with under-contrast human-authored text.
Useful? React with 👍 / 👎.
| * destructive light #141413 on #FAF9F5 17.50:1 | ||
| * destructive dark #F5F4EE on #262624 13.76:1 | ||
| */ | ||
| export const speaker = { |
There was a problem hiding this comment.
Wire speaker colors into NativeWind tokens
In the mobile styling path I checked, NativeWind utilities are generated from the explicit color list in apps/mobile/tailwind.config.js, backed by variables mirrored in src/global.css, not from this TS export. Adding the speaker register only here means class-based mobile surfaces using the new cross-platform vocabulary such as text-cp-human or bg-cp-agent will get no generated utility, so these roles need to be mirrored into the NativeWind token path or exposed through the existing theme object before mobile content surfaces consume them.
Useful? React with 👍 / 👎.
| }, | ||
| dark: { | ||
| human: '#DE7C72', // oxblood lifted for AA as text on the dark well | ||
| agent: '#45B4A3', // teal lifted for AA, held hue-distant from a blue accent |
There was a problem hiding this comment.
Tune dark voice colors for the deep-teal machine theme
When users select the existing deep-teal machine surface, chat/agent-output surfaces can render on t.machine.mid (#284C56; checked apps/mobile/src/app/thread/[id].tsx for agent bubbles). This new dark agent voice color is only receipted against bg, and #45B4A3 on #284C56 is about 3.68:1, so applying the speaker register to chat messages under that mobile theme would ship under-contrast agent text.
Useful? React with 👍 / 👎.
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/plans/console/20-STRANGLER-CENSUS.md`:
- Around line 17-18: The deep-pass dispatch criteria must include PR 25 so its
documented C + F split is actually verified. Update the deep-pass rule near the
existing E, 18, 30, and 34 selection logic to explicitly select PR 25, or move
its verification into a step that is executed by the plan.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 98327620-c67a-4ed7-b42e-f4a7190755a7
📒 Files selected for processing (7)
apps/console/scripts/check-contrast.mjsapps/console/scripts/check-register-lint.mjsapps/console/src/app/fonts.tsapps/console/src/components/mark/PresenceMark.tsxapps/console/src/styles/register-bridge.cssapps/mobile/src/theme/tokens.tsdocs/plans/console/20-STRANGLER-CENSUS.md
| | 9, 13, 17, 19, 20, 26, 27, 28, 50, 51, 52 | Porcelain v2 shell, register, UX physics, design-taste lane | C | Paint and shell die; the governance habits already carried into the console constitution | | ||
| | 25 | Porcelain physics (paint) plus the mobile app foundation: expo-router tabs, thread and room and object routes, a capture queue, notifications, theme tokens with contrast receipts, the WeaveSpinner | C + F | Errata (AMENDMENT-REGISTERS-AND-MOBILE-RECONCILIATION 5.1): split out of the lane-C group, which classified it porcelain-only from its title. Porcelain physics dies (C); the mobile foundation is carried (F) and re-lands via HANDOFF-MOBILE-EXCELLENCE. The deep pass still verifies the split against the PR diff | |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Ensure PR 25 is included in the deep-pass dispatch.
This row claims that the deep pass verifies the C + F split, but the deep-pass rule at Line 37 only selects E rows and rows 18, 30, and 34. Because PR 25 is now C + F, it will be skipped. Add PR 25 to the deep-pass criteria or move the verification requirement into an executed step.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/plans/console/20-STRANGLER-CENSUS.md` around lines 17 - 18, The
deep-pass dispatch criteria must include PR 25 so its documented C + F split is
actually verified. Update the deep-pass rule near the existing E, 18, 30, and 34
selection logic to explicitly select PR 25, or move its verification into a step
that is executed by the plan.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adb29dc5d5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| { name: 'human on chrome', foreground: '--cp-human', background: '--ij-chrome', target: 4.5 }, | ||
| { name: 'agent on chrome', foreground: '--cp-agent', background: '--ij-chrome', target: 4.5 }, | ||
| { name: 'human on editor', foreground: '--cp-human', background: '--ij-editor', target: 4.5 }, | ||
| { name: 'agent on editor', foreground: '--cp-agent', background: '--ij-editor', target: 4.5 }, |
There was a problem hiding this comment.
Add raised-surface coverage for agent voice contrast
When the speaker register is applied to raised conversational cards or the existing raised agent-plan surface (apps/console/src/views/ThreadView.tsx:65 uses bg-ij-raised), dark --cp-agent (#45B4A3) on --ij-raised (#393B40) is about 4.44:1, below the 4.5 body-text target this gate assigns to agent voice. Because the new coverage stops at chrome and editor, the contrast gate stays green while standard raised cards can ship under-contrast agent text.
Useful? React with 👍 / 👎.
| // in (Galley emits oklch, color-mix). A component inlining any of these bypasses | ||
| // the register just as a raw hex would, so raw color functions fail outside the | ||
| // register files too. | ||
| const RAW_COLOR_FN_RE = /\b(?:oklch|oklab|rgba?|hsla?|hwb|lab|lch)\(|color-mix\(/g; |
There was a problem hiding this comment.
Include CSS color() in raw color lint
With this regex, the new “raw color function” gate still allows standard CSS color(...) notation, e.g. style={{ color: 'color(display-p3 1 0 0)' }} in any component under src. That bypasses the register just like the oklch/rgb cases this rule is meant to reject, so the lint does not actually enforce “raw values fail” for modern CSS color functions.
Useful? React with 👍 / 👎.
…ers) Union-resolve the registration seams both surfaces append to: console-host query routing (pg.* local seam ahead of memory and the live-wire default), the workspace seed (proactivity seeded as a secondary surface peer to Review and Appearance, with role, seed_revision, and files/context/thread companions, reached through the switcher and Command mode), the view registry (PROACTIVITY and APPEARANCE descriptors both kept), the CLAUDE.md library ledger (elkjs row beside the new files/context/plan rows), package.json (d3 and elkjs), and the surface-list test. Lockfile regenerated with elkjs.
Implements dispatch slice 1 of
docs/plans/console/13-AMENDMENT-REGISTERS-AND-MOBILE-RECONCILIATION.md(section 2.5): the cross-platform--cp-*speaker register, plus the section 2.4 Presence mark ruling and the section 5.1 census errata.What lands
--cp-*speaker vocabulary (apps/console/src/styles/register-bridge.css):--cp-human(oxblood),--cp-agent(teal),--cp-memory(--ij-gold),--cp-destructive(reserved red), the presence tokens, and the trinity font tokens. Tailwind@theme inlineemitstext-cp-*/font-cp-*. Two grammars coexist by scope: chrome stays--ij-*, conversational content consumes--cp-*.fonts.ts, next/font/google), because Galley ships no@font-faceandgy-bridgere-points--gy-font-uiat the chrome Inter. Verified in the running app: the three faces resolve distinct (serif / sans / mono).destructive/dangervariant fails. Both verified firing on fixtures.check-contrast.mjsgains human/agent/destructive pairs on chrome and editor.PresenceMark.tsx): base voice teal, commit brightness lift, oxblood interrupt edge; gold removed (gold marks memory, not the mark).speakerexport inapps/mobile/src/theme/tokens.tswith computed contrast receipts.Verification
tsc --noEmitclean (console);next buildcompiles; speaker tokens verified resolving in the running console (agent teal 80.7 deg from the Int UI accent blue in oklch, so machinery and voice never blur).Coordination
register-bridge.css,check-contrast.mjs,check-register-lint.mjs(that PR is the OKLCH coloration engine; it defines no--cp-*). feat(console): add coloration and role-aware information architecture #62 rebases onto this token layer. feat(console): cards, actions, mentions + stripe surface nav + live doc wire #60 touches none of these files.Deferred (later dispatch items, not cut)
The agency kernel (2.5 item 2), HANDOFF-MOBILE-EXCELLENCE section 3.1 execution, and verified-cognition VC1 are ordered after this slice in section 5.2.
Note
The Presence mark's Playwright visual baseline changes with the teal repaint (a spec ruling, not a downgrade) and is regenerated in this PR.
Summary by CodeRabbit
New Features
Accessibility