Skip to content

fix(ask): scroll ordinary question premises - #3687

Merged
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
snowykr:fix/ordinary-ask-scroll-title
Aug 1, 2026
Merged

fix(ask): scroll ordinary question premises#3687
Yeachan-Heo merged 1 commit into
Yeachan-Heo:devfrom
snowykr:fix/ordinary-ask-scroll-title

Conversation

@snowykr

@snowykr snowykr commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Problem

Fixes #3675. Ordinary ask dialogs did not opt into the existing bounded, scrollable question-title path. A long premise could leave the viewport with no PageUp/PageDown or Ctrl+U/Ctrl+D route to read it.

This is intentionally separate from #3684 native terminal-scrollback work. Keyboard paging moves only the question; the wheel and terminal scrollbar keep their transcript behavior.

Reproduction

  1. Open a normal ask with a premise longer than the available title area, including wrapped text in a narrow terminal.
  2. Before this change, scroll through the selector: early premise rows are unavailable.
  3. With this change, PageUp/PageDown and Ctrl+U/Ctrl+D expose every premise row without increasing the dialog beyond its viewport.

Scope and behavior

  • Enables the already-established scroll-title mode for ordinary ask; no new interaction model or public API is introduced.
  • Uses content-row paging so indicator rows never skip a premise row.
  • Preserves title position through timeout and Other/clarification input transitions, including a countdown repaint on the bottom page.
  • Keeps inline autocomplete ownership of PageUp/PageDown and retains the ordinary Ctrl+G external-editor hint.
  • Computes title/list budgets from wrapped base and inline-input footer heights, including 20-row / 19-column cases; reserves a bounded multiline editor and autocomplete menu at workable sizes, uses a compact literal-@ fallback when the dropdown itself cannot fit, and restores autocomplete after expansion. Budgets recompute in place on terminal resize without losing focus, input, or the semantically visible title premise. One-row option budgets retain a visible focused label, clipped windows retain an option-position marker, and one-row title view keeps the premise line intact rather than consuming it with an indicator.
  • Adds the required packages/coding-agent Unreleased changelog entry.

Direct HookSelector callers that do not request scrollTitleRows retain their previous behavior. No unrelated legacy-selector cleanup is included.

Regression coverage

  • Ordinary ask forwards scroll-title, outline, and wrap-focused settings.
  • Narrow wrapped premises stay within the viewport, all premise content is reachable, rendered rows fit the width, and one-row title views preserve each visited premise line.
  • Inline custom input covers autocomplete PageUp/PageDown, Ctrl+G, wrapped footer budgeting, bounded multiline drafts and an eight-item autocomplete list, the 20-row / 19-column compact literal-@ fallback plus autocomplete restoration after expansion, one-row focused-label visibility, title offset preservation after timeout reset, and 30→20-row terminal resize while preserving an active draft.
  • Timed bottom-page repaint, shrinking a title to one row, and wide↔narrow Markdown reflow retain the visible premise position.

Verification

bun test packages/coding-agent/test/hook-editor.test.ts packages/coding-agent/test/hook-selector-inline-input.test.ts packages/coding-agent/test/hook-selector-overflow.test.ts packages/coding-agent/test/tools/ask.test.ts
# 154 pass, 0 fail

bun --cwd=packages/coding-agent run check
# biome + TypeScript pass

git diff --check
# pass

Focused automated coverage exercises the rendering and input contracts. Physical interactive-terminal dogfooding was not run; exact-head CI remains required.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ddeffb02d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/controllers/extension-ui-controller.ts Outdated
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from ddeffb0 to e2d5983 Compare July 31, 2026 21:44

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2d5983659

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/controllers/extension-ui-controller.ts Outdated
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from e2d5983 to 0df947c Compare July 31, 2026 21:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0df947c3f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/controllers/extension-ui-controller.ts Outdated
Comment thread packages/coding-agent/src/modes/components/hook-selector.ts
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from 0df947c to 670df91 Compare July 31, 2026 22:27

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 670df91c4a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from 670df91 to a2d2789 Compare July 31, 2026 22:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a2d27892e4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from a2d2789 to 4fc61a2 Compare July 31, 2026 22:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fc61a2737

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/controllers/extension-ui-controller.ts Outdated
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from 4fc61a2 to e756566 Compare July 31, 2026 23:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7565665db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/components/hook-selector.ts Outdated
Comment thread packages/coding-agent/src/modes/controllers/extension-ui-controller.ts Outdated
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from e756566 to b2ba6fe Compare July 31, 2026 23:31
Route ordinary ask selectors through the bounded title viewport already used by Deep Interview so long premises remain recoverable without changing terminal wheel scrollback.

Issue: Yeachan-Heo#3675
Constraint: preserve Deep Interview behavior and terminal wheel handling
Not-tested: tests and formatters intentionally skipped per assignment
Confidence: high
Scope-risk: narrow
Reversibility: revert-commit
@snowykr
snowykr force-pushed the fix/ordinary-ask-scroll-title branch from b2ba6fe to 8fffb6f Compare July 31, 2026 23:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8fffb6fdfd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Hostile Review — MERGE_READY ✅

Reviewed commit 8fffb6fdfd1d28561bcf757f3ded93649151f2b6 on base 4c6e81706 (dev).

Attacked the diff for every named regression vector. Findings below.

Transcript admission regression — no regression

The selector continues to mount under the existing editorContainer swap path (detachChildclearaddChild(hookSelector)), and hideHookSelector() restores the composer via the same restoreComposer() path. No transcript repaint or admission-state write was touched. showHookSelector still calls attachAbort() and returns the same finish(option | undefined) promise. Deep Interview routing is byte-identical (still DEEP_INTERVIEW_SELECTOR_SCROLL_TITLE_ROWS).

Ask viewport overflow — fixed, not regressed

ask.ts:1616 now routes all selector prompts (ordinary + deep-interview) through scrollTitleRows: DEEP_INTERVIEW_SELECTOR_SCROLL_TITLE_ROWS. extension-ui-controller.computeBudget() clamps that sentinel against availableTitleRows, so the title is bounded by the terminal budget and never pushed into scrollback. Verified: 20-row terminal renders ≤ 20 lines with Prompt row 1 and all options visible; the premise is fully recoverable via PgUp/PgDn/Ctrl+u/d.

Scrollback semantics — sound

  • Terminal wheel scrollback is untouched: the selector renders within the viewport; nothing writes to scrollback.
  • ▼ more/▲ more indicators are now computed inside a bounded convergence loop (4 iterations) instead of baked into the last visible line. The wasAtBottom re-anchor before the indicator pass prevents a countdown-timer repaint from resurrecting a stale ▼ more row — covered by keeps the bottom premise page stable across a countdown repaint.
  • One-row title viewport (scrollTitleRows: 1) slices cleanly without indicators (the maxRows < 3 fast path). Verified by keeps each premise line intact in a one-row title viewport.

Focus / prompt pinning — no regression

  • PageUp/PageDown/Ctrl+u/Ctrl+d now page by max(1, scrollTitleRows - 2) instead of scrollTitleRows. This accounts for the indicator rows and prevents overshooting past content. Existing paging tests were updated from 8→16 page-downs to reflect the smaller page stride; this is correct, not gaming.
  • Paging is suppressed while the inline-editor autocomplete is open (!this.#inlineEditor?.isAutocompleteOpen()) — a genuine fix so PageDn doesn't both scroll the title and move the autocomplete selection. Covered by keeps an open autocomplete dropdown ahead of title paging.
  • Option focus (selectedIndex) is never mutated by title scrolling — preserved.

Title reflow across resize — sound

ScrollableTitle.render() detects width changes via #lastRenderWidth and re-anchors the scroll offset to the same source-text span (graphemeStart/graphemeEnd from the #2031 viewport anchor system) rather than resetting to top. findLast is ES2023 — Bun runtime supports it (verified typeof === "function"). Covered by keeps the visible premise anchored across title reflow and the resize-handler test.

Resize listener lifecycle — clean

process.stdout.on("resize") is registered only when requestedTitleRows !== undefined, removed on hideHookSelector(), dispose(), and before re-registration. Test removes the bounded selector resize listener when disposed asserts listenerCount returns to baseline. No listener leak.

Contract drift — one widening, sound

Editor.setAutocompleteProvider widened from (provider: AutocompleteProvider) to (provider: AutocompleteProvider | undefined). The undefined branch cancels any open autocomplete and notifies — correct for the compact-mode path that disables @ autocomplete. All callsites remain valid (a concrete provider is still assignable to AutocompleteProvider | undefined). The EditorComponent interface in editor-component.ts:60 still declares the narrower signature — functionally sound (contravariant parameter widening on the implementer is assignable), but worth a follow-up to align the interface for clarity. Not blocking.
EditorComponent interface in editor-component.ts:60 still declares the narrower signature — functionally sound (contravariant parameter widening on the implementer is assignable), but worth a follow-up to align the interface for clarity. Not blocking.

#capFocusedSegments(budget === 1) behavior change — intentional, tested

The budget === 1 branch now returns truncateToWidth(rows[0]) instead of the … N wrapped rows omitted … marker. This keeps at least the first content row of a focused option visible under extreme compaction rather than replacing it entirely with an omission marker. The new sibling-clipping marker logic (mustMarkClippedSiblings) covers the position-indicator case. Tested by reserves a position marker when focused wrapping clips siblings.

Tests — comprehensive

The commit trailer Not-tested: tests and formatters intentionally skipped per assignment is stale/inaccurate — the PR actually adds substantial test coverage (309+ lines in hook-editor.test.ts, 171+ in hook-selector-overflow.test.ts, 43+ in hook-selector-inline-input.test.ts). I ran the full set: 154/154 green across the 4 affected files, plus 206/206 green across deep-interview-render-middleware, hook-input-timeout, interactive-mode-editor-component, editor-autocomplete-actions, and editor tests. The trailer should be corrected post-merge, but the actual coverage is strong.

Type/lint/build verification

  • bun --cwd=packages/coding-agent run check (tsc + biome): clean
  • bun --cwd=packages/tui run check: clean
  • CI: 14 SUCCESS, 2 SKIPPED (platform-gated), 0 failures

Verdict

The diff is maintainable, well-commented, and correctly addresses #3675 without regressing Deep Interview, transcript admission, scrollback, or focus pinning. The only nits (stale commit trailer, narrow EditorComponent interface signature) are non-blocking.

MERGE_READY — merging with squash.


Signed-off-by: GJC (hostile reviewer) — review grounded in 8fffb6fdfd on 4c6e81706, 154+206 tests re-run green, tsc+biome clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants