Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions docs/design/ai-slop-tells.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ listed again.
line, so it excuses one literal, never the rest of the file.
*Exception:* keyboard notation (`⌘↵`), the reply-aim `↳`, the DM pair `↔`;
user content (the reaction picker); the parser for the kernel's `🤝` DM
event; masked-token bullets; `↵` in the marketing demo. Dated 2026-11-03:
`activity.decision.ruled`, left to the Activity redesign owner.
event; masked-token bullets; `↵` in the marketing demo.
7. **A sparkle "AI" icon.** It is the category's cliché, and it names the
technology rather than the act.
*Check:* no `AutoAwesome`, `AutoFixHigh`, `Sparkle(s)` or `✨` in v2
Expand Down Expand Up @@ -101,9 +100,9 @@ any live app surface. It found one chromatic glow, the logo key, which is drawn.
| 3 | Frosted glass | `landing/v2-landing.css:87` | the marketing sticky header only | acceptable | guard |
| 4 | Gradients | 30+ key rules | all d215 a/b key pairs; 4 named masks, track and hatch | acceptable | guard |
| 5 | Glow | `v2.css` `.v2-rail__brand-icon`, `primitives.css` `.v2p-b-c` | artboard values (`d215/index.html:167`, `:226`) | acceptable | guard |
| 5 | Focus halo | `v2.css` `.v2-activity__compose:focus-within` | hard-coded `rgba(29,63,209,.10)` 4px, not `--v2-focus-ring`; on the dark ground it is all but invisible (`rgb(138,162,255)` 4px ring with the token, measured on a local build) | real | proposal for the Activity/Artifacts redesign owner |
| 5 | Focus halo | `v2.css` `.v2-activity__compose:focus-within` | hard-coded `rgba(29,63,209,.10)` 4px, not `--v2-focus-ring`; on the dark ground it is all but invisible (`rgb(138,162,255)` 4px ring with the token, measured on a local build) | real | fixed by the Activity build: the open composer's ring is `var(--v2-focus-ring)` (`components/V2ActivityPage.css`) |
| 6 | Glyph icons | `en`/`zh-CN`: `inviteModal.connectOwnAgent`, `adminUsers.registered.analyticsLink`, `adminAnalytics.userAdminLink` (`→`), `approvalCard.approved` (`✓`) | strings | real | glyphs dropped from the copy |
| 6 | Glyph icons | `activity.decision.ruled` (`✓ {{by}} ruled`), shown on Activity and the thread decision card | string | real | proposal for the Activity/Artifacts redesign owner; allowlisted by name and date in the guard |
| 6 | Glyph icons | `activity.decision.ruled` (`✓ {{by}} ruled`), shown on Activity and the thread decision card | string | real | fixed by the Activity build: the `✓` left both locales and the guard's allowlist |
| 6 | Glyph icons | `V2PodBoard.tsx` Follow `✓`, `V2LangSwitch.tsx` `✓`, `V2FirstRunHero.tsx` `↗`, `V2Lightbox.tsx` `←`/`→`, `V2SettingsFrame.tsx` `✎` | JSX text | real | SVG glyphs from `icons/glyphs.tsx` (two chevrons added) |
| 6 | Close and chevron glyphs | `×` on the close buttons in `V2Lightbox`, `V2PodBoard` (focus editor and new task, both with no accessible name), `V2Composer` (reply aim), `V2InviteModal`, `V2CatchUpStrip` and `V2AvatarCropDialog`; `›` in `V2SettingsFrame` | JSX text | real | `ShellGlyph` `close` (added) and `chevron-right`; the two board buttons gained `aria-label` from `common.close` |
| 6 | Emoji | `V2MessageRow.tsx` reply quote | quoted uploads rendered as `📎 name` | real | an `aria-hidden` SVG file glyph before the name |
Expand All @@ -129,11 +128,9 @@ floors burn-down allowlist under a heading dated 2026-11-03, not fixed here.

### Proposals for the Activity/Artifacts redesign owner

- `.v2-activity__compose:focus-within` should use `var(--v2-focus-ring)`. The
hard-coded 10% cobalt halo barely shows in dark mode.
- Drop the `✓` from `activity.decision.ruled` (en and zh-CN), and the
allowlist entry in `v2-slop-tells.test.ts` with it.
- The Class A note on "Needs you" below.
- Done for Activity (the d215 build): the composer ring is the token, the `✓`
left `activity.decision.ruled`, and "Needs you" is one hairline-split list
(the Class A note below).

### Proposals for UX Lead (Class A, not made here)

