Skip to content

feat(spec-detail): .use_my_data() beside the library carousel replaces the image icon - #12539

Merged
MarkusNeusinger merged 4 commits into
mainfrom
feat/use-my-data-entry
Nov 2, 2026
Merged

MarkusNeusinger merged 4 commits into
mainfrom
feat/use-my-data-entry

Conversation

@MarkusNeusinger

@MarkusNeusinger MarkusNeusinger commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Summary

The owner's decisions of 2026-11-02: the plot page's entry to the agent chat stops being a data-table icon in the image's top-right corner (not pretty, not telling) and becomes a text action beside the library carousel; the landing page's line points to the catalogue.

  • .use_my_data() → to the right of the carousel, the mirror of ← .compare() on its left: same mono 12.8 px, --ink-soft, green on hover, the arrow nudging outwards, a hairline rule between it and the carousel. No "experimental" tag: the chat's notice says it once open (owner). The icon, its tooltip and the onUseWithMyData prop leave SpecDetailView; SpecPage hands the same callback to LibraryPills.
  • Same gating, same target. useAgentEligibility is untouched: the entry shows only while the public lane is open or for an admin on the admin lane, and only for an eligible pair. Admins still get /debug/agent by full navigation, everyone else /agent through the router, both with source=plot_page.
  • The landing line reads # new: pick any plot, then .use_my_data() → and links to /plots instead of opening the chat on scatter-basic in matplotlib; still shown only while the public lane is open, and no "experimental" there either (owner).
  • Analytics. agent_open keeps source=plot_page: the plot page has exactly one entry, so the value stays unambiguous, and a new value would need a change to the chat page's OPEN_SOURCES allowlist, which this PR does not touch. The landing line no longer opens the chat, so it is tracked like the other hero links, nav_click{source: hero_use_my_data, target: /plots}; agent_open{source: landing} was sent on launch day only. docs/reference/plausible.md says both.

Decisions (delegated, documented here and in code comments)

  • No layout jump. The row is a grid with equal side columns (minmax(0, 1fr) auto minmax(0, 1fr) from md up), so the carousel is centred over the image whether or not the right column is filled, and the entry fades in (0.3 s, off under prefers-reduced-motion). Measured shift between "eligibility pending" (response delayed 3 s) and "shown": 0 px for the carousel, .compare() and the image, at 1440 and 390 px.
  • The carousel is now centred over the image (before, the .compare() + carousel group was centred, which put the carousel 61 px right of centre at 1440 px).
  • Phones and tablets (below 900 px): the two text actions share the line above the carousel, ← .compare() at the left edge, .use_my_data() → at the right, and the carousel takes the line below. That first line exists for .compare() anyway, so the late entry moves nothing, and on a phone the image starts where it does on main (387.3 px at 390). Between 600 and 899 px .compare() moves from beside the carousel to the line above it.
  • Accessible name "Use with my data" (the owner left it to me): with the tag gone the visible control says nothing about "experimental", and the chat's notice says it to everyone, screen-reader users included, once it opens.
  • Tab order follows the desktop row (compare, carousel arrows, entry). On a phone, focus goes from the top line to the carousel and back up to the entry: the trade-off of one DOM for two layouts, chosen for the desktop's reading order.
  • The landing line keeps its aria-label in words ("New: pick any plot, then use it with my data"), as the style guide asks for method-call text, and a no-break space keeps the arrow with .use_my_data() where a 360 px phone wraps the line.

Texts to read

  • Plot page, visible label: .use_my_data() →
  • Plot page, accessible name: Use with my data
  • Landing page line: # new: pick any plot, then .use_my_data() → (links to /plots)
  • Landing page line, accessible name: New: pick any plot, then use it with my data

Screenshots

Headless Chromium (playwright-core) against a production build with the agent chat on and the live API (/agent/lane open), at 2× pixel density. File paths are in the delegate's report to the lead: the plot page at desktop 1440 and mobile 390, light and dark, lane open and closed (/agent/lane mocked to {"open": false}), keyboard focus and hover crops, 360 px; the landing page at desktop 1440 and mobile 390, light and dark, open and closed, and 360 px.

Measurements (read off the page)

