Skip to content

fix(orchestrator): path hashing + system_status version emit - #7

Open
evannadeau wants to merge 2 commits into
SpawnBox-dev:mainfrom
evannadeau:fix/path-hashing-leading-dash
Open

fix(orchestrator): path hashing + system_status version emit#7
evannadeau wants to merge 2 commits into
SpawnBox-dev:mainfrom
evannadeau:fix/path-hashing-leading-dash

Conversation

@evannadeau

Copy link
Copy Markdown

Summary

Two independent latent bugs in plugins/orchestrator/mcp/server.ts. Bundled because both are one-line fixes to the same file with the same bun run build cost.

1. Path hashing — leading-dash strip broke the JSONL filewatcher on POSIX (cab2a57)

projectHash mirrors how Claude Code names per-project directories under ~/.claude/projects/. CC keeps the leading dash that comes from POSIX absolute paths (/home/foo-home-foo). The previous .replace(/^-+/, "") stripped that dash, producing home-foo instead of -home-foo and silently pointing the agent-channel JSONL filewatcher at a directory that doesn't exist.

The MCP server stayed up and tools answered normally, but no cross-session channel events were observed (and downstream features that depend on the watcher quietly broke). Diagnostic: absence of offsets-<id8>.json files in <project>/.orchestrator-state/agent-channel/ despite live JSONLs in ~/.claude/projects/-<...>.

Fix: drop the strip. The Windows case (C:\fooC--foo) just produces a cosmetic double-dash and remains harmless — that was the original reason for the strip, but the cost on POSIX (silent feature death) outweighs the cosmetic cleanup on Windows.

2. system_status emitted hardcoded version string (93c5da6)

system_status reported a literal 0.30.28 instead of ${PLUGIN_VERSION}. The 0.30.31 cleanup (see the comment at mcp/server.ts:32-37) consolidated the version source to read from package.json at module load specifically so it wouldn't be "hardcoded in multiple spots and forgotten on every other version bump" — but the system_status line at mcp/server.ts:655 was missed during that consolidation. Every bump since (0.30.32 → 0.30.38) shipped with the line still saying 0.30.28.

Concrete symptom: running an up-to-date install and calling system_status returns **Version**: orchestrator MCP server **0.30.28** regardless of the actual package version. The startup banner uses PLUGIN_VERSION directly and reports correctly — only this one line was wrong.

Fix: use the existing PLUGIN_VERSION constant.

Files changed

  • plugins/orchestrator/mcp/server.ts — 2 single-line edits (line 2183 path-hashing, line 655 version emit)
  • plugins/orchestrator/dist/server.js — rebuilt via bun run build

Tested

  • bun run typecheck — clean
  • bun test — 516 pass / 0 fail / 38 files / 1207 assertions
  • Confirmed dist/server.js no longer contains the 0.30.28 literal in the system_status output line; build output is byte-stable across repeated bun run build runs against the same source.

Test plan

  • POSIX install: confirm ~/.claude/projects/-<...> is scanned — offsets-*.json files appear in <project>/.orchestrator-state/agent-channel/ and @SA-<id8> channel addresses deliver to peer sessions.
  • Windows install: confirm path-hashing still produces a valid directory name for C:\foo inputs (cosmetic double-dash C--foo expected).
  • Any install: confirm system_status reports the package.json version, not the hardcoded 0.30.28.

🤖 Generated with Claude Code

evannadeau and others added 2 commits May 13, 2026 18:50
…ewatcher

projectHash mirrors how Claude Code names per-project dirs under
~/.claude/projects/. CC keeps the leading dash that comes from POSIX
absolute paths (/home/foo -> -home-foo). The previous .replace(/^-+/, "")
stripped that dash, producing 'home-foo' instead of '-home-foo' and
silently pointing the agent-channel JSONL filewatcher at a directory
that doesn't exist.

The MCP server stayed up and tools answered, but no cross-session
channel events were observed (and downstream features that depend on
the watcher quietly broke).

Reference: anti_pattern 6dfc7ae1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…d literal)

The system_status output line hardcoded "0.30.28" instead of using the
${PLUGIN_VERSION} constant that's already read from package.json at module
load. The 0.30.31 cleanup (see lines 32-37 of mcp/server.ts) consolidated
the version source specifically so it wouldn't be "hardcoded in multiple
spots and forgotten on every other version bump" — but this single line at
mcp/server.ts:655 was missed during that consolidation, and every bump
since (0.30.32 → 0.30.38) shipped with the line still saying 0.30.28.

Concrete symptom: running an up-to-date plugin and calling system_status
returns "**Version**: orchestrator MCP server **0.30.28**" regardless of
the actual package.json version. The startup banner (which uses
PLUGIN_VERSION directly) reports correctly — only this line was wrong.

Tested: bun run typecheck clean, bun test 516 pass / 0 fail, dist/server.js
rebuilt via bun run build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpawnBox-dev pushed a commit that referenced this pull request Jul 28, 2026
…and the triage branches on need instead of enforcing an order

Firing #7 (0-for-7) refired on PA at 13:32Z, 22 minutes after PA had answered a
direct address and closed #6. Two independent reports, two distinct fixes.

MEASURED AT THE MOMENT IT FIRED, before concluding anything: PA's transcript
had been written 2 SECONDS earlier, and six of seven sessions had produced
output within 20s. So the subject was demonstrably alive and the fleet
demonstrably awake - which also confirms 0.31.6's dormant suppressor is
correctly SCOPED rather than over-broad: it did not catch this, and should not
have.

1. REFRACTORY FLOOR (SA-c5b207e0). The episode dedup clears the moment a
   verdict goes healthy, so the alert re-arms and re-asks immediately, forever,
   and every ask costs a peer a turn. The subject's own recent OUTPUT is far
   stronger proof of liveness than an unprocessed delivery is proof of the
   opposite. Emission is now floored at 30 minutes per session, OUTSIDE the
   episode dedup - the alert remembers it just asked.

   Their honest note is why this is a defect rather than an annoyance: they
   skipped the triage this time and said plainly that "I judged it safe to
   skip" is not something the triage should have to rely on. That is the alert
   training the behaviour it must not train.

2. TRIAGE BRANCHES ON NEED (SA-b14fafa3). The 0.30.77 text numbered the checks
   1-2-3 and said "do NOT skip" - but the costs are not comparable. ADDRESSING
   SPENDS A PEER'S TURN; TRANSCRIPT MTIME COSTS NOBODY ANYTHING and is
   conclusive for liveness. So a fixed order is wrong for the common case.

   Now: need only liveness -> mtime first, free and instant. Need something
   from them anyway -> address, since liveness rides along free. Answered
   recently -> do nothing.

   The sharp part: PA had ALREADY been reasoning this way, praising one session
   for choosing mtime and another for addressing. But that judgement lived in
   PA's head, not in the alert text, and non-PA readers only have the text.
   Same lesson as putting the base rate in the alert - encode the reasoning
   where the reader is.

TEST NOTE, recorded because it looked like a product bug and was not: the
recovery/re-arm integration test began failing, and the cause was MY OWN 0.31.6
dormant gate. That test advances a SIMULATED clock 30 minutes while file mtimes
stay at real time, so every peer transcript looked 30 minutes stale and
suppressed as "fleet asleep". An artifact of simulating time with real files -
in production both clocks are real. Fixed by ageing the fixture with utimesSync
rather than by weakening either check, and the test's original property
(episode state CLEARS on recovery, not merely suppressed) is preserved and
still asserted.

Two of tonight's checks now interact, which is worth knowing: refractory (30m)
exceeds the dormant threshold (15m), so a post-refractory re-emit requires the
fleet to be active at that later time. Correct in production; only the harness
had to be taught about it.

Tests: +6 refractory (first firing allowed; suppresses the exact 22-minute
refire; allows a genuinely new episode past the window; exact boundary; window
exceeds the delivery threshold; independence from the dormant gate). Suite 841
pass / 0 fail.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MLELREep1GfMbuPSpmJRcu
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.

1 participant