Add FT_TIMEOUT_MULTIPLIER env var to scale engine call timeouts#159
Open
aaronwestphal wants to merge 1 commit into
Open
Add FT_TIMEOUT_MULTIPLIER env var to scale engine call timeouts#159aaronwestphal wants to merge 1 commit into
aaronwestphal wants to merge 1 commit into
Conversation
Engine call timeouts (DEFAULT_TIMEOUT in src/engine.ts, the per-depth timeoutMs values in adjacent/prompts.ts, the wiki-compile timeout in md.ts) are sized for a baseline local CLI with no startup overhead. In environments where the configured engine has heavy startup cost — MCP servers, SessionStart hooks, high reasoning effort — the deadlines fire before the child has responded, producing non-deterministic "claude/ codex timed out after Ns" failures even on small prompts. The fix is a single uniform multiplier applied at the engine layer so every caller (classify, wiki compile, Possible runs) inherits it without changes. Read on every call so tests can scope the override. Non-numeric or non-positive values fall back to 1 silently. No default change — opt-in only. export FT_TIMEOUT_MULTIPLIER=2 # doubles every timeout ft possible run --seed <id> --repo . Two new tests pin the scaling behavior and the input-validation fallback. All 545 tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Engine call timeouts (
DEFAULT_TIMEOUTinsrc/engine.ts, the per-depthtimeoutMsvalues insrc/adjacent/prompts.ts, the wiki-compile timeout insrc/md.ts) are sized for a baseline local CLI with no startup overhead.In environments where the configured engine has heavy startup cost — MCP servers, SessionStart hooks, high reasoning effort, packaged plugin/skill loaders — the deadlines fire before the child has responded. The failure mode is non-deterministic
claude/codex timed out after Nseven on small prompts.Concrete repro from my setup:
ft possible run --depth quick --engine claudeagainst a 30-file repo. Claude Code with my normal MCP fleet + SessionStart hooks takes ~140s to return the first candidate-generation pass, soquick(120s) deterministically aborts at the "Generating candidates" step.standard(180s) is on the edge.deep(300s) is the only reliable depth, which defeats the point of having tiers.What
Single uniform multiplier applied at the engine layer so every caller (classification, wiki compile, Possible runs) inherits it without per-site changes.
Default is
1(no change in behavior). Non-numeric or non-positive values fall back to1silently. Read on every call so tests and one-off env overrides take effect without re-importing the module.Diff shape
src/engine.ts— addtimeoutMultiplier()andresolveTimeout()helpers, replaceopts.timeout ?? DEFAULT_TIMEOUTat the two consumption sites (invokeEngineandinvokeEngineAsync). +23 / -2.tests/engine-invoke.test.ts— two new tests using the existingshEngineshell fake: one pins the scaling behavior (multiplier 5 lets a 500ms sleep complete inside a 200ms caller timeout), one pins input validation ('not-a-number','0','-2',''all fall back to multiplier 1).README.md— new "Engine timeouts" subsection adjacent to the existing proxy-env-var paragraph.No default change. Opt-in only.
Verification
The existing
invokeEngineAsync: timeout kills the child promptlytest is unchanged and still passes — with no env var set, multiplier is 1 and 200ms stays 200ms.Why a multiplier and not per-tier env vars
Considered
FT_ENGINE_TIMEOUT_MS/FT_DEPTH_TIMEOUT_QUICK_MS/FT_DEPTH_TIMEOUT_STANDARD_MS/FT_DEPTH_TIMEOUT_DEEP_MS/ etc. Rejected as too much surface for a single failure mode (children that are uniformly slower than the author's reference machine). One knob, documented in one place, scales the existing tier shape rather than letting users invert it accidentally.