Width Overflow Carousel centre vs. viewport centre Gap carousel to rule either side
1440 0 720 / 720 20 / 20 px
1024, 1000, 960, 900 0 centred at each 20 / 20 px
899, 600 0 449.5 / 449.5, 300 / 300 (stacked)
390, 360, 320 0 195 / 195, 180 / 180, 160 / 160 (stacked)
  • Pending vs. shown: 0 px shift at 1440 and 390.
  • Fonts: label 12.8 px MonoLisa Code (same as .compare()); landing line 13 px, 344 px wide, one line at 390, two at 360 with the arrow kept on the second. Colours --ink-soft in both themes, #009E73 on hover.
  • Keyboard: Tab reaches the entry, the 2 px green focus ring shows, Enter opens /agent?spec=scatter-basic&library=matplotlib&language=python&source=plot_page. The landing line opens /plots.
  • Console: no errors besides the known GitHub releases 403 (rate limit).
  • At 320 px the carousel itself (356 px wide) overflows both edges symmetrically, as on main; not changed here.

Checks

  • Gemini 3.8 Flash before opening: sound with changes. Applied: the grid's 8 px column gap had added to the rules' margins (12 vs 20 px visible), now 0 from md up. Not applied: an inline onAll that defeats memo (unchanged, not this PR). The chat page's own "open this page from a plot's .adapt() button" text (AgentChatPage.tsx) is stale and goes to the agent that owns that file.
  • Copilot (one round): two low findings on docs/concepts/agent-network.md, fixed in bb26e1f. The tag removal and the landing line came after, as owner changes, with no new round.

Plan

N/A

Test plan

  • yarn lint, yarn fm:check, yarn type-check, yarn test (148 files, 1,545 tests), yarn build
  • uv run python -m tools.changelog check --base origin/main
  • Tests: LibraryPills shows the entry only with the prop, by name, with no "experimental", click, Enter and Space, after the carousel in the tab order; SpecPage passes it only for an eligible pair and navigates to /agent?...&source=plot_page; SpecDetailView no longer renders it; HeroSection shows the line only while the lane is open (not while it probes), links to /plots, and tracks nav_click{source: hero_use_my_data}.
  • Browser: the plot page at desktop 1440 and mobile 390, light and dark, lane open and closed, eligibility delayed 3 s, widths 320 to 1024; the landing page at 1440, 390 and 360, light and dark, open and closed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8

…s the image icon

The agent chat entry on plot pages was a data-table icon in the image's
top-right corner. It becomes a text action to the right of the library
carousel, the mirror of `<- .compare()` on its left, with a small muted
`experimental` tag hanging under the label. Same gating, same chat URL,
same `agent_open{source: plot_page}`.

The carousel row becomes a grid with equal side columns, so the carousel
stays centred over the image and the action fades in after the
eligibility probe without moving anything. Below md the two text actions
share the line above the carousel, and the gap under it keeps room for
the tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
Copilot AI lite review requested due to automatic review settings November 2, 2026 22:30
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two active documentation issues misdescribe the lane-specific navigation and public eligibility logic, so the guidance contradicts the implementation.

2 open issues
What changed in this PR

Moves the plot page’s “use with my data” entry from the image overlay to a text action beside the library carousel while preserving eligibility gating, routing, analytics, responsive behavior, and keyboard access.

Changes:

  • Adds the .use_my_data() → action, experimental tag, responsive layout, hover/focus states, and keyboard support to LibraryPills.
  • Removes the former image-overlay icon and rewires SpecPage to pass the eligibility callback to LibraryPills.
  • Updates tests, analytics and architecture documentation, changelog text, and related configuration comments.
File Summary Review notes
docs/​reference/​plausible.md Documents the new plot-page location for agent_open. —
docs/​concepts/​agent-network.md Updates the agent request flow and frontend architecture documentation. Nit (4 votes): Document both admin and public destinations instead of only /debug/agent.
Nit (3 votes): Update the frontend eligibility contract to include the public lane.
Nit (1 vote): Document both admin/public route pairs for agent requests.
changelog.d/​use-my-data-entry.md Adds the changelog fragment for the UI move. —
app/​src/​vite-env.d.ts Updates agent feature-flag documentation. —
app/​src/​utils/​adminAuth.ts Updates admin-hint documentation. —
app/​src/​sections/​spec-detail/​SpecDetailView.tsx Removes the former image-overlay entry and icon. —
app/​src/​sections/​spec-detail/​SpecDetailView.test.tsx Verifies the entry is no longer rendered on the image. —
app/​src/​sections/​spec-detail/​LibraryPills.tsx Adds the carousel-adjacent action, tag, responsive layout, animation, and keyboard behavior. —
app/​src/​sections/​spec-detail/​LibraryPills.test.tsx Tests visibility, activation, and tab order. —
app/​src/​pages/​SpecPage.tsx Passes the gated callback to LibraryPills. —
app/​src/​pages/​SpecPage.test.tsx Tests eligibility gating and public navigation. —
app/​src/​pages/​DebugPage.tsx Updates the admin-hint comment. —
app/​src/​pages/​DebugPage.test.tsx Updates the related test documentation. —
app/​src/​global-config.ts Updates feature-flag documentation for the new entry. Nit (1 vote): Clarify that the flag gates both the admin and public agent pages, not only the admin page.

Review effort: Lite

Comment thread docs/concepts/agent-network.md Resolved
Comment thread docs/concepts/agent-network.md Resolved
Copilot review on #12539: the request flow and the frontend contract still
described the admin-only gate and route. The entry shows for the admin
lane or the open public lane, each with its pair's eligibility, and a
public visitor goes to /agent through the router.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
@codecov

codecov Bot commented Nov 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…e leads to /plots

Owner changes for #12539:

- `.use_my_data() →` beside the carousel loses the `experimental` tag
  under it; the chat's notice says it once open. The accessible name
  becomes "Use with my data", and the gap the tag needed on phones goes
  back to main's 8 px.
- The landing line reads `# new: pick any plot, then .use_my_data() →`
  and links to the catalogue instead of opening the chat on scatter-basic,
  still only while the public lane is open. Tracked as
  nav_click{source: hero_use_my_data}; plausible.md and the agent-network
  doc say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8
@MarkusNeusinger
MarkusNeusinger merged commit 2e80154 into main Nov 2, 2026
16 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the feat/use-my-data-entry branch November 2, 2026 22:50
MarkusNeusinger added a commit that referenced this pull request Nov 2, 2026
## Summary
- **Notice:** the public experimental notice is one line, `#
experimental AI · results can be wrong · stored only if you send
feedback`, and its ⓘ button (`About the assistant`) opens a popover with
which AI and where, what not to paste, the daily limits and the link to
`/legal#assistant` (`ExperimentalNotice.tsx`, texts in `lane.ts`).
- **Data card:** the header is `# your data ⓘ`, and the ⓘ opens the
how-to (formats, steps, a fix in plain words, changes afterwards). The
long label, its hint line and the how-to paragraph under the card are
gone. The data box and the composer name example data, a curve and a fix
in short placeholders, and typing `example data` or a curve still works
as before. Both ⓘ popovers share `InfoPopover.tsx`.
- **Result card:** the image, its toolbar and the theme switch show as
before. The rounds grid and the "what changed" list sit behind one
status line at the end of the theme row (`second try · 2 changes ⓘ`).
The code sits behind `.show_code()` / `.hide_code()`, while `.copy()`
and the downloads stay in view. Each card keeps its choice for the
session, also across a collapse of the whole card, and a new version's
card starts folded. Residual notes stay in view.
- **Feedback and save:** quick feedback shows only the four reactions
until one is picked, which unfolds the message box, the data box, the
public consent line and `.send()`. On the admin lane, `.save()` and its
`# include data.csv` box leave the header row for a "⋯" menu
(`SessionMenu.tsx`). The public lane has no `.save()` and no menu (owner
decision of 2026-11-02): a visitor cannot resume a saved session, and
the feedback form covers "something went wrong".
- **Missing parameters:** the notice now names the plot page's
`.use_my_data()` (#12539) instead of `.adapt()`.
- **Wider column:** the chat column grows with the window up to 1360 px
(`COLUMN_MAX_WIDTH`, 960 before). The data card, the plot cards (bigger
images) and the code use the full width. The thread's replies, turns and
notices, and a card's text lists, keep a readable line of at most about
80 characters (`CHAT_TEXT_MAX = '80ch'` in `styles.ts`); user turns stay
right-aligned. Below about 1100 px the window sets the width, as before.
Both lanes share the layout. Measured at 1920 px with the BFF mock:
before, column 960 and card 918 px; after, column 1360, card 1318 and
reply 718 px.
- **Root prompt (`agents/anyplot/prompts/root.md`, "The page's
controls"):** the list now names `.show_code()` and `.hide_code()` for
the code, `.expand()` and `.collapse()` for the whole card, the status
line, and `.cancel()` in the feedback. It no longer names `.save()`: the
prompt has no notion of the lane, and the public page has no `.save()`.
This is a wording-only prompt change, so it got no harness or eval run.
`test_prompt_controls.py` and all of `tests/unit/agents` pass (19,962
tests).

## Decisions (decided and documented)
- **Popover, not tooltip,** for the ⓘ buttons: it opens on a tap as on a
click, holds a link, traps focus until Escape or a click outside, and
returns the focus to the button. The data card's ⓘ sits beside its
`<label>`, not inside it, so it never joins the data box's accessible
name.
- **Collapsed layout:** the tries moved from the card header into the
status line, so `ok` is not said twice. The header keeps `v2 · library ·
● status` for collapsed earlier versions. A run with neither rounds nor
changes gets a plain status line without a toggle. `.copy()` became a
text button in the code row, because the code block it used to sit on is
folded now. The highlighter chunk loads only when the code opens.
- **`.save()` goes into a "⋯" menu on the admin lane, not the feedback
area.** A save downloads the session to the user's computer and stores
nothing, while feedback stores a case for the operator; one data box for
both would blur what goes where. The menu stays mounted, so the box
keeps its choice; a successful save closes it, and a failure keeps it
open with its line, which goes when the menu closes. The admin lane
keeps its ticked default (checked in the browser on `/debug/agent`). On
the public lane the page renders neither the menu nor `.save()`.
- **Fresh feedback form gets `.cancel()`,** which folds it back to the
reactions and moves the focus to the first one; without it a mis-click
could not be undone.
- **Placeholders wrap at phone width** (`::placeholder` with
`pre-wrap`), while a pasted table keeps its lines.

## Finding for the API (not in this PR)
The public BFF route `GET /agent/session/bundle` still exists, but no
page calls it now. Removing it is an API change for another PR;
`docs/reference/api.md` says so for now.

## Texts to read
New or changed user-facing texts:
- Notice line: `# experimental AI · results can be wrong · stored only
if you send feedback`
- ⓘ button name: `About the assistant`
- Popover heading: `# about the assistant`
- Popover lines: `Claude by Anthropic, through Google Cloud Vertex AI in
the EU` · `don't paste data you may not share` · `daily limits apply` ·
link `how the assistant works` (unchanged, now inside the popover)
- Removed from the notice (the legal page covers them): `an AI does the
work here: … reads what you paste and writes the plot and its code` and
`nobody checks them by hand`. Say if either should come back into the
popover.
- Data card header: was `# your data — paste or drop CSV, TSV, JSON,
plain text, Excel, ODS, Parquet, Feather or NumPy`, now `# your data`
with an ⓘ (name `How the data card works`)
- Data card how-to popover, heading `# how it works`, lines:
- `formats: CSV, TSV, JSON, plain text, Excel, ODS, Parquet, Feather or
NumPy`
- `paste or drop → check the preview and the bindings → .confirm() →
.create_plot()`
  - `the assistant fixes your data in plain words: "sum per month"`
- `afterwards, ask for changes: "log scale on y", "label the outliers"`
- Removed: the hint `or type "example data" here, or ask for a curve in
the chat: y = sin(x), x from -pi to pi`, and the paragraph under the
card (`paste your data above, or ask here for example data or a curve …
it sums your data up here … "read Anteil as numbers" or "sum per month".
check the preview and the bindings, confirm, then .create_plot(), with a
note first if the plot should do something differently. afterwards, ask
for changes to the plot: "log scale on y", "dark version", "label the
outliers".`). The paragraph's "it sums your data up here", "read Anteil
as numbers", "with a note first if the plot should do something
differently" and "dark version" are not carried over.
- Data box placeholder: was the sample `month,revenue / 2026-01,120 /
2026-02,135`, now three lines: `paste a table or drop a file (csv,
excel, json …)` / `or type: example data` / `or ask for a curve: y =
sin(x), x from -pi to pi`
- Composer placeholder, step 1: was `ask for example data or a curve: "y
= sin(x), x from -pi to pi"` (no data) and `ask about your data, or for
a fix: "sum per month"` (data), now `ask for example data, a curve, or a
fix to your data` for both
- Composer placeholder after a plot: was `ask about this plot, or ask
for a change`, now `ask for a change, e.g. log scale on y`
- Missing-parameters notice: was `open this page from a plot's .adapt()
button: it needs a spec and a library, such as scatter-basic in
matplotlib.`, now `open it from a plot's .use_my_data(), or start with
scatter-basic in matplotlib.`
- Card status line: `<tries> · <n> change(s)` with ⓘ, for example
`second try · 2 changes`; screen-reader name `Run details: …`
- Code toggle: `.show_code()` / `.hide_code()` (names `Show code` /
`Hide code`); copy button `.copy()` / `.copied`
- Feedback: `.cancel()` on a fresh form (name `Cancel the feedback on
version N`)
- Admin lane only: menu button `⋯` (name `More actions`, tooltip `more ·
.save() the session as a json file`); menu heading `# save the session
as a json file` (the old `.save()` tooltip's words). Public lane:
`.save()` and its `# include data.csv` box are gone.
- Root prompt, "The page's controls" (read by the model, not shown to
users):
- page header: the clause `` `.save()`, which downloads the session ``
is removed;
- result card: `` `.expand()` and `.collapse()` for the code `` becomes
`` the status line next to the light and dark switch (the tries and the
number of changes), which opens the rounds and the list of what changed,
`.show_code()` and `.hide_code()` for the code, `.expand()` and
`.collapse()` for the whole card ``;
- feedback: `` with `.send()` `` becomes `` a click on one of which
opens the message box with `.send()` and `.cancel()` ``.

## Screenshots (BFF mock, public lane, headless playwright-core)
All in
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/`,
named `<before|after>-<width>-<theme>-<n>-<what>.png`, each at 1440 and
390 in light and dark.

Wide screen at 1920 px, full page with two versions, a user turn and a
reply, before and after:
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1920-light-wide.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1920-light-wide.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1920-dark-wide.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1920-dark-wide.png`
- also after: `after-1440-*-wide.png`, `after-2560-*-wide.png` and
`after-390-*-wide.png` in the same folder (the masthead and the pinned
data header appear mid-page in these full-page captures because they are
sticky)

Data card, before and after:
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1440-light-8-datacard.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-8-datacard.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-390-light-8-datacard.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-light-8-datacard.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1440-dark-8-datacard.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-dark-8-datacard.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-390-dark-8-datacard.png`
→
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-dark-8-datacard.png`
- How-to open:
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-9-datacard-howto.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-dark-9-datacard-howto.png`

Notice, header, card and feedback, before:
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1440-light-1-top.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-390-dark-1-top.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1440-light-4-card-folded.png`
(the whole card as it was),
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-390-dark-4-card-folded.png`
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/before-1440-light-6-feedback.png`

After:
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-1-top.png`:
notice and header
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-2-notice-open.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-dark-2-notice-open.png`:
notice popover open
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-admin-3-menu-open.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-dark-admin-3-menu-open.png`:
the "⋯" menu on the admin lane (the public header in
`after-1440-light-1-top.png` has none)
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-4-card-folded.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-dark-4-card-folded.png`:
card folded
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-5-card-open.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-dark-5-card-open.png`:
card with details and code open
-
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-6-feedback.png`
/
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-1440-light-7-feedback-open.png`,
`/tmp/claude-1000/-home-meake-projects-anyplot/402df83f-568f-4063-805d-572b195b8887/scratchpad/chatui/shots/after-390-light-7-feedback-open.png`:
feedback before and after a click

## Plan
N/A (owner decisions of 2026-11-02, relayed by the lead)

## Test plan
- [x] `yarn lint`, `yarn fm:check`, `yarn type-check`, `yarn test` (149
files, 1561 tests), `yarn build`, on the head after the merges of
`origin/main` (#12539, #12538) and the width change
- [x] Width: 1440, 1920 and 2560 px, light and dark, plus 390 px: no
sideways scroll; the column is 1248, 1360 and 1360 px wide, and 358 px
at 390 as before; the reply is capped at 718 px; the card is full width
- [x] `uv run --extra test --extra agents pytest tests/unit/agents`
(19,962 passed, 36 skipped) after the `root.md` change
- [x] New and updated tests: `SessionMenu.test.tsx` (new);
`ResultCard.test.tsx` (status line, rounds, plain line, code fold,
failed code, state across a collapse, new version folded);
`ResultFeedback.test.tsx` (folded form, `.cancel()` focus, consent
before send); `SaveButton.test.tsx` (`onSaved`); `DataPanel.test.tsx`
(one-line label, placeholder, the how-to popover with Escape and focus
return); page tests for the notice popover, the menu, the save flow, the
placeholders and the `.use_my_data()` notice
- [x] `uv run pytest tests/unit/agents/test_prompt_controls.py` (3
passed)
- [x] Browser: public lane at 1440 and 390, light and dark, against the
BFF mock: notice popover, menu, card folded and open, feedback before
and after a click, the data card and its how-to popover, the placeholder
wrapping in the box at 390, no "⋯" menu on the public lane, no sideways
scroll, no console errors from the page (the only 403 is the masthead's
GitHub release lookup, rate-limited); admin lane at 1440 light and 390
dark: no notice, box ticked, save downloads and closes the menu with
focus back on the button
- [x] Gemini 3.8 Flash pre-PR check: 4 findings. Fixed: a stale failure
line in the kept-mounted menu, and a missing Escape test. Skipped: a
static name for the code toggle, which would break label-in-name for
`.show_code()`; and a "missing" edit-cancel test that already exists.

https://claude.ai/code/session_01H7HSkGyea1k2v293XiAMo8

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants