Untracked-aware verifier + npm distribution (2.1.0) - #44
Merged
Conversation
The post-dispatch completion verifier confirmed a task's work via git diff, which omits untracked files. Editing a file that was untracked when the task started (a new file never `git add`ed) produced no diff, so the judge read "no changes to <file>" and aborted work that had in fact succeeded. The plan-stop detector shared the blind spot: status shows an unchanged `??` and diff omits untracked content. Route both change-detection gates through an untracked-aware tree snapshot (snapshotWorktreeTree): capture a pre-task tree, diff it against a fresh snapshot, and edits to still-untracked files surface as content deltas while pre-existing tracked/untracked state cancels out. Fall back to the prior ref + intent-to-add path on a non-git or too-old git. Bound every snapshot call with a timeout so a wedged git cannot block the worker.
The MCP server was only installable by cloning and building, so an MCP client (or a directory like LobeHub) had to point at an absolute dist/ path. Package it for npm instead: - add a shebang to src/server.ts so dist/server.js runs as a bin, and expose it as the `bob-control` bin — `npx -y @pounceai/bob-control` starts the server over stdio with no checkout - scope the package `@pounceai/bob-control`, publish access public, and whitelist `files` to dist runtime JS (drops 53 test files and repo metadata: a 2MB/258-file pack becomes 461KB/50 files) - build fresh on publish via prepublishOnly - sync serverInfo.version to the manifest (was a stale 1.1.0) README gains the npx install method and a LobeHub MCP badge.
captureGitDiff's tree-vs-tree path used gitOut (stdout only), so a diff that errored — e.g. an unresolvable baselineTree — returned an empty string and read as "(no changes detected)", feeding the judge a false empty diff and aborting good work. The ref-based fallback was gated on the current-tree snapshot being null, never on the diff command failing. Gate on git's exit code and fall through when the tree diff errors. Also: - snapshotWorktreeTreeBounded: clear the race timeout on the fast path, and correct the comment — index.lock fails fast; only a genuine hang (stalled filter / wedged FS) skips the inner temp-index cleanup. - test the defaultCheckDidWork verdict directly (it was exercised only through injected stubs) and the tree-diff error fall-through. - captureGitDiff docstring: note that add -A honors .gitignore, so a deliverable at an ignored path is invisible to the tree diff. README: the npx snippet gains type:stdio and a note that non-Claude-Code clients must set BOB_TASKS_DB — a bare npx server writes to a throwaway board inside the npx cache that no worker can share.
The files whitelist shipped dist/ipc-test-harness.js (a named-pipe IPC fixture) and dist/smoke.js — neither is public API. The !*.test.js negation doesn't match them, so exclude both by name. Add check:shebang to prepublishOnly: a toolchain change that strips dist/server.js's #!/usr/bin/env node line (which npx relies on) now fails the publish instead of shipping a bin that can't launch.
workerLikelyActive() keyed the "board armed, may be pulled mid-curation" warning off an in_progress task touched within 5 min — but that race fires precisely when a drainer is alive and IDLE (0 in_progress), so the warning stayed silent in exactly the case it guards. Gate on the worker heartbeat instead, matched to the task's tags (a tag-pinned worker only pulls matching tasks). Drop the now-redundant worker_likely_active field from board_status; worker_draining is the authoritative liveness signal.
snapshotWorktreeTreeBounded raced snapshotWorktreeTree against a timeout but abandoned the loser: on a genuine hang the inner promise never settled, so its temp-index finally never ran and the git child stayed alive — an accumulating .git/bob-tmp-index-* file plus an orphaned process. Thread an AbortSignal through runGit/gitOut into spawn and have the timeout abort it: the child is killed (SIGTERM / TerminateProcess on Windows), the inner finally runs and drops the temp index, and the caller still resolves null. Only a child that ignores the kill and stays wedged can still leak, and even then the caller returns.
The tree-snapshot verifier degraded silently — on a snapshot timeout or a failed tree diff the judge saw "(no changes)" with no stderr trail, which is undiagnosable in a slow-git environment. Both fall-throughs now log to stderr, naming the cwd. check:shebang covers dist/cli.js too; both are bin entries relying on the #!/usr/bin/env node line that npx invokes.
npm distribution as @pounceai/bob-control, the untracked-aware verifier fix, and the create_task race-warning fix. The VS Code extension stays at 2.0.2 (unchanged this release).
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.
Verifier
The completion check and LLM judge diffed with
git status/git diff HEAD, which can't see an editto a file that was already untracked when the task started — so real work read as "no changes" and got
aborted. They now diff two untracked-aware
git write-treesnapshots (staged into a temp index, so thereal index is untouched).
"no changes".
AbortSignal) rather than leaking its temp index and child.npm packaging
Publish the connector as
@pounceai/bob-control(2.1.0).bob-controlbin → the MCP server;npx -y @pounceai/bob-controlruns it standalone.filesallowlist ships only runtimedist(258 files / 2 MB → 48 / ~460 KB), no tests or fixtures.check:shebang; scoped public viapublishConfig.BOB_TASKS_DB.First publish requires the
@pounceainpm org to exist.Board (bundled)
create_task's "may be pulled mid-curation" warning keyed off in-progress tasks, so it stayed silentfor a live-but-idle drainer — exactly the race it guards. It now reads the worker heartbeat, matched to
the task's tags, and the redundant
worker_likely_activefield is dropped fromboard_status(use
worker_draining).The VS Code extension is unchanged and stays at 2.0.2.