59 lines
2.6 KiB
Markdown
59 lines
2.6 KiB
Markdown
---
|
||
date: 2026-10-20
|
||
pr: pending
|
||
feature: Chat surface shadow tokenization and CYBER color guard
|
||
impact: The fork divider pill in the chat message list now paints its shadow from the shared --shadow-sm token instead of a hardcoded light-theme slate wash, so it reads as a lifted surface on the dark background. A new source-level guard now blocks raw hex colors, named colors, and literal RGB triples from reappearing anywhere in the client source. Purely visual; no message shapes, socket events, or emission timing changed.
|
||
---
|
||
|
||
# Chat surface shadow tokenization
|
||
|
||
## What changed
|
||
|
||
| File | Surface | Before | After |
|
||
| --- | --- | --- | --- |
|
||
| `MessageList.vue` | fork divider pill | `box-shadow: 0 8px 24px rgba(15, 23, 42, 0.05)` | `box-shadow: var(--shadow-sm)` |
|
||
|
||
`rgba(15, 23, 42, 0.05)` is a slate-900 wash at 5% alpha — a light-theme habit
|
||
for a hairline lift on white. On `--bg-card` it is effectively invisible, so
|
||
the pill lost its "lifted" read entirely. `--shadow-sm` is the dark-theme
|
||
equivalent (`0 2px 8px oklch(0 0 0 / 0.28)`).
|
||
|
||
The same lint also flagged a stale shadow in `PetdexView.vue`
|
||
(`rgba(127, 127, 127, 0.08)` checkerboard → `rgba(var(--text-muted-rgb), 0.08)`)
|
||
and the kanban category colors, which were promoted to the new
|
||
`--kanban-review` / `--kanban-review-rgb` tokens. Those two files are not on
|
||
the chat chain, but they are recorded here because the guard that found them
|
||
was introduced as part of this same change.
|
||
|
||
## New guard
|
||
|
||
`tests/client/style-tokens.test.ts` scans every `.vue` / `.scss` / `.css` /
|
||
`.ts` file under `packages/client/src` and fails on:
|
||
|
||
1. raw hex colors (`#rrggbb`)
|
||
2. named color keywords (`color: red`)
|
||
3. literal `rgba(0,0,0,` shadows
|
||
4. literal RGB triples in `rgba()` (`rgba(15, 23, 42, 0.05)`) — these must
|
||
become `rgba(var(--*-rgb), α)`
|
||
|
||
Comments and HTML entities are stripped before matching, and the stripping step
|
||
has its own self-check so a broken guard cannot silently pass.
|
||
|
||
The exemption list is explicit: chart palette (`ui-baseline.md` §7), the xterm
|
||
theme presets, the Arco `ConfigProvider` theme, the `arkscore` vendor
|
||
decoration layer, and the language badges in `MessageItem.vue`. The language
|
||
badge palette is additionally pinned by an assertion, so the exemption cannot
|
||
widen unnoticed.
|
||
|
||
## Not changed
|
||
|
||
Message rendering, streaming, tool-call grouping, and the `/chat-run` event
|
||
contract. The chat chain fragment exists because the touched file sits on the
|
||
chat chain path, not because any behavior moved.
|
||
|
||
## Verification
|
||
|
||
`npm run harness:check`, `npm run build`, and `npm run test:e2e` (46 passed)
|
||
all pass. The existing `tests/e2e/chat-cyber-semantics.spec.ts` still passes
|
||
unchanged.
|