fix(runtime): stop Smithers persisting per-pulse heartbeat events and fetching/rebasing task worktrees - #1166
Merged
Merged
Conversation
…tbeat write The pinned @smthrs/engine flushHeartbeat() writes the fenced attempt-row heartbeat and, when that write succeeds, appends a TaskHeartbeat event: an _smithers_events row and a stream.ndjson line. Ultrafuzz never attaches heartbeat data, so the event carries nothing the row lacks. A quiet agent writes one per throttled liveness pulse (the watchdog pulses every 250ms and writes are throttled to 500ms). An agent that streams output writes one per ownership check its stdout, stderr and tool callbacks force, and forced writes bypass the throttle: in a scratch run with a stdout write every 10ms, one 3.5s task appended 384-588 of them. Ultrafuzz never acts on these events: it handles only TaskHeartbeatTimeout, the engine's heartbeat timeout advances only when the attempt-row write succeeds, and `smithers why` reads the attempt row. Add an engine_task_heartbeat_event compatibility patch that deletes the emit and keeps the fenced write, registered in SMITHERS_COMPATIBILITY_PATCHES and in the fresh operator-controller patch list. The new integration test runs a one-task workflow under Bun with every registered compatibility patch applied as each Smithers module loads. Its agent owns a quiet 3.5s child under a 3s heartbeat timeout. On main the run records TaskHeartbeat rows (6 to 8 in the runs observed); with this patch it records none, the task still finishes, and the attempt row's heartbeat_at_ms keeps advancing. Refs #1147 Co-Authored-By: Claude Opus 5.5 <[email protected]>
Smithers' <Worktree baseBranch> treats its value as a branch to track. Creating a worktree runs `git fetch origin` first. Each time a task re-enters an existing worktree, the pinned engine retries `git rebase origin/<base>`, after another `git fetch origin` unless one succeeded for that repository in the last 60s (the worktree sync cache's default TTL). Ultrafuzz passes the recorded launch commit (or the pinned source branch), and origin/<sha> never resolves, so every re-entry by an agent or verifier task logs "worktree sync rebase failed"; a failed rebase is never recorded, so it repeats. The fetches have no timeout, update the user's remote-tracking refs, and are retried on every re-entry while they fail; on this host `git fetch origin` against an unreachable HTTPS remote took 136s to fail. Task worktrees must stay on the launch commit, which assertWorkspaceSourceRevision enforces. Add two engine compatibility patches: engine_worktree_sync makes getWorktreeSyncCache() return an inert cache, so the re-entry path never fetches or rebases (git and jj), and engine_worktree_create_fetch removes the fetch before `git worktree add`, which already tried the local base first. Both are registered in SMITHERS_COMPATIBILITY_PATCHES and in the fresh operator-controller patch list. The new integration test runs a <Worktree> seeded from a local-only launch commit with a preparation task that creates it and a verifier task that re-enters it, on the controller-patched engine, with every git invocation recorded. On main it records `fetch origin`, `fetch origin` and `rebase origin/<sha>`; with this patch it records no fetch or rebase, the run finishes, and the worktree is on the launch commit and its task branch. #1148 also asks for worktree retention and missing-object diagnostics, which this does not change. Refs #1148 Co-Authored-By: Claude Opus 5.5 <[email protected]>
aviggiano
force-pushed
the
claude/w09-smithers-unused-behaviors
branch
from
September 29, 2026 02:41
f6a62a6 to
82b008d
Compare
Every pull request in this batch inserts its entry at the same place in CHANGELOG.md, so each merge would conflict with the next. The entries are collected into one changelog update instead. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This was referenced Sep 29, 2026
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.
Problem
Two behaviours of the pinned Smithers engine (
@smthrs/engine0.35.0) run in every Ultrafuzz campaign, although Ultrafuzz never uses them.TaskHeartbeatevent after every heartbeat write (Reduce durable-state duplication and heartbeat volume #1147). Each successful fenced attempt-row heartbeat write is followed by aTaskHeartbeatevent: one_smithers_eventsrow plus onestream.ndjsonline. The event carries no heartbeat data, because Ultrafuzz never passes any.flushHeartbeat(true)), and forced writes bypass the throttle. In a scratch run of this PR's harness with a stdout write every 10 ms, one 3.5 s task appended 384-588TaskHeartbeatrows (9 runs, load average about 9). The same task without output appended 8.TaskHeartbeat. I re-counted that.nodeevent category, so they fillultrafuzz events --type node.<Worktree baseBranch>as a branch to track.git fetch originfirst.git rebase origin/<base>. That happens for the agent and the verifier after preparation, and again on each retry or resume. Before the rebase it runsgit fetch originagain, unless a fetch succeeded for that repository in the last 60 s (the sync cache's default TTL). A failed fetch is not cached, so it is retried on every re-entry.origin/<sha>is never a ref. So every re-entry logsworktree sync rebase failed … invalid upstream 'origin/<sha>'. Only a successful rebase is recorded, so the failure repeats.git fetch originagainst an unreachable HTTPS remote took 136 s to fail.Root cause
flushHeartbeat()in@smthrs/engine/src/engine.jsmakes the fencedadapter.heartbeatAttempt(...)write. When the write persists, it then awaitseventBus.emitEventQueued({ type: "TaskHeartbeat", … }). Nothing that depends on liveness reads that event:smithers whyreadsattempt.heartbeatAtMs;TaskHeartbeatTimeout.Inside Smithers the event is only formatted for display, filtered out as noise (
tail,bug), counted in in-memory metrics, or relayed by the gateway. Ultrafuzz acts on none of these. The only other emitter, the compute-task bridge, fires only on explicitheartbeat()calls, and Ultrafuzz makes none.ensureWorktree()asksgetWorktreeSyncCache()whether to fetch and rebase an existing worktree. Its create path runsgit fetch originunconditionally beforegit worktree add, andgit worktree addalready tries the local<base>first. A rebase that moved HEAD off the launch commit would fail the task inassertWorkspaceSourceRevision. So in Ultrafuzz this sync can only fail, or break the run's source invariant.Change
Three deletions in the operator controller's engine, through the existing
SMITHERS_COMPATIBILITY_PATCHESmechanism. Each has a registry entry, aSmithersCompatibilityPatchIdmember, and an entry in the fresh-install list inapplySmithersCompatibilityPatches.engine_task_heartbeat_eventTaskHeartbeatemit. The fenced attempt-row write and the rest offlushHeartbeatare unchanged.engine_worktree_syncgetWorktreeSyncCache()returns an inert cache, so re-entering a worktree never fetches or rebases (git and jj paths).engine_worktree_create_fetchgit fetch originbeforegit worktree add.A script over the registry checked the three anchors:
engine.js;upstreamAbsentis[]for all three, as for the other entries that have no known upstream marker.The new
packages/runtime/test/smithers-controller-engine.integration.test.tsruns a one-off workflow under Bun on the pinned Smithers release. A Bun preload plugin applies every registered compatibility patch as each patched module loads, using the same exactly-once replacement as the controller. The test therefore runs the engine Ultrafuzz ships, without copying or modifying the package store. Theruntime-supportinglane picks the file up.The change is two commits, one per issue: +91 lines in
smithers.ts, a 187-line test file, and 2 CHANGELOG lines. Nothing is removed.Revised after review. The code is unchanged. The comments, CHANGELOG, commit messages and this description now describe the streaming heartbeat rate, the 60 s fetch cache, and which runs pick the change up. The #1148 reference is now
Refsrather than a closing keyword, in the commit message too, so the squash commit cannot close the issue. The branch is rebased onto currentmain.Deliberately not built (and why)
NodeStarted/NodeFinishedalready bound the interval. Deleting the emit is smaller and removes more._smithers_eventswould break Smithers' seq pagination and Ultrafuzz's full-history event reads. That is why this PR saysRefs #1147, notCloses.git cat-file -eprobe, fetch-only-when-absent, and "one actionable fetch error". In Ultrafuzz the launch object is always local:refs/ultrafuzz/runs/<id>/sourceor the pinned branch keeps it, and the Modal worker fetches it explicitly. Smithers already tries the local<base>first. A conditional fetch would bring back an untimed network call. If the object were ever missing, creation would fall back toHEADandassertWorkspaceSourceRevisionwould fail the task with a source-revision error, which is today's behaviour.artifacts/and.ultrafuzz/schemas/mirrors make task worktrees dirty, so the Smithers reaper correctly keeps them. I left it unchanged. The sentence "Successful runs remove their generated workspaces by default" indocs/reference/configuration.mdneeds a separate look. Because Create worktrees directly from pinned local commits #1148's retention and missing-object criteria stay open, this PR saysRefs #1148, notCloses.applySmithersCompatibilityPatcheswith a registry filter, as the@smthrs/agentspath already does (about -85 lines). Worth doing as the next PR, but not here: it changes how every existingengine.jspatch is applied at controller install, so it needs its own byte-identical-output evidence. An earlier version of this description gave a different reason, that it would collide with w06's edits. A reviewer checked that w06 does not touch that list, so that reason was wrong.TaskHeartbeat(or make it opt-in), and treat a commit-idbaseBranchas immutable.Verification
Discriminating (re-run after the rebase onto
b6dd1da9). I compiled the same test file againstorigin/main'ssmithers.tsand against this branch. Both new tests fail on main and pass on the branch.controller agent tasks stay live on their attempt row without a TaskHeartbeat event per pulse: a quiet agent owns a 3.5 ssleepchild under a 3 s heartbeat timeout.TaskHeartbeat: 8of 22 event rows.heartbeat_at_msis at least 2 s afterstarted_at_ms.controller task worktrees stay on a local-only launch commit without fetching or rebasing: a<Worktree>is seeded from an unpushed commit. A preparation task creates it, a verifier task re-enters it, andSMITHERS_GIT_PATHrecords every git call.['fetch origin', 'fetch origin', 'rebase origin/<sha>'].ultrafuzz/r1/task-a.Other evidence (scratch runs, not committed)
heartbeatEvidenceAtMs = heartbeatAtMsfrom the patched engine. The same quiet-agent workflow then failed withTASK_HEARTBEAT_TIMEOUT … has not heartbeated in 4434ms (timeout: 3000ms). So the test'sfinishedassertion catches a patch that breaks attempt-row liveness.TaskHeartbeatrows over 9 runs; with it, 0.Other tests (pass on this branch; not discriminating)
every runner compatibility patch still anchors in the pinned Smithers releasecompatibility patcher rewrites every described workaround(registry vs. fresh-install list)compatibility patches declare every ultrafuzz helper inside the module they patchpatched engine admits authenticated controller path changes without accepting VCS relocation(imports the fully patched engine)diagnoseProject reports a posture for every tracked compatibility patchcontroller refresh/controller generationtests inruntime.test.ts.controller-source,operator-npm,smithers-attempt-authority,smithers-diagnostic,smithers-executable-capability,smithers-package.native continuation keeps a finished producer and runs only a newly rendered downstream task(see Risk).Static checks (all pass)
npx prettier --checkandnpx eslinton the changed filesCI=1 ESLINT_PLUGIN_DIFF_COMMIT=origin/main pnpm -w lint:strict:cipnpm --filter @ultrafuzz/runtime typecheckpnpm -w knipnode scripts/docs-check.mjsNot run
External static analysisjob fails MD013 on existing long lines inCHANGELOG.md, and does so for every PR that edits that file until ci: validate every package on PRs, stop cancelling main runs, and add a global complexity ceiling #1184 turns MD013 off. That failure skips the release lanes, includingruntime-supporting.Risk / compatibility
ultrafuzz resumedoes not use the sealed runner.execSmithersCliresolves the current operator controller (prepareSmithersExecutableEnvironment), and a native continuation resolves the workflow's packages through that controller'snode_modules. So a run launched before the upgrade should pick up the change once it is stopped and resumed.native continuation keeps a finished producer…test, run above, shows resumed tasks resolving packages from a freshly installed controller. I did not resume a run launched on an older version.ultrafuzz replayandforkrun the runner sealed at launch (linkedWorkflowExecutionEnvironment). For an older run they keep its old engine, and so does a runner process that is still executing.doctor(which reports a not-yet-applied patch as a warning), and byrefreshedSmithersControllerSnapshot, which has no production caller. I found nothing that compares a run's sealed engine against it, so older runs are not rejected.TaskHeartbeatrows insmithers eventsandstream.ndjson, the gateway'stask.heartbeatrelay, and Smithers' in-memory heartbeat metrics. Ultrafuzz acts on none of these. Existing runs keep their rows, andultrafuzz events --typestill acceptsTaskHeartbeat.origintip. Ultrafuzz only ever passes a commit id, the pinned branch (materialized with no remote), or the governed-source commit.assertWorkspaceSourceRevisionalready requires HEAD to stay on the launch commit.TaskHeartbeatemit. If both land, the patch applied second cannot find its anchor and every controller install fails, so one of them must be dropped. Git also reports a textual conflict insmithers.ts.smithers.tsauto-merges with all three;CHANGELOG.mdconflicts trivially.Refs #1147, #1148, #1156
🤖 Generated with Claude Code
No new blocking issue was identified in the changes since the previous review; the PR appears safe to merge on that basis.
Summary
The PR patches the pinned Smithers engine to keep attempt-row heartbeats without emitting
TaskHeartbeatevents, and to create and re-enter task worktrees without fetching or rebasing. It adds integration tests for both behaviors.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR A[Controller installs compatibility patches] --> B[Patched Smithers engine] B --> C[Heartbeat] C --> D[Fenced attempt-row write] B --> E[Task worktree] E --> F[Create from local launch commit] F --> G[Re-enter without fetch or rebase]Reviews (3) · Last reviewed commit: "chore: move the changelog entry to the c..."