From c7d6add473e64306beb1e2f82cc7590f9fae7412 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 23 Apr 2026 09:10:59 -0700 Subject: [PATCH] fix(test): session-awareness reads AskUserQuestion Format from a Tier 2+ SKILL.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test was reading ROOT/SKILL.md (browse skill, Tier 1) which never contained '## AskUserQuestion Format' — that section is only emitted for Tier 2+ skills by scripts/resolvers/preamble.ts. As a result the agent was prompted with an empty format guide and only emitted 'RECOMMENDATION' intermittently, making the test flaky. Pre-existing on main (same ROOT/SKILL.md shape there) — surfaced now because the agent run didn't hit the RECOMMENDATION/recommend/option a fallback strings in this particular attempt. Fix: read from office-hours/SKILL.md (Tier 3, always has the section) with a fallback that scans for the first top-level skill dir whose SKILL.md contains the header. Future template moves won't break this test again. --- test/skill-e2e-bws.test.ts | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/test/skill-e2e-bws.test.ts b/test/skill-e2e-bws.test.ts index acbdf86c..95617411 100644 --- a/test/skill-e2e-bws.test.ts +++ b/test/skill-e2e-bws.test.ts @@ -286,11 +286,38 @@ Log the operational learning now. Then say what you logged.`, // Add a remote so the agent can derive a project name run('git', ['remote', 'add', 'origin', 'https://github.com/acme/billing-app.git']); - // Extract AskUserQuestion format instructions from generated SKILL.md - const skillMd = fs.readFileSync(path.join(ROOT, 'SKILL.md'), 'utf-8'); + // Extract AskUserQuestion format instructions from a generated SKILL.md. + // ROOT/SKILL.md is the browse skill (Tier 1) and does NOT contain the + // "## AskUserQuestion Format" section — that block is only emitted for + // Tier 2+ skills by scripts/resolvers/preamble.ts. Use office-hours/SKILL.md + // (Tier 3) which always has the format guidance baked in. Falls back to + // the first SKILL.md that contains the header so a future template move + // doesn't break this test again. + let skillMdPath = path.join(ROOT, 'office-hours', 'SKILL.md'); + let skillMd = ''; + if (fs.existsSync(skillMdPath)) { + skillMd = fs.readFileSync(skillMdPath, 'utf-8'); + } + if (!skillMd.includes('## AskUserQuestion Format')) { + // Fallback: scan top-level skill dirs for the first match. + const skillDirs = fs.readdirSync(ROOT, { withFileTypes: true }) + .filter(d => d.isDirectory()) + .map(d => path.join(ROOT, d.name, 'SKILL.md')); + for (const candidate of skillDirs) { + if (!fs.existsSync(candidate)) continue; + const content = fs.readFileSync(candidate, 'utf-8'); + if (content.includes('## AskUserQuestion Format')) { + skillMd = content; + skillMdPath = candidate; + break; + } + } + } const aqStart = skillMd.indexOf('## AskUserQuestion Format'); const aqEnd = skillMd.indexOf('\n## ', aqStart + 1); - const aqBlock = skillMd.slice(aqStart, aqEnd > 0 ? aqEnd : undefined); + const aqBlock = aqStart >= 0 + ? skillMd.slice(aqStart, aqEnd > 0 ? aqEnd : undefined) + : ''; const outputPath = path.join(sessionDir, 'question-output.md');