test: spell out AskUserQuestion in the PTY single-line fixture

Rename test/pty-auq-single-line.test.ts to
test/pty-askuserquestion-single-line.test.ts and expand the AUQ
abbreviation in identifiers and comments. House style writes
AskUserQuestion in full in filenames, identifiers, and comments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-13 18:27:43 -07:00
co-authored by Claude Fable 5
parent 1ef48ae052
commit 562273d793
@@ -1,10 +1,11 @@
/** /**
* Pins single-logical-line AskUserQuestion detection (the plan-design-with-ui * Pins single-logical-line AskUserQuestion detection (the plan-design-with-ui
* gate-timeout class). When the PTY reflows a boxed AUQ, ALL options land on * gate-timeout class). When the PTY reflows a boxed AskUserQuestion, ALL
* ONE logical line after stripAnsi the per-line option parser then finds * options land on ONE logical line after stripAnsi the per-line option
* only option 1 and the >= 2 check fails forever while the (correct) question * parser then finds only option 1 and the >= 2 check fails forever while the
* sits on screen. Both fixture strings below are condensed from REAL observed * (correct) question sits on screen. Both fixture strings below are condensed
* failure buffers of test/skill-e2e-plan-design-with-ui.test.ts. * from REAL observed failure buffers of
* test/skill-e2e-plan-design-with-ui.test.ts.
*/ */
import { describe, expect, it } from 'bun:test'; import { describe, expect, it } from 'bun:test';
@@ -14,10 +15,11 @@ import {
stripPtyResidue, stripPtyResidue,
} from './helpers/claude-pty-runner'; } from './helpers/claude-pty-runner';
// Condensed from the 2026-08-13 failure buffer: whole AUQ on one logical // Condensed from the 2026-08-13 failure buffer: whole AskUserQuestion on one
// line — dividers, cursor option, options 2-5, footer. Note the missing // logical line — dividers, cursor option, options 2-5, footer. Note the
// spaces ("2.Planordesigndoc") from stripped cursor-positioning escapes. // missing spaces ("2.Planordesigndoc") from stripped cursor-positioning
const SINGLE_LINE_AUQ = // escapes.
const SINGLE_LINE_QUESTION =
'────────────Planning: /tmp/x/.claude/plans/soft-questing-jellyfish.md──────────' + '────────────Planning: /tmp/x/.claude/plans/soft-questing-jellyfish.md──────────' +
' ☐ Review target What should I review? <gstack-qid:plan-design-review-scope-gate>' + ' ☐ Review target What should I review? <gstack-qid:plan-design-review-scope-gate>' +
'1.Branch diff (current WIP) Review the design implications of what changed. ' + '1.Branch diff (current WIP) Review the design implications of what changed. ' +
@@ -25,27 +27,27 @@ const SINGLE_LINE_AUQ =
'3. Spcific page, file, r pah Name a specific file. 4. Type something.' + '3. Spcific page, file, r pah Name a specific file. 4. Type something.' +
'────────────5.ChataboutthisEnter to select · ↑/↓ o navigate · Escto cancel'; '────────────5.ChataboutthisEnter to select · ↑/↓ o navigate · Escto cancel';
// The same AUQ with DEC cursor-visibility residue + spinner frames // The same AskUserQuestion with DEC cursor-visibility residue + spinner
// interleaved, as captured before stripPtyResidue existed. // frames interleaved, as captured before stripPtyResidue existed.
const RESIDUE_AUQ = const RESIDUE_QUESTION =
'[?25l✻Sprouting…[?25h[?25l✶[?25h' + SINGLE_LINE_AUQ.slice(0, 200) + '[?25l✻Sprouting…[?25h[?25l✶[?25h' + SINGLE_LINE_QUESTION.slice(0, 200) +
'[?25l·still thinking[?25h' + SINGLE_LINE_AUQ.slice(200); '[?25l·still thinking[?25h' + SINGLE_LINE_QUESTION.slice(200);
describe('single-logical-line AUQ detection', () => { describe('single-logical-line AskUserQuestion detection', () => {
it('isNumberedOptionListVisible matches the reflowed one-line AUQ', () => { it('isNumberedOptionListVisible matches the reflowed one-line AskUserQuestion', () => {
expect(isNumberedOptionListVisible(SINGLE_LINE_AUQ)).toBe(true); expect(isNumberedOptionListVisible(SINGLE_LINE_QUESTION)).toBe(true);
}); });
it('parseNumberedOptions finds the full ascending option run on one line', () => { it('parseNumberedOptions finds the full ascending option run on one line', () => {
const options = parseNumberedOptions(SINGLE_LINE_AUQ); const options = parseNumberedOptions(SINGLE_LINE_QUESTION);
expect(options.length).toBeGreaterThanOrEqual(2); expect(options.length).toBeGreaterThanOrEqual(2);
expect(options[0]).toEqual({ index: 1, label: expect.stringContaining('Branch diff') }); expect(options[0]).toEqual({ index: 1, label: expect.stringContaining('Branch diff') });
expect(options[1]?.index).toBe(2); expect(options[1]?.index).toBe(2);
}); });
it('survives DEC residue + spinner interleave', () => { it('survives DEC residue + spinner interleave', () => {
expect(isNumberedOptionListVisible(RESIDUE_AUQ)).toBe(true); expect(isNumberedOptionListVisible(RESIDUE_QUESTION)).toBe(true);
expect(parseNumberedOptions(RESIDUE_AUQ).length).toBeGreaterThanOrEqual(2); expect(parseNumberedOptions(RESIDUE_QUESTION).length).toBeGreaterThanOrEqual(2);
}); });
it('stripPtyResidue removes cursor-visibility fragments only', () => { it('stripPtyResidue removes cursor-visibility fragments only', () => {
@@ -57,7 +59,7 @@ describe('single-logical-line AUQ detection', () => {
expect(parseNumberedOptions('steps: 1. Read the file 2. Edit it 3. Done')).toEqual([]); expect(parseNumberedOptions('steps: 1. Read the file 2. Edit it 3. Done')).toEqual([]);
}); });
it('still parses classic multi-line AUQs', () => { it('still parses classic multi-line AskUserQuestions', () => {
const multiLine = 'What should I do?\n 1. First option\n 2. Second option\n 3. Third option\n'; const multiLine = 'What should I do?\n 1. First option\n 2. Second option\n 3. Third option\n';
const options = parseNumberedOptions(multiLine); const options = parseNumberedOptions(multiLine);
expect(options.map((o) => o.index)).toEqual([1, 2, 3]); expect(options.map((o) => o.index)).toEqual([1, 2, 3]);