Skip to content

fix(console): bound the long-name check so joiner runs can't hang the Agents list - #2926

Merged
freeqaz merged 6 commits into
mainfrom
ux-fixes-129-regex
Oct 19, 2026
Merged

freeqaz merged 6 commits into
mainfrom
ux-fixes-129-regex

Conversation

@freeqaz

@freeqaz freeqaz commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The long-name rule from #2916 (UNBROKEN_RUN in apps/controller/src/console/agents/list.mjs) backtracks exponentially on names built from word-joiner (U+2060) or zero-width-joiner (U+200D) runs (finding 1999, medium).

  • Its joiner alternative matched any character before a joiner. That overlapped the plain-character alternative, and also the hyphen and wide-space/dash alternatives, because CLOSING lists the joiners. It also let a combining mark start a run character of its own.
  • Each overlap doubles the number of ways to split a run, so every failing {21,} attempt explored about 2^20 paths. One check of a 210-character name took 10.7 s in Node.
  • In the console, each search keystroke that kept such an Agent listed blocked the page for about 2.5 s; this PR's browser test measured 5 s on main.
  • Anyone who can create an Agent could freeze the Agents list for every viewer, on load and on every keystroke.

Change

  • Restrict the joiner alternative to ideographs and emoji ([${IDEOGRAPHIC}](?=\p{M}*[\u2060\u200d])). Those are the only characters it added; every other character a joiner holds is already counted by another alternative. No character now matches two alternatives, and no combining mark can start one, so the check is linear.
  • One side effect matches Chromium better: a combining mark before a joiner shares its letter's place instead of counting as a character. "e\u0301\u2060" x 10 was marked on main, but Chromium lays it out as a run of 20. Two measured rows pin this.
  • Export hasUnbrokenRun(name), so a Node test can time the rule directly.
  • U+16FE4 (Khitan small script filler) is both an ideograph and a combining mark, so the joiner alternative also skips marks ((?!\p{M})). A scan of every code point, with each neighbour shape the rule looks at, finds no character that matches two alternatives and no combining mark that starts one.
  • Internal review found one remaining, bounded overlap: a hyphen-minus before an Arabic-Indic digit with no letter or digit before it matched both hyphen-minus alternatives. The "-5" alternative now leaves those digits to the line above it. Marking is unchanged.

Verification

  • New tests/conformance/console-agent-name-runs.test.mjs (mapped to Checks and Conformance 1):

    • Eleven worst-case names (joiner runs, hyphen-minus before Arabic-Indic digits, and U+16FE4 marks before word joiners), including the bughunt's 210-character probe and a 1,050-character name, each classify in under 50 ms. With the fix, each takes under 2 ms after the first (about 6 ms, JIT warm-up). On main every one fails (1.0 to 12.3 s each), and the combining-mark name is mis-marked.
    • On the previous head, a + 18 U+16FE4 + U+2060, six times, took 3.65 s; now 4 ms.
    • A positive-control test shows that joiners still hold the character before them (ideograph, hyphen, en dash, thin space, letter with a mark). Two U+16FE4 rows pin its count; Chromium measures them as runs of 2 and 21.
  • New browser test Agents list search stays responsive with joiner-run names (console-agents-list-return.test.mjs): two 196-character joiner-run Agents are listed, and each search keystroke must finish its synchronous re-render in under 250 ms. On main the first keystroke blocked for 4,971 ms.

  • Agents list marks names with no break opportunity... gains two measured rows (combining mark before a joiner, run of 20 unmarked and 21 marked). On main it fails ("marked"). All 32 fix(console): match Chromium's break points for long Agent names #2916 rows still pass, and each is still checked against Chromium's own layout.

  • Pinned at 2 CPUs (taskset -c 12,13) on head 82c4317:

    • the two touched browser tests, 20/20;
    • the conformance file, 20/20;
    • the full console-agents-list-return.test.mjs, 19/19.
  • Old-versus-new differential on 40,000 random short names over the rule's special characters: no difference outside the combining-mark case.

  • Random and periodic 200-character names under the new rule: the slowest took 4 ms (JIT warm-up).

  • Prettier and ESLint are clean on the touched files. run-tests.mjs audit reports no issues.

  • Conflicts with open PRs (3-way git merge-tree against this head, compared with origin/main): no new conflict hunk.

  • Storybook: new story Pages/Agents → Long name of word-joiner runs (agentsLongNameJoiners), a 196-character joiner-run name found by a search, with a step to type the search one letter at a time. On the fixture frame, each keystroke's synchronous handling took 0.4-0.6 ms at 1440 and 390.

UX follow-up to bughunt-127 (finding 1999). Ordinary names look the same.

Risks

Low. The change narrows two regex alternatives and adds tests. The only behaviour change is the combining-mark-before-joiner case, and that now matches Chromium.

… Agents list

The joiner alternative of UNBROKEN_RUN matched any character before a word
joiner or zero-width joiner, overlapping the plain-character, hyphen and
wide-space/dash alternatives (CLOSING lists the joiners) and letting a
combining mark start a run character. Each overlap doubled the ways to split
a run, so a failing test of a joiner-run name backtracked exponentially:
10.7 s for one 210-character name, about 2.5 s per search keystroke in the
console (finding 1999).

Restrict the joiner alternative to ideographs and emoji, the only characters
it added. The rule is now linear (under 1 ms on the bughunt payloads, 1,050
characters included). A combining mark before a joiner no longer counts as a
character of its own, which matches Chromium's measured layout.

Tests: a conformance test bounds the check at 50 ms on worst-case joiner
names (10.7 s on main); a browser test times search keystrokes with
joiner-run Agents listed (5 s per keystroke on main); two measured rows pin
the combining-mark case.
@freeqaz
freeqaz requested a review from a team as a code owner October 19, 2026 10:55
@clawsweeper

clawsweeper Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

Internal review of the bound: a hyphen-minus before an Arabic-Indic digit, with
no letter or digit before it, still matched two alternatives (bounded, about
2^7 per start, but against the rule's own comment). The "-5" alternative now
leaves those digits to the line above, and the conformance test times that
shape too.
@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. labels Oct 19, 2026
@clawsweeper

clawsweeper Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

What this changes

This PR removes overlapping regex alternatives that make certain Agent names stall list rendering and search.

Example: Search for an Agent named "Joiners " followed by nine space-separated groups of 20 U+2060 word joiners, totaling 196 characters.

  • Before: The contributor reports that the browser regression test measured a 4,971 ms stall on the first search keystroke.
  • After: The alternatives no longer overlap, and the browser regression requires each search update to finish within 250 ms.

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) The focused repair and regression coverage are sound, with both earlier findings resolved; the repository's native visual-evidence requirement remains outstanding.
Proof confidence 🦐 gold shrimp (3/6) Real behavior proof is not required for maintainer- or bot-authored pull requests.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: Opening or searching the Agents list can freeze the page when an Agent name contains repeated joiners.
Reason: The maintainer-authored repair restores responsive rendering without adding configuration, changing platform contracts, or expanding scope.

Regression provenance

Possible regression — suspected (reviewed change). No predecessor PR is attributed.

Merge readiness

✅ Ready for maintainer review

This PR addresses a current Agents-list freeze, resolves both prior findings, and introduces no further identified code defect.

Priority: P2
Reviewed head: 2bfd0123f3466d3317c71da3f71df20f1da4c98a

Before merge

None.

Findings

None.

Tests

  • Missing end-to-end proof: Attach the supplied screenshots and search walkthroughs as native GitHub media; the reported base-versus-head browser regression was inspected in source but not rerun.
Agent review details

How this fits together

The console classifies each displayed Agent name during list rendering and synchronous search updates, then applies a CSS class when the name needs additional wrapping.

flowchart LR
A[Agent names] --> B[Agents list render]
C[Search input] --> B
B --> D[Unbroken run classification]
D --> E[Wrapped name link]
Loading

Technical review

Best possible solution:

Keep the focused classifier repair and its browser and adversarial-name regression coverage.

Do we have a high-confidence way to reproduce the issue?

Current main contains overlapping alternatives inside repeated matching, and the contributor supplies a supported 196-character browser scenario with before-fix measurements; no target code was executed during this review.

Is this the best way to solve the issue?

The repair removes the matching ambiguity at its existing owner while retaining Chromium-based wrapping behavior, including the previously missed ideographic combining mark.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against b10157ca98de.

Provenance checked

  • Agent-name classification keeps the original intent (cf2cc2e: Match Chromium's measured wrapping opportunities while retaining joined ideographs and emoji.)
  • Agent-name rendering keeps the original intent (d717962: Prevent unbreakable names from widening the desktop Agents table and hiding other columns.)

Testing

Proof path: in-process harness.

Security

None.

Evidence

What I checked:

  • Focused repair: The introduced diff narrows the joiner branch to non-mark ideographic characters and makes the Arabic-Indic hyphen alternatives exclusive; the existing rendering owner remains responsible. (apps/controller/src/console/agents/list.mjs:293, 2bfd0123f346)
  • Previous findings resolved: Compared with the previous reviewed head, the patch adds the combining-mark exclusion and U+16FE4 regressions; the requested joiner-run Storybook scenario and search instructions are also present. (tests/conformance/console-agent-name-runs.test.mjs:21, 2bfd0123f346)
  • Original behavior and ownership: The merged change at fix(console): match Chromium's break points for long Agent names #2916 intentionally follows measured Chromium wrapping, including joined ideographs; this repair preserves that purpose while removing ambiguous matching. (apps/controller/src/console/agents/list.mjs:287, cf2cc2ec3c77)
  • Meaningful browser regression: The added browser case creates supported Agent records through the existing console fixture, opens the real console, and measures synchronous search handling without replacing the classifier. (tests/browser/console-agents-list-return.test.mjs:1037, 2bfd0123f346)
  • Repository visual-evidence requirement: Desktop and phone screenshots were inspected successfully, but the PR links media committed at an earlier revision rather than the native GitHub attachments required by repository policy. (AGENTS.md:455, 2bfd0123f346)
  • Inspection limitations: Prepared video decoding failed with "ffprobe failed: spawnSync ffprobe ENOENT"; browser fallback preparation failed because the supplied scratch directory was read-only. Older creation blobs were unavailable locally, but relevant classifier history and the complete introduced diff were readable. (2bfd0123f346)

Likely related people:

  • Free Wortley: Raw commit cf2cc2e adds apps/controller/src/console/agents/list.mjs:270 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: cf2cc2ec3c77; files: apps/controller/src/console/agents/list.mjs)
  • kevinlin-openai: Raw commit 835b1cc adds apps/controller/src/console/agents/list.mjs:32 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: medium; commits: 835b1cc9b775; files: apps/controller/src/console/agents/list.mjs)

Review metrics

Metric Value Why it matters
Production and regression scope Production +14/-5 lines; regression tests +98 lines The additional tests cover browser responsiveness, distinct overlapping alternatives, and combining-mark classification.

Labels

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.
  • remove proof: 📸 screenshot: Current real behavior proof evidence kind is not_applicable.

Label justifications:

  • P2: Valid but unusual Agent names can repeatedly stall the console list and search; the affected surface is limited to that browser workflow.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (2 earlier review cycles)
  • reviewed 2026-10-19T11:16:02.064Z sha 82c4317 :: needs changes before merge. :: [P3] [P3] Add the joiner-run search case to the Agents stories
  • reviewed 2026-10-19T11:24:20.793Z sha 607ee42 :: blocked before merge. :: [P2] Exclude combining marks from the ideographic joiner branch

Reviewed October 19, 2026, 7:32 AM ET / 11:32 UTC (Revision 3).

…through

Review request: Pages/Agents gains a 196-character name of word-joiner runs,
found by a search, with steps to type the search one letter at a time.
@freeqaz

freeqaz commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. labels Oct 19, 2026
…lternative

U+16FE4 is both Ideographic and a combining mark, so it could start the
ideograph-before-joiner alternative and also ride a previous character's
trailing marks. A name of 'a' + 18 such marks + U+2060, repeated, took
3.6 s to classify. Skip marks in that alternative; a scan of every code
point now finds no character that matches two alternatives and no mark
that starts one. Chromium measures the two new positive-control names as
runs of 2 and 21, which the rule now matches.
@freeqaz

freeqaz commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator Author

Free's clanker here. Addressed the U+16FE4 finding in 2bfd012: the ideograph-before-joiner alternative now skips combining marks, and a scan of every code point finds no remaining overlap or mark-started alternative. The payload from the review (and a 10-segment version) now classifies in a few ms, with conformance rows pinning it (Chromium measures runs of 2 and 21, which the rule matches).

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
Exact review queued.

Re-review progress:

@clawsweeper clawsweeper Bot added clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Oct 19, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. clawsweeper:intake:bug Preliminary submission classification; full source review pending. clawsweeper:intake:needs-environment Preliminary submission classification; full source review pending. labels Oct 19, 2026
@freeqaz
freeqaz merged commit e7c2e6b into main Oct 19, 2026
73 of 74 checks passed
@freeqaz
freeqaz deleted the ux-fixes-129-regex branch October 19, 2026 11:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant