From c0169c23e4a0abc5567c726c0065a74b6812dc37 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 4 Nov 2026 02:11:50 -0800 Subject: [PATCH 1/2] fix(v2): CodeRabbit's last points on #3373 and #3381: the bar key's hit area, folded code fences, the clamp's box orient #3373 and #3381 were already in the merge queue when CodeRabbit raised these, so they land here. - Agent profile public bar: #3373 drew the Sign up key at 28, and its phone hit area still reached 5px each way, 38 in all. It now reaches 8 (28 + 16 = 44). A guard computes the reach from the last inset. - Activity plainLine: an agent post arrives with its newlines folded, so the fence's info-string match ran to the end of the text, and `Before ```js code ``` after` read "Before". The info string is now a bare word, and tests in the folded shape cover it. - The two-row clamp's guard pins `-webkit-box-orient: vertical`, which the prefixed clamp needs. - Connect: the translated intro is asserted on the rendered zh-CN page, not only in source. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MDs9DT6tbhKm6UhsmFhLk9 --- frontend/src/v2/__tests__/V2ActivityPage.test.tsx | 3 +++ frontend/src/v2/__tests__/V2ConnectPage.test.tsx | 2 ++ .../src/v2/__tests__/v2-layout-invariants.test.ts | 11 +++++++++++ frontend/src/v2/agents/v2-agent-profile.css | 2 ++ frontend/src/v2/components/V2ActivityPage.tsx | 3 ++- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/frontend/src/v2/__tests__/V2ActivityPage.test.tsx b/frontend/src/v2/__tests__/V2ActivityPage.test.tsx index cf0540fd39..5355a6b521 100644 --- a/frontend/src/v2/__tests__/V2ActivityPage.test.tsx +++ b/frontend/src/v2/__tests__/V2ActivityPage.test.tsx @@ -1706,6 +1706,9 @@ describe('V2ActivityPage', () => { // The shape agent posts arrive in: whitespace already folded by the recap. expect(plainLine('Done: - a - b - c ## Shipped **ok**')).toBe('Done: a - b - c Shipped ok'); expect(plainLine('```\nlog line\n```')).toBe('log line'); + // Folded, as agent posts arrive: the fence ends where its closing marks are, not at the end. + expect(plainLine('Before ```js code ``` after')).toBe('Before after'); + expect(plainLine('```sh npm test```')).toBe('npm test'); expect(plainLine('中_文_字 and __init__.py stay')).toBe('中_文_字 and __init__.py stay'); const link = `${'y'.repeat(160)} see [the doc](https://example.com/aaaaaaaaaaaa`.slice(0, 180); expect(plainLine(link)).toMatch(/ see the doc…$/); diff --git a/frontend/src/v2/__tests__/V2ConnectPage.test.tsx b/frontend/src/v2/__tests__/V2ConnectPage.test.tsx index 05eba8cb56..2e361ad667 100644 --- a/frontend/src/v2/__tests__/V2ConnectPage.test.tsx +++ b/frontend/src/v2/__tests__/V2ConnectPage.test.tsx @@ -164,6 +164,8 @@ describe('V2ConnectPage in zh-CN', () => { expect(container.querySelector('.v2-connect__rule .v2-connect__code-head > span')) .toHaveTextContent(`Cursor 规则 · 在项目中保存为 ${CURSOR_PROJECT_RULE_PATH}`); expect(container.querySelector('.v2-connect__cursor')).toHaveTextContent('在 Cursor 的 MCP 设置里填入你的智能体密钥。'); + // The intro line that replaced the head's hint renders translated, not just present in source. + expect(container.querySelector('p.v2-connect__intro')).toHaveTextContent('MCP 用的是接入时创建的智能体密钥。'); expect(chrome.join('\n')).not.toMatch(/\b(Copy|Copied|Connect|Manage|Add|Set up|Open|Instance keys|save as)\b/); fireEvent.click(screen.getAllByRole('button', { name: '复制' })[0]); expect(await screen.findByRole('button', { name: '已复制' })).toBeInTheDocument(); diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts index c3a50b30c1..74688ad239 100644 --- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts +++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts @@ -6133,6 +6133,16 @@ describe('secondary pages on the reference grammar (ui-audit-1104 findings 2–8 expect(css.lastIndexOf('@media (max-width: 760px)')).toBeLessThan(css.indexOf('.v2-feature--aprofile .v2-aprofile__avatar-button::after')); }); + test('the public bar\'s keys (Sign up) reach 44px to touch on a phone: 28 drawn + 2 x 8', () => { + const css = read('../agents/v2-agent-profile.css'); + expect(ruleBody(css, '.v2-aprofile .v2-aprofile__btn')).toContain('height: 28px'); + const phone = css.slice(css.lastIndexOf('@media (max-width: 760px)')); + const hits = [...phone.matchAll(/\.v2-aprofile \.v2-aprofile__bar \.v2-aprofile__btn::before \{([^}]*)\}/g)].map((m) => m[1]); + // The last inset wins: its vertical reach must make 44 from 28. + const inset = hits.map((body) => body.match(/inset:\s*(-?\d+)px/)).filter(Boolean).pop(); + expect(28 - 2 * Number(inset?.[1])).toBeGreaterThanOrEqual(44); + }); + test('finding 6: the board header icon keys never shrink on a phone', () => { const phone = mediaBlockContaining(boardCss, '.v2-feature--board .v2-board__key--icon { flex: none; }'); expect(ruleBody(boardCss, '.v2-feature--board .v2-board__key--icon', { within: phone })).toContain('flex: none'); @@ -6197,6 +6207,7 @@ describe('Activity built to the d215 signal frames (#s-activity-signal)', () => const text = rule('.v2-activity__moved-text'); expect(text).toContain('-webkit-line-clamp: 2'); expect(text).toContain('display: -webkit-box'); + expect(text).toContain('-webkit-box-orient: vertical'); expect(text).toContain('overflow: hidden'); }); diff --git a/frontend/src/v2/agents/v2-agent-profile.css b/frontend/src/v2/agents/v2-agent-profile.css index 4b78418d93..b8c1b4cf1d 100644 --- a/frontend/src/v2/agents/v2-agent-profile.css +++ b/frontend/src/v2/agents/v2-agent-profile.css @@ -156,6 +156,8 @@ .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn { position: relative; } .v2-aprofile .v2-aprofile__navlink::before, .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn::before { content: ''; position: absolute; inset: -5px -6px; } + /* The bar key draws at the v2p small key's 28, so its hit area reaches 8px each way: 44. */ + .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn::before { inset: -8px -6px; } .v2-aprofile .v2-aprofile__navlink::before { inset: -14px -7px; } .v2-aprofile .v2-agent-settings__tabs > * { box-sizing: border-box; min-height: 44px; display: inline-flex; align-items: center; } .v2-aprofile .v2-aprofile__pod-remove { height: 44px; line-height: 44px; } diff --git a/frontend/src/v2/components/V2ActivityPage.tsx b/frontend/src/v2/components/V2ActivityPage.tsx index 8765747710..97c3e15793 100644 --- a/frontend/src/v2/components/V2ActivityPage.tsx +++ b/frontend/src/v2/components/V2ActivityPage.tsx @@ -167,7 +167,8 @@ const RECAP_CLIP = 180; export const plainLine = (value: string): string => { const clipped = value.length >= RECAP_CLIP; const fold = (text: string) => text.replace(/\s+/g, ' ').trim(); - const fence = /```[^\n]*\n?([\s\S]*?)(?:```|$)/g; + // The info string is a bare word (js, ts, sh), so a folded post's fence keeps the text after it. + const fence = /```[\w+-]*[ \t]*\n?([\s\S]*?)(?:```|$)/g; const prose = value.replace(fence, ' '); let text = (fold(prose) ? prose : value.replace(fence, ' $1 ')) .replace(/!?\[([^\]]*)\]\([^)]*\)/g, '$1'); From 005c7b740295dba666c138c7ca7b804854ff97ef Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Wed, 4 Nov 2026 02:16:59 -0800 Subject: [PATCH 2/2] fix(v2): the bar key's overlay measures from inside its border, so it reaches 9px to make 44 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the review of #3382: the key is drawn at 28 with a 1px border, and an absolute ::before measures from the padding box (26). So -8px gave 42 in Chromium, and the old -5px gave 36, not 38. It now reaches 9px each way: 26 + 18 = 44. Measured at 390 in light and dark, the hit area is 44.5 tall and both ±21 points land on Sign up. The guard now subtracts the border, and it fails at -8. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MDs9DT6tbhKm6UhsmFhLk9 --- frontend/src/v2/__tests__/v2-layout-invariants.test.ts | 9 ++++++--- frontend/src/v2/agents/v2-agent-profile.css | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts index 74688ad239..10acb301fe 100644 --- a/frontend/src/v2/__tests__/v2-layout-invariants.test.ts +++ b/frontend/src/v2/__tests__/v2-layout-invariants.test.ts @@ -6133,14 +6133,17 @@ describe('secondary pages on the reference grammar (ui-audit-1104 findings 2–8 expect(css.lastIndexOf('@media (max-width: 760px)')).toBeLessThan(css.indexOf('.v2-feature--aprofile .v2-aprofile__avatar-button::after')); }); - test('the public bar\'s keys (Sign up) reach 44px to touch on a phone: 28 drawn + 2 x 8', () => { + test('the public bar\'s keys (Sign up) reach 44px to touch on a phone', () => { const css = read('../agents/v2-agent-profile.css'); expect(ruleBody(css, '.v2-aprofile .v2-aprofile__btn')).toContain('height: 28px'); + // Both bar keys carry a 1px border, and an absolute ::before measures from the padding box, + // so the overlay starts from 26, not 28 (measured in Chromium: -8px gave 42). + expect(ruleBody(css, '.v2-aprofile .v2-aprofile__btn--primary')).toContain('border: 1px solid'); const phone = css.slice(css.lastIndexOf('@media (max-width: 760px)')); const hits = [...phone.matchAll(/\.v2-aprofile \.v2-aprofile__bar \.v2-aprofile__btn::before \{([^}]*)\}/g)].map((m) => m[1]); - // The last inset wins: its vertical reach must make 44 from 28. + // The last inset wins: its vertical reach must make 44 from the 26px padding box. const inset = hits.map((body) => body.match(/inset:\s*(-?\d+)px/)).filter(Boolean).pop(); - expect(28 - 2 * Number(inset?.[1])).toBeGreaterThanOrEqual(44); + expect(28 - 2 - 2 * Number(inset?.[1])).toBeGreaterThanOrEqual(44); }); test('finding 6: the board header icon keys never shrink on a phone', () => { diff --git a/frontend/src/v2/agents/v2-agent-profile.css b/frontend/src/v2/agents/v2-agent-profile.css index b8c1b4cf1d..2b9bc2d661 100644 --- a/frontend/src/v2/agents/v2-agent-profile.css +++ b/frontend/src/v2/agents/v2-agent-profile.css @@ -156,8 +156,9 @@ .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn { position: relative; } .v2-aprofile .v2-aprofile__navlink::before, .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn::before { content: ''; position: absolute; inset: -5px -6px; } - /* The bar key draws at the v2p small key's 28, so its hit area reaches 8px each way: 44. */ - .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn::before { inset: -8px -6px; } + /* The bar key draws at the v2p small key's 28 with a 1px border, and an absolute overlay + measures from inside the border (26), so it reaches 9px each way: 26 + 18 = 44. */ + .v2-aprofile .v2-aprofile__bar .v2-aprofile__btn::before { inset: -9px -6px; } .v2-aprofile .v2-aprofile__navlink::before { inset: -14px -7px; } .v2-aprofile .v2-agent-settings__tabs > * { box-sizing: border-box; min-height: 44px; display: inline-flex; align-items: center; } .v2-aprofile .v2-aprofile__pod-remove { height: 44px; line-height: 44px; }