Repository navigation
perf(engine): keep furrow detection off the session build path - #1954
Merged
Merged
Conversation
…e folder asked about
…urrow arming goroutine
…ion config; test writes take the lock
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.
Summary
A cold launch held the first frame behind two furrow subprocesses: the engine hello builds the agent, the agent builds its belt, and the belt asked furrow on the spot.
bootEngine enginehost.(*Host).open session.newAgent (*Agent).belt (built once, at construction) - (*Agent).workspaceTools - furrow.Tools -> Open -> Detect - `furrow --version` (blocks the hello) - `furrow --repo ws --json status` (2-3 s, blocks the hello) + (*Agent).workspaceTools + furrow.PeekTools (memory only, never a subprocess) + (*Agent).askFurrow (returns at once) + furrowRefresher.ask -> guard.Go (joined by Close) + furrow.Detect (cancellable, one asker per folder) + armFurrowVerbs -> armFamily (appends the 4 tools at the tail) ... first model request + settleFurrow (waits <= 200 ms, once, only if a question is running) completeWithModel(WithTools(beltDefinitions))Design it twice:
armFamily, which appends at the tail. An unwatched folder, the common case, never changes.What the review changed from the first push:
Detectno longer takes a plain mutex per folder. Later askers wait on the first asker's question but on their own context, so a session closing (or a cancelled ground-path caller) leaves at once instead of waiting out another session's furrow.armFamily.--once, resume with a pending prompt, spawned workers): the first model request waits up to 200 ms for a furrow question that is already running, and only the first request, and never while the session is built, so the first frame is unaffected. Past the cap the request goes out without the verbs and they are armed when furrow answers.Prompt-cache cost. On a watched folder the four definitions are appended at the end of the tool list once. If the answer lands before the first request (usual, and guaranteed when the 200 ms wait catches it) nothing is invalidated. Otherwise the request after the answer pays one invalidation at the tail, and nothing ahead of it moves. Tools never leave the list mid-conversation, so the TTL cannot flip attached to unattached under the model: a folder unwatched later keeps the tools and they answer with furrow's refusal. An unwatched folder pays nothing.
Evidence
Before: first frame 3.87 s on a quiet box; interleaved rig runs on the same box and profile: 4.91, 4.90, 5.07 s. Red tests on the test-only commit (
598691cc8, the pre-fix tree):After (against the furrow embedded before 0.3.3): first frame 0.62, 0.44, 0.50 s (cold engine per workspace, owner profile, Spark linux-arm64). Green with
-race. Nothing is timed: furrow is a script whosestatusparks on a named pipe, and the assertions are about whether it was still alive.With furrow 0.3.3 merged from dev (Bump embedded furrow to v0.3.3 (fast store open) #1962):
origin/devalone now draws the first frame in 0.97, 0.43, 0.43 s and this branch in 0.43, 0.38, 0.38 s. The fast furrow removed most of the wait this PR was written for; what remains is that first-frame time no longer depends on furrow's speed or on a folder furrow handles badly, and that a Close never waits on another session's furrow.Full
make checkon Spark via fleet, job 20261026-131849-002475, on the merge of devf0cf232cf(head359167f64, later commit2d0db4833is docs only):internal/session(8 shards),cmd/codeaf,internal/furrow,internal/guard,internal/tui3ok.internal/releaseandinternal/seniordev/utilfail identically on cleanorigin/dev. Whole-package-raceoninternal/sessionshows one race, inTestAHeldPhaseKeepsSayingItselfAndStopsWhenItEnds(a test write againstbeatHeldPhase, no furrow code), and wall-clock or shared-spend failures (TestSessionCountersCostNothingBesideTheWork,TestTheDailyCeilingBindsTaskAndErrandTurnsToo).TestAStoppedTaskResultCannotAutoStartItsRequestAgainfails under-raceon cleanorigin/devas well (16 of 20 runs): the test marks a node failed afteradmithas already let the frontier goroutine start it.Merge Danger
Door: two-way
Blast Radius: session belt
On a watched folder the four workspace tools can join the tool list after the session starts (one tail append, see the prompt-cache note). No tool text, schema or name changes, and an unwatched folder behaves as before.