Expand Down
8 changes: 4 additions & 4 deletions docs/design/artboards/d215/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The spec for D215 (artboard v2). Open `index.html` in a browser. The toggle at t
- A second block under agent settings draws the states of that page (policy and machine, identity edit, connector grants, runtime with the model and effort selects, own API key) at 1440 and 390. The runtime and key frames follow V2RuntimeControls and V2AgentProviderKey, including the stored-model refusal and the key-save error. Those frames carry `data-state`, so `measure_after.js` skips them and `targets.json` does not move.
- Two state-only surfaces: `task-record` (the task record page, loaded and not-available, under the reply trace) and `handoff` (the OAuth and Discord return pages, `data-state` working, done, error, on the auth card). Every frame carries `data-state`, so the scorer skips them and `targets.json` does not move.
- A block under Settings draws the free-plan Plan row and the administrator-only Administration group (`data-state="admin-free"`, 1440 and 390, also skipped by the scorer).
- Under Activity and under Artifacts, a block redraws each page in the picked language (`#s-activity-signal`, `#s-artifacts-signal`): busy and day zero at 1440 and 390, built only from the seven picked surfaces' blocks. Sam approved them on 11-03. The frames carry `data-state="signal"`, so the scorer skips them until each page's build PR makes them the scored frames; the frames above them stay as the record of the live page until then.
- Under Activity and under Artifacts, a block redraws each page in the picked language (`#s-activity-signal`, `#s-artifacts-signal`): busy and day zero at 1440 and 390, built only from the seven picked surfaces' blocks. Activity's build scores its four frames (no `data-state`) and retired the traced `#s-activity` section. Artifacts' frames still carry `data-state="signal"`, so the scorer skips them until its build lands.
- The theme switch (sun / moon, D224) sits in the rail above the avatar at 1440. At 390 there is no rail, so the same switch rides the Pods top bar, left of Search. It is a two-item segment: the item for the theme in effect is the white key.
- `before/` holds prod captures from 2026-10-31, blurred so they show layout and density only.
- `targets.json` holds the helper-word and scroll targets per frame. `cap/measure_after.js` writes it from `index.html`.
Expand All @@ -15,14 +15,14 @@ The spec for D215 (artboard v2). Open `index.html` in a browser. The toggle at t

## Where each frame came from

Passing the prod check means a page matches its frame. It means the page matches the style Sam picked only when the frame came from his pick. Every frame is in one of four groups. Only the first two have scored frames, and prod scores are reported per group, never as one total.
Passing the prod check means a page matches its frame. It means the page matches the style Sam picked only when the frame came from his pick. Every frame is in one of four groups. A group's frames are scored only where the table says so, and prod scores are reported per group, never as one total.

| Group | Frames | Source |
|---|---|---|
| **From Sam's pick** | sidebar, chat, board, agent-memory, agent-settings, settings, connectors | The seven surfaces picked on 10-31 (#3059). Later edits: the theme switch (#3175) and the open thread (#3178). #3288 (the 390 agent-settings and settings frames, brought up to the shipped pages) and #3289 (memory notes drawn as the API holds them) moved those frames toward the live page, so read them with that in mind. |
| **Drawn after the pick** | dm, byo, byo-handoff, connect, team, firstrun-\*, signin, signup, signup-sent, verify-email, forgot-password, reset-password, cli-authorize, invite, invite-required, profile, agent-profile, run-trace-after, chat-trace, chat-agents-away, and the agent-settings and settings state blocks | New drawings in the picked language, from 11-01 on. Sam has not reviewed them as a set. |
| **Approved by Sam, 11-03** | activity-\*, artifacts-\* with `data-state="signal"`; task-record-\*; handoff-\* | Sam saw each one live-beside-proposed and answered "Build as drawn" for all four pages. Activity and Artifacts are built only from the picked surfaces' blocks. The scorer still skips these frames (they carry `data-state`). Each page's build PR makes its approved frame the scored one and retires the frame it replaces. |
| **Drawn from live, being retired** | activity-\*, artifacts-\* without `data-state` | Traced from the live pages with small fixes (#3316, #3318). The scorer skips them (`SKIPPED` in `cap/measure_after.js`). Scoring a page against them would only show it has not drifted from itself. The Activity and Artifacts build PRs remove them. The two before frames, `run-trace-before` and `chat-trace-before`, draw the old pages and are never a target. |
| **Approved by Sam, 11-03** | activity-busy, activity-dayzero (`#s-activity-signal`, scored since the Activity build); artifacts-\* with `data-state="signal"`; task-record-\*; handoff-\* | Sam saw each one live-beside-proposed and answered "Build as drawn" for all four pages. Activity and Artifacts are built only from the picked surfaces' blocks. The scorer still skips these frames (they carry `data-state`). Each page's build PR makes its approved frame the scored one and retires the frame it replaces. |
| **Drawn from live, being retired** | artifacts-\* without `data-state` | Traced from the live page with small fixes (#3318). The scorer skips them (`SKIPPED` in `cap/measure_after.js`); scoring a page against them would only show it has not drifted from itself. The Artifacts build PR removes them; the Activity build removed its traced frames. The two before frames, `run-trace-before` and `chat-trace-before`, draw the old pages and are never a target. |

## Rules for D215 PRs

Expand Down
13 changes: 7 additions & 6 deletions docs/design/artboards/d215/cap/measure_after.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@ const SURFACES = [
'settings', 'agent-settings', 'agent-memory', 'board', 'connectors', 'chat', 'sidebar', 'byo', 'byo-handoff',
'firstrun-welcome', 'firstrun-waiting', 'firstrun-connected', 'firstrun-error', 'connect', 'team',
'chat-agents-away', 'chat-trace', 'run-trace-after', 'profile', 'firstrun-welcome-nohost',
// Activity: the frames Sam approved 11-03 ("Build as drawn"), built in V2ActivityPage.
'activity-busy', 'activity-dayzero',
];
// Base frames (no data-state) that are drawn but deliberately not scored. Each needs a reason.
const SKIPPED = {
// Activity and Artifacts are being redesigned in another session; targets taken now would pin
// frames that are about to change. Score them once that redesign lands.
'activity-busy': 'redesign in progress elsewhere',
'activity-dayzero': 'redesign in progress elsewhere',
'activity-dayzero-pending': 'redesign in progress elsewhere',
// Artifacts is being redesigned in another session; targets taken now would pin frames that
// are about to change. Score them once that redesign lands.
'artifacts-busy': 'redesign in progress elsewhere',
'artifacts-dayzero': 'redesign in progress elsewhere',
// Drawings of the old page beside their "after" frames (390 only). They are what the fix moves
Expand All @@ -48,7 +47,8 @@ const SKIPPED = {
// a real key. The first-run dialog is a latch-gated overlay, and the Scout welcome only exists in a
// brand-new pod. chat-agents-away and chat-trace need a pod in that exact state, run-trace-after a
// run id and profile a person id, none of which prod() takes yet, so they are artboard-only for now.
const PROD_SURFACES = ['settings', 'agent-settings', 'agent-memory', 'board', 'connectors', 'chat', 'sidebar', 'byo', 'connect', 'team'];
// activity-dayzero needs an account with no asks and no agents, so only the busy page is checked.
const PROD_SURFACES = ['settings', 'agent-settings', 'agent-memory', 'board', 'connectors', 'chat', 'sidebar', 'byo', 'connect', 'team', 'activity-busy'];
const VIEWPORTS = ['1440', '390'];
const EXPECTED = SURFACES.flatMap(s => VIEWPORTS.map(v => `${s}-${v}`));

Expand Down Expand Up @@ -221,6 +221,7 @@ async function prod(only) {
['byo', () => '/v2/agents/byo'],
['connect', () => '/v2/connect'],
['team', () => '/v2/agents'],
['activity-busy', () => '/v2/activity'],
['chat', () => `/v2/pods/${pod}`],
['sidebar', vp => (vp === '1440' ? `/v2/pods/${side}` : '/v2'), { list390: SIDEBAR_390 }],
];
Expand Down
4 changes: 2 additions & 2 deletions docs/design/artboards/d215/cap/measure_after.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test('--only with an unknown surface throws', () => {

test('the committed targets.json passes its own validation', () => {
const t = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'targets.json'), 'utf8'));
assert.strictEqual(Object.keys(t).length, 40);
assert.strictEqual(Object.keys(t).length, 44);
validateTargets(t);
});

Expand All @@ -39,7 +39,7 @@ test('an empty or partial measurement is refused', () => {
const partial = { ...t }; delete partial['board-390'];
assert.throws(() => validateTargets(partial), /missing board-390/);
assert.throws(() => validateTargets({ ...t, 'chat-1440': { helperWords: NaN, innerRatio: 2 } }), /invalid chat-1440/);
assert.strictEqual(EXPECTED.length, 40);
assert.strictEqual(EXPECTED.length, 44);
});

test('a frame the scorer does not know is named, with the way to fix it', () => {
Expand Down
Loading
Loading