From 525254455a93ace09b894450b7fa0c3966d78bdc Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Wed, 24 Jun 2026 08:16:04 -0700 Subject: [PATCH] chore: revert pty-smoke harness experiments (race-retry + CI debug step) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diagnosis is conclusive and the experiments aren't the fix, so restore the harness to its original state (net-zero diff vs main for both files). What the CI debug step proved: `claude -p` returns READY — claude v2.1.187 fully DISCOVERS /office-hours from the symlinked registry. Only the interactive PTY TUI rejects it as "Unknown command" (and it received the full command text). So the e2e-pty-plan-smoke failure is a claude 2.1.187 interactive-TUI regression (skills discovered by `claude -p` aren't exposed as TUI slash commands), pre-existing in the #2077 harness and failing identically on its own origin branch — unrelated to this activation PR. The race-retry can't help (the TUI genuinely lacks the command); the debug step also tripped actionlint (shellcheck SC2012). Both reverted. --- .github/workflows/evals.yml | 18 ------------------ test/helpers/claude-pty-runner.ts | 20 ++------------------ 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/.github/workflows/evals.yml b/.github/workflows/evals.yml index 2611678dc..f2c5cb232 100644 --- a/.github/workflows/evals.yml +++ b/.github/workflows/evals.yml @@ -216,24 +216,6 @@ jobs: || { echo "ERROR: plan-ceo-review SKILL.md missing 'name: plan-ceo-review' frontmatter" >&2; exit 1; } echo "skill registry OK" - # TEMP DEBUG (remove after diagnosing pty-smoke discovery): the smoke fails - # with "Unknown command: /office-hours" even after retries (not a race). - # Capture what claude actually discovers in CI to fix the registry precisely. - - name: Debug skill discovery (pty smoke) - if: matrix.suite.name == 'e2e-pty-plan-smoke' - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - run: | - set +e - echo "=== claude version + binary ==="; command -v claude; claude --version 2>&1 | head -3 - echo "=== HOME/CLAUDE/XDG env ==="; env | grep -iE '^(HOME|CLAUDE|XDG)=' || true - echo "=== ~/.claude/skills (top) ==="; ls -la "$HOME/.claude/skills" 2>&1 | head -30 - echo "=== office-hours SKILL.md resolves? ==="; head -3 "$HOME/.claude/skills/office-hours/SKILL.md" 2>&1 - echo "=== project .claude in cwd? ==="; ls -la "$GITHUB_WORKSPACE/.claude" 2>&1 | head - echo "=== claude -p probe (same discovery path) ===" - cd "$GITHUB_WORKSPACE" - timeout 90 claude -p "Reply with exactly the word READY and nothing else if the /office-hours slash command is available to you, otherwise reply MISSING." 2>&1 | tail -10 - - name: Run ${{ matrix.suite.name }} env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/test/helpers/claude-pty-runner.ts b/test/helpers/claude-pty-runner.ts index d4e4ffef0..2f507c66c 100644 --- a/test/helpers/claude-pty-runner.ts +++ b/test/helpers/claude-pty-runner.ts @@ -1605,7 +1605,7 @@ export async function runPlanSkillObservation(opts: { // command. await Bun.sleep(3000); } - let since = session.mark(); + const since = session.mark(); session.send(`/${opts.skillName}\r`); const budgetMs = opts.timeoutMs ?? 180_000; @@ -1619,7 +1619,6 @@ export async function runPlanSkillObservation(opts: { // even if the current state is 'working'. let proseAUQEverObserved = false; let waitingEverObserved = false; - let unknownCmdRetries = 0; const JUDGE_AFTER_MS = 60_000; const JUDGE_INTERVAL_MS = 30_000; while (Date.now() - start < budgetMs) { @@ -1635,24 +1634,9 @@ export async function runPlanSkillObservation(opts: { }; } if (visible.includes('Unknown command:')) { - // Skill-discovery race: in a cold CI container the overlay-FS scan of - // the symlinked ~/.claude/skills registry can finish AFTER the boot - // grace, so the first `/skill` send reaches claude before the skill is - // indexed and is rejected as unknown. (Reproduces only in CI — passes - // locally where claude is warm and discovery is instant.) Re-send the - // command a few times, re-marking first so the stale "Unknown command:" - // line in scrollback can't immediately re-trip this check, before - // concluding the skill is genuinely unregistered. - if (unknownCmdRetries < 3) { - unknownCmdRetries++; - await Bun.sleep(6000); - since = session.mark(); - session.send(`/${opts.skillName}\r`); - continue; - } return { outcome: 'exited', - summary: `claude rejected /${opts.skillName} as unknown command after ${unknownCmdRetries} retries (skill not registered in this cwd)`, + summary: `claude rejected /${opts.skillName} as unknown command (skill not registered in this cwd)`, evidence: visible.slice(-2000), elapsedMs: Date.now() - startedAt, };