Commit Graph
6 Commits
Author SHA1 Message Date
Kevin Meinon be5ee8f503 perf(composer): make the single-row autoResize fast path reachable (long-session typing lag) (#7604)
* perf(composer): make the single-row autoResize fast path reachable

autoResize() skips the height:'auto' -> scrollHeight -> restore round trip only
when the composer is already at its one-row height, but the guard compared
el.offsetHeight against the CSS min-height (44px) while the composer's natural
one-row border box is line-height + vertical padding + borders (~48px at the
stock font). 48 <= ceil(44)+1 is false, so the skip was unreachable in a real
browser: every append keystroke wrote style.height twice, and the scrollHeight
read that follows forces a synchronous layout of the whole document, transcript
included. The cost therefore grows with the rendered transcript, which is the
"typing gets laggy in long sessions" report.

Accept the natural one-row height as the skip ceiling, computed from the same
already-read getComputedStyle. The strict finite-pixel gate is kept for every
value involved, so a percentage / calc / normal line-height, padding or
min-height still fails closed to the full resize (the #6349 re-gate property is
preserved, and test_issue5514_composer_grow_scroll_pin.py still pins it).

Measured on a 758-message / 5 MB session (31k DOM nodes rendered) with the
browser Event Timing API (input -> next paint) at 6x CPU throttle: a keystroke
went from 168ms to ~136ms median echo latency (72ms with the transcript
detached), 96ms to ~72ms in the windowed state, and the style writes per 8
keystrokes from 16 to 2.

The #5514 invariant holds: an oversized composer still takes the full resize
because its offsetHeight is far above the one-row ceiling.

Tests:
- new tests/test_long_session_composer_typing_latency.py runs the real
  autoResize() body from messages.js in a node sandbox whose getComputedStyle
  returns the composer's computed styles; it is red before this change
  (2 failed, 27 passed) and green after (29 passed).
- tests/test_issue5514_composer_grow_scroll_pin.py source pins updated to the
  new guard shape.

* test(docs): address #7604 review - behavior-only tests + composer sizing docs

Review feedback on the PR flagged two repo-rule items: tests that pin source
strings, and an undocumented runtime behavior change. Both are addressed here.

- tests/test_long_session_composer_typing_latency.py: delete
  test_fix_is_pinned_in_source. It asserted exact JS declarations, which the
  repo testing guidance rejects and which the harness in this module already
  covers by executing the REAL autoResize() body. In its place add
  test_natural_row_skip_survives_every_append_of_a_typed_word, which drives the
  actual typing loop ('' -> 'h' -> ... -> 'hello') and asserts zero height
  writes on every keystroke. Red on the pre-fix tree, green with the fix.
- tests/test_issue5514_composer_grow_scroll_pin.py: convert
  test_single_line_growth_skips_the_height_round_trip from source-string pins to
  a behavior fixture whose getComputedStyle returns the composer's real computed
  styles. It asserts the observable outcome: a one-row append at the natural
  48px row takes no height write, while an oversized 176px composer still
  remeasures back to one row. Red before the fix (2 writes), green after.
- docs/UIUX-GUIDE.md: document the composer sizing invariants in the composer
  section - the single-row skip is a hot path and must stay reachable, its
  ceiling is the natural one-row height or the CSS min-height (whichever is
  larger), everything else still remeasures, and non-px computed values fail
  closed.

./scripts/test.sh on the two touched modules: 29 passed (3 failed on the
pre-fix tree). Neighbour sweep over the 51 composer/scroll/typing modules:
386 passed. ruff check clean.

* fix(tests,docs): derive composer test dimensions from style.css (#7604 review)

Greptile's re-review is right: the fixtures hardcoded the 18px
`data-font-size=large` composer (line-height 29.7px -> a 47.7px one-row box) as
if it were the stylesheet's 16px default (44.4px). At the default the pre-fix
ceiling (ceil(44)+1 = 45px) DID clear the one-row box, so the regression is
font-size dependent - the 16px default reaches the skip, the 18px and 20px
appearance settings do not - and not a stock-configuration bug. The runtime
change is unaffected and unchanged.

- new `tests/_composer_metrics.py`: parses `static/style.css` (the base
  `textarea#msg` rule, the `data-font-size` overrides, the skin overrides) and
  exposes each configuration's box metrics - natural one-row height, the integer
  offsetHeight a browser reports, and both the pre-fix and post-fix ceilings -
  so a fixture cannot encode the wrong font size again.
- `tests/test_long_session_composer_typing_latency.py`: parameterized over every
  configuration the stylesheet can produce, with
  `test_the_regression_was_font_size_dependent_not_stock` pinning the grounding.
- `tests/test_issue5514_composer_grow_scroll_pin.py`: the converted single-row
  test uses the same derived metrics.
- `docs/UIUX-GUIDE.md`: the sizing section now states that the natural row
  tracks the appearance font size (44 / 48 / 51px) while `min-height` stays
  44px, which is why a min-height-only ceiling silently disables the skip.

Pre-fix tree: `4 failed, 31 passed` - exactly the large-18px and xlarge-20px
parameterizations plus the two tests that assert the reported configuration.
Post-fix tree: `35 passed`. Neighbour sweep over the 51 composer/scroll/typing
modules: `392 passed`. ruff clean.
2026-09-16 07:38:43 -07:00
starship-sandnesquena-hermes 1480718767 feat(typography): establish three-font contract (#5918)
* feat(typography): establish three-font contract

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: OpenCode:gpt-5.3-codex-spark
Assisted-by: Claude Code:claude-opus-4-8
Assisted-by: Codex:gpt-5.3-codex-spark

* fix(terminal): refit after live font changes

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: OpenCode:gpt-5.3-codex-spark
Assisted-by: Claude Code:claude-opus-4-8

* docs(typography): preserve global serif guardrail

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Claude Code:claude-opus-4-8

* fix(typography): enforce font tokens in rendered editors

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.3-codex-spark

* fix(terminal): resync after stylesheet font changes

Observe live extension stylesheet changes and completed stylesheet loads so open terminals refresh font metrics and backend dimensions.

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.3-codex-spark
Assisted-by: Greptile:undisclosed

* test(typography): remove dynamic harness execution

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.3-codex-spark
Assisted-by: nesquena-hermes:undisclosed

* test(typography): skip missing Playwright browser

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-luna
Assisted-by: nesquena-hermes:undisclosed

* fix(terminal): refit after web fonts load

Assisted-by: Hermes Agent:gpt-5.6-sol
Assisted-by: Codex:gpt-5.6-luna
Assisted-by: Greptile:undisclosed

---------

Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com>
2026-08-08 22:40:21 +00:00
e3a7c93dc6 [HELD — independent review pending] Release v0.51.294 — stage-3401 (live-to-final redesign #3401 + 4 deep-review fixes) (#3741)
* Harden interrupted recovery control filtering

* Redesign live-to-final assistant replies

* Fix live activity anchor test fixture

* Fix CI lint issues for live reply tests

* Strengthen live progress prompt contract

* Recover PR #3401 refresh on origin/master

* Repair live-to-final refresh regressions

* Fix live worklog refresh regressions

* Show live footer timer on initial stream start

* Restore live stream shell after reload

* Preserve per-frame live SSE replay cursors

* Preserve reasoning as Worklog Thinking cards

* Quiet Worklog Thinking card styling

* Align Worklog Thinking card styling

* Scope live Worklog Thinking cards by segment

* Suppress exact duplicate settled Thinking

* Close #3401 merge review test gaps

* fix(#3401): resolve 4 deep-review regressions (inline-think, reconnect-dup, neon skin, busy-gate worklog)

Deep review (Codex diff-vs-master + live-browser drive) of the live-to-final refactor
surfaced 4 regressions vs master that the rewritten suite no longer guarded:

1. Inline <think>…</think>answer reasoning vanished — _assistantReasoningPayloadText
   used $-anchored regexes so a leading think block + visible answer extracted nothing
   and the Thinking card never rendered. Removed the 3 $ anchors to match the
   (non-anchored) display stripper. Live: inline-think thinking-only turn now renders.
2. (CORE) reconnect/reload duplicated the live reply — _rememberRunJournalCursor advanced
   a closure-local seq but never wrote INFLIGHT[activeSid].lastRunJournalSeq, so a reload
   replayed the journal from after_seq=0 over restored lastAssistantText. Now mirrors the
   cursor onto INFLIGHT + schedules a throttled persist.
3. Neon skin silently broke — PR deleted the :root[data-skin="neon"] CSS but left Neon in
   the picker. Restored the neon CSS block from master.
4. Settled tool-worklog rebuild gated purely on !S.busy — dropped every prior settled
   turn's worklog when renderMessages re-ran during an active stream (switch-back to an
   in-progress session). Restored master's !S.busy || (S.toolCalls && S.toolCalls.length).
   Live: busy re-render now preserves tool cards (4→4, was 4→0).

Live-verified all 4 + confirmed #3709/#3592 invariants still hold (1 thinking card, none
below footer; distinct siblings preserved). + tests/test_issue3401_deep_review_fixes.py (7).

* test(#3401): realign 3 stale source-shape assertions to the deep-review fixes

Fix commit changed two source literals that existing stage tests scanned for:
- test_live_activity_timeline.py (x2): split anchor 'if(!S.busy){' → the restored
  'if(!S.busy || (S.toolCalls&&S.toolCalls.length)){' guard (fix 4).
- test_run_journal_frontend_static.py: 'after_seq=0' not in source — fix 2's comment
  contained that literal; rephrased the comment to 'the zero floor (after_seq of 0)'.
Intent of all three assertions unchanged; only the matched string updated. No code
behavior change.

* docs(changelog): v0.51.294 — Release JJ (stage-3401, #3401 live-to-final redesign)

---------

Co-authored-by: Frank Song <franksong2702@gmail.com>
Co-authored-by: Nathan-Hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: nesquena-hermes <[email protected]>
2026-06-06 12:12:37 -07:00
Frank Song 26fb71839e fix(chat): keep visible interim progress in timeline 2026-05-26 09:53:55 +08:00
Eleanor Berger 4598adfd04 feat: add Geist Contrast skin 2026-05-20 00:09:06 +00:00
nesquena-hermes 715017924c Stage 382: PR #2503 2026-05-18 03:45:42 +00:00