Skip to content

Untracked-aware verifier + npm distribution (2.1.0) - #44

Merged
PounceAI merged 8 commits into
mainfrom
fix/verifier-untracked-target-files
Jul 3, 2026
Merged

Untracked-aware verifier + npm distribution (2.1.0)#44
PounceAI merged 8 commits into
mainfrom
fix/verifier-untracked-target-files

Conversation

@Joshua-Gilbert

Copy link
Copy Markdown
Collaborator

Verifier

The completion check and LLM judge diffed with git status / git diff HEAD, which can't see an edit
to 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-tree snapshots (staged into a temp index, so the
real index is untouched).

  • A failed tree diff gates on git's exit code and falls through to the ref diff instead of reporting
    "no changes".
  • A wedged snapshot is killed on timeout (AbortSignal) rather than leaking its temp index and child.
  • The timeout and the tree→ref fallback log to stderr.

npm packaging

Publish the connector as @pounceai/bob-control (2.1.0).

  • New bob-control bin → the MCP server; npx -y @pounceai/bob-control runs it standalone.
  • files allowlist ships only runtime dist (258 files / 2 MB → 48 / ~460 KB), no tests or fixtures.
  • Both bin shebangs guarded at publish by check:shebang; scoped public via publishConfig.
  • README gains the npx install method plus a note that non-Claude-Code clients must set BOB_TASKS_DB.

First publish requires the @pounceai npm org to exist.

Board (bundled)

create_task's "may be pulled mid-curation" warning keyed off in-progress tasks, so it stayed silent
for 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_active field is dropped from board_status
(use worker_draining).

The VS Code extension is unchanged and stays at 2.0.2.

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).
@PounceAI
PounceAI merged commit 75a3941 into main Jul 3, 2026
3 checks passed
@PounceAI
PounceAI deleted the fix/verifier-untracked-target-files branch July 3, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants