fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(tool-trow): stabilize concurrent tool summary and settle seam - #721

Merged
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary
Jul 11, 2026
Merged

fix(tool-trow): stabilize concurrent tool summary and settle seam#721
Astro-Han merged 5 commits into
mainfrom
fix/tool-trow-stable-summary

Conversation

@Astro-Han

Copy link
Copy Markdown
Contributor

Summary

Concurrent (parallel) tool calls made the trow jitter badly: the summary line cycled through each tool's description as tools started/finished (the "1234567" jump), and when parallel results returned together, N per-row opacity-0→1 settle fades stacked into a big shake.

Why

Refs #546 (Phase B PR6 tool rendering polish), #646 (real-time status language — tool run→done seam). Manual testing flagged parallel tool execution as a poor experience.

Scope

  • summary aggregation: multi-tool running shows the whole-group bucket + "正在"("正在读取 7 个文件,搜索 2 次")instead of the active tool's description; counts the whole group (incl. settled) so it doesn't decrement as tools finish in batches. Single-tool keeps the tool's description (existing tests lock it). Running omits the failed count (it changes mid-group); errored tools still force-open their disclosure.
  • row settle = light-band stop: a row settles by its shimmer stopping (same seam as the 深度思考 disclosure title), no opacity fade — parallel tools finishing together each just drop their light band instead of stacking N opacity-0→1 fades. Removes the now-dead deriveToolRowMotion / ToolRowMotion and the two contract tests that locked the removed behavior; isToolRowRunning / isToolRowSettled stay.

Not included (tracked separately under #546 Phase B/C):

  • single→multi structure jump (ToolCardBodyToolTrowRow list)
  • merging trows split by interleaved text/thinking (overlayLiveTurn step regroup)
  • artifact preview / browser panel polish
  • whole-group summary "正在 X"→"X" as a true cross-fade (current opacity fade-in is single + non-stacking, good enough)

Verification

  • npm run -w @maka/ui test — 101 pass, 0 fail (new tool-trow-summary.test.ts: running aggregation + whole-group count; existing presentation/stability tests green).
  • npm run -w @maka/desktop test — 2310 pass, 0 fail (updated tool-row-motion.test.ts keeps the isToolRowRunning/isToolRowSettled classification; removed the two settle-fade tests that locked the removed behavior).
  • npm run typecheck — clean across all workspaces.
  • CDP on the running dev build (Playwright connectOverCDP): injected the post-change ToolTrow running render, confirmed the summary shows "正在读取 2 个文件", the maka-text-shimmer keyframe runs (animationPlayState: running) with adequate light-band vs base contrast across light + dark themes (catppuccin-mocha / nord / tokyo-night / mono) — so "shimmer seems missing" was the pre-change summary jitter breaking the sweep's continuity, not a contrast/keyframe fault.

User-facing impact

Concurrent tool calls no longer make the summary line jump through each tool's description, and parallel results returning together no longer stack N settle fades into a shake. The working signal stays the 深度思考-style light band, now continuous because the summary text is stable. No schema, migration, or config changes.

Reviewer notes

  • The group summary keeps its own one-shot settle fade (SETTLE_FADE) as the whole-group signal; only the per-row fade is removed, so a batch settle is N light bands dropping, not N fades stacking.
  • Single-tool running keeps the tool's description (existing tests lock it, and "what exactly is running" is useful when there's one); only multi-tool running aggregates. This is an intentional asymmetry, not a missed case.
  • deriveToolRowMotion / ToolRowMotion removed as dead code (the row no longer tracks everRunning; the group computes its own settled/settling). The two desktop contract tests that locked the removed fade-gating behavior are removed; the classification tests stay.
  • The "shimmer seems missing" report was investigated over CDP: keyframe + class + contrast are all correct, so no shimmer change was made; the summary-stabilization fix is what makes the sweep read as continuous.

Checklist

  • Scope matches the PR title and excludes unrelated changes
  • Verification lists commands/results, or explains why they were not run
  • User-facing impact, docs, changelog, migrations, and breaking changes are noted, or marked none
  • Risk, rollback, or review focus is called out for non-trivial changes
  • UI changes include screenshots/video, or explain why not applicable — behavior verified via CDP measurement (computed styles + rendered summary); no new static layout to screenshot — the change is dynamic (summary text stability + settle motion)

… jitter
A multi-tool running trow showed the active tool's description as the summary
line, cycling through each tool's intent as tools started/finished in parallel
— the 1234567 jitter. Switch to the whole-group bucket aggregation with a
"正在" prefix (e.g. "正在读取 7 个文件,搜索 2 次"), counting the whole group
including settled tools so the summary does not decrement as tools finish in
batches. Single-tool rows keep the tool's own description (locked by existing
tests, and the "what exactly is running" signal is useful when there is one).
Running summary omits the failed count (it changes mid-group as tools error);
errored tools still force-open their disclosure (trowNeedsAttention), so the
failure signal is not lost — it just stops jittering the summary line.
…tack
A tool row settled with a one-shot opacity-0→1 fade (SETTLE_FADE). When
parallel tools finished together, N fades stacked into the 1234567 jitter.
The row now settles by its shimmer stopping — the same seam as the 深度思考
disclosure title (light band → static muted text), no opacity fade — so a
batch settle is N light bands dropping, not N fades stacking.
Removes the now-dead deriveToolRowMotion / ToolRowMotion (the group summary
keeps its own settle fade as the whole-group signal; the row no longer tracks
everRunning) and the two settle-fade contract tests that locked the removed
behavior. isToolRowRunning / isToolRowSettled stay (the row still uses them).
…review)
Addresses Codex review findings on #721.
P3 — the group summary icon still picked the active tool's kind, so a
mixed-kind group (e.g. Read running + Grep running) flipped its icon as the
active tool changed mid-run even though the aggregated summary text never
moved. The icon now stays on the first bucket's kind (the same first-seen order
the summary clauses use), so the whole summary row is stable.
P2 — adds the contracts the prior commits lacked:
- summarizeTrowTools({ live: true }) omits the failed count (it changes
mid-group); settled includes it.
- rendered rows never carry the settle-fade animation (the per-row seam is a
light-band stop). A full running→settled rerender contract needs dynamic test
infrastructure packages/ui lacks; this static contract locks the rendered
output and the rerender case is tracked separately.
…JSDoc (re-review)
Addresses Codex re-review findings on #721.
P2 — the prior row no-fade test only did a terminal first-mount SSR, so the old
everRunning-gated fade implementation also passed it; it didn't lock the real
running→settled regression. Replace it with a source contract over
tool-activity.tsx: the row never reintroduces the per-row settle fade
(SETTLE_FADE stays at 2 — the group summary's define + use) or the motion
abstraction (deriveToolRowMotion / motion.* / settleFade). The full dynamic
running→settled rerender contract is still tracked separately (packages/ui has
only renderToStaticMarkup).
P3 — two JSDoc blocks in trow-summary.ts no longer matched the behavior:
summarizeTrowTools now has a { live } mode (running "正在" prefix + suppressed
failed count), and activeTrowTool's description drives the shimmering summary
only for a single-tool group (multi-tool uses the aggregation). Updated both.
…r (review P3)
The multi-tool summary aggregates the whole group, the group icon follows the
first bucket, and disclosure attention is overridden by the whole-group
trowNeedsAttention — so ToolTrowGroup's active-tool lookup had no remaining
effect (a single-tool group's active tool is items[0] anyway). Replace it with
firstPresentation = deriveToolActivityPresentation(items[0]!), used for the
icon, the single-tool summary, and the disclosure base. Removes the now-unused
activeTrowTool helper, its barrel export, and the activeTrowTool assertions in
the desktop trow-summary test (the isTrowRunning classification tests stay).
No behavior change: single-tool active === items[0], and the multi-tool path
never read activePresentation.summary/needsAttention.
@Astro-Han
Astro-Han merged commit 7c41ea0 into mainJul 11, 2026
3 checks passed
@Astro-Han
Astro-Han deleted the fix/tool-trow-stable-summary branch July 11, 2026 12:01
Sign up for freeto 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.

1 participant

@Astro-Han