fix(launcher): claude-pmoves shorthand had no MCP creds — they were never duplicates - #2484
Conversation
… the real launcher
The two claude-pmoves.sh files were never duplicates. They share a name and do
different, mutually exclusive things:
pmoves/scripts deploy/provision
loads the shared env file no yes
passes --mcp-config=<roster> no yes
selects --agent yes no
Each ended in its own `exec claude`, so you could have a PMOVES agent OR working
MCP creds, never both. `make -C pmoves claude-pmoves` (Makefile:4936) calls the
agent-selecting one, so the documented way to launch the delivery agent came up
with every cred-dependent MCP empty — the exact failure the provisioning script
was written to prevent, reached by the path most likely to be used.
Fix: pmoves/scripts/claude-pmoves.sh becomes a thin delegate. It keeps its
positional-agent shorthand and forwards `--agent "$AGENT" "$@"` to
deploy/provision/claude-pmoves.sh, which loads the shared env and the normalized
roster. All three of that script's exec paths forward "$@" verbatim (lines
127/130/134) and it consumes no positionals, so the passthrough is clean.
Neither UI changes. `claude-pmoves control-agent` still works and now inherits
creds; `deploy/provision/claude-pmoves.sh` on its own is still the no-agent
launch. Nothing deleted — both entry points stay valid, and crush-pmoves.sh plus
install-claude-pmoves-command.sh (which reference the provisioning one) are
untouched.
If the launcher is missing, this degrades to the previous behavior — agent
loads, creds do not — with a warning, rather than failing outright. The point is
that the missing half becomes visible instead of silent.
Verified: bash -n clean.
WS2 item 3. Note for the coordination plan: this item was enumerated as "two
divergent claude-pmoves.sh — pick the authoritative one". Picking one would have
deleted a working capability; the divergence was a name collision hiding a
missing composition.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 52 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…d-mount class Two corrections to the handoff doc, made before the enumeration propagates. RETRACTION. An earlier revision added hf-mcp-server.yml to the sibling-submodule build list. Wrong. Its context is ../../pmoves/services/hf-mcp-server — a two-level relative path back INTO pmoves/services/, i.e. a first-party service. My matcher keyed on a leading `../`, which is not sufficient: the first path segment has to be checked against .gitmodules. Corrected list is 7 registered submodules / 8 services, which is z890's original number plus n8n. This is the same class of error as the "13 of 15" figure it was meant to fix — pattern- matching a path shape instead of resolving it. ADDITION. The enumeration covers build contexts only, and those are the less dangerous half. Five BIND-MOUNT sources also come from submodules (PMOVES-supabase x4, PMOVES-n8n x1). A missing build context fails loudly; a missing bind source does not — Docker CREATES it as a directory, so a file mount silently becomes a directory mount and the container then fails on its own config. That is the class that took services down on this node, and it is the reason item 4 is a runbook rather than a code fix. Also records item 3's outcome: the two claude-pmoves.sh were never duplicates. One selects an agent and loads nothing; the other loads env + the MCP roster and selects no agent. Each ends in its own `exec claude`, so they are mutually exclusive, and `make -C pmoves claude-pmoves` took the path with no creds. Picking one — the item as written — would have deleted a working capability either way. Fixed by delegation in #2484. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…lindness claim Review pass on the claim + handoff. All six findings were valid; none were cosmetic. TTL. The claim had no expiry, so an abandoned branch would reserve these items indefinitely with no way for another node to tell when reclaiming is safe. Added: TTL 72h, expires 2026-08-11T13:00:00Z. OWNERSHIP COUNT. The entry said "five items claimed" while the body enumerated items 2-5 and the next paragraph assigned item 1 to z890 — ambiguous in exactly the file that exists to prevent collisions. Now states WS2 has five items and 4090 reserves FOUR of them, with item 1 named as z890's. PROVENANCE. "Everything re-verified via git show against origin/main" was not true of the whole document: it also carries GitHub Actions run results and node runtime observations, neither of which git show can produce. Now split three ways — repository content via git show, CI behavior via gh api on run records, node runtime state via docker inspect / git submodule status on THIS node only (single-node observation, not a fleet claim). CI-BLINDNESS CLAIM WAS WRONG. The doc said CI cannot catch the submodule gap because workflows check out with `submodules: recursive`. They do not check out submodules at all (validate-dockerfile-paths-ratchet.yml:54, validate-composes-ratchet.yml:41). They pass because validate_dockerfile_paths.py explicitly excludes sibling-submodule targets — "external repos the ratchet can't statically check" — and because validate-composes never inspects bind sources. A known, accepted blind spot rather than an accidental one. That is a better argument for the runbook, not a worse one, and it is now the one the doc makes. TRIGGER ROW. Correction 3 said `issue_comment` and `push` were both correct and only `pull_request_review` was wrong. `push` resolves from the PUSHED ref, so that was half-right; my first fix left the other half standing. Now a three-row table with the two halves' provenance distinguished — the pull_request_review correction is empirical from runs 31257145963 / 31257247543, the push correction is Actions semantics from review and is stated as behavior rather than as something measured here. Plus: item 3's outcome recorded (the two claude-pmoves.sh were never duplicates, fixed by delegation in #2484), and MD040 language identifiers on three fenced blocks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…n the enumeration (#2482) * docs(ws2): claim the tooling-audit workstream + correct three items in the enumeration z890's coordination plan assigns Workstream 2 to this node by affinity. This claims it — bounded to five enumerated items, not to "tooling" as an area — and records the corrections the enumeration needs before either node builds on it. Corrections, all verified against origin/main @ 22c78fb: (a) 2 leaking copies, not 4 drifting implementations. Both shell scripts already carry the #2473 buildx fix (pmoves-disk-cleanup.sh:52, docker-fleet-cleanup.sh:43). Only infra.mk:89 and ci-expedition/SKILL.md:69 lack it. (b) 4090's own earlier "13 of 15 fork services" figure was WRONG — it double-counted services re-declared across the generated split overlays. Correct count is 7 unique sibling-context builds in docker-compose.yml, plus n8n, plus hf-mcp-server.yml which the handed-over list missed. (c) The ci-expedition fix is narrower than "PR head, not default". In that row `issue_comment` and `push` are correct; only `pull_request_review` is wrong. Surgical edit, not a row rewrite. Plus: the four .worktrees/* skill copies are checkouts of the same tracked file, so fixing main fixes them all — one item off the list. Evidence for (c) is empirical, from the #2479 fix rather than from docs: run 31257145963 (PR head pre-fix, main already fixed) ran the OLD workflow and failed at checkout; run 31257247543 (head rebased) ran the NEW workflow and went green. Default-branch resolution predicts the opposite. Not claimed and deliberately left alone: infra.mk:89 (z890's declared sub-fix), WS1/WS3/WS4. Recommends Mavis-5090 for WS4-B, since the "rooms pull portals" model is their open OpenRoom slice-2 claim. The handoff doc also carries a WS3-relevant finding: AGNOTE4482PHI.t1.md was damaged three times in a row by stale-base merges (#2437 markers, #2450 deleting six entries, a corrupted duplicate). A deletion is a valid diff, so nothing catches it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(ws2): retract hf-mcp-server from the submodule list, add the bind-mount class Two corrections to the handoff doc, made before the enumeration propagates. RETRACTION. An earlier revision added hf-mcp-server.yml to the sibling-submodule build list. Wrong. Its context is ../../pmoves/services/hf-mcp-server — a two-level relative path back INTO pmoves/services/, i.e. a first-party service. My matcher keyed on a leading `../`, which is not sufficient: the first path segment has to be checked against .gitmodules. Corrected list is 7 registered submodules / 8 services, which is z890's original number plus n8n. This is the same class of error as the "13 of 15" figure it was meant to fix — pattern- matching a path shape instead of resolving it. ADDITION. The enumeration covers build contexts only, and those are the less dangerous half. Five BIND-MOUNT sources also come from submodules (PMOVES-supabase x4, PMOVES-n8n x1). A missing build context fails loudly; a missing bind source does not — Docker CREATES it as a directory, so a file mount silently becomes a directory mount and the container then fails on its own config. That is the class that took services down on this node, and it is the reason item 4 is a runbook rather than a code fix. Also records item 3's outcome: the two claude-pmoves.sh were never duplicates. One selects an agent and loads nothing; the other loads env + the MCP roster and selects no agent. Each ends in its own `exec claude`, so they are mutually exclusive, and `make -C pmoves claude-pmoves` took the path with no creds. Picking one — the item as written — would have deleted a working capability either way. Fixed by delegation in #2484. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(ws2): add claim TTL, split evidence provenance, correct the CI-blindness claim Review pass on the claim + handoff. All six findings were valid; none were cosmetic. TTL. The claim had no expiry, so an abandoned branch would reserve these items indefinitely with no way for another node to tell when reclaiming is safe. Added: TTL 72h, expires 2026-08-11T13:00:00Z. OWNERSHIP COUNT. The entry said "five items claimed" while the body enumerated items 2-5 and the next paragraph assigned item 1 to z890 — ambiguous in exactly the file that exists to prevent collisions. Now states WS2 has five items and 4090 reserves FOUR of them, with item 1 named as z890's. PROVENANCE. "Everything re-verified via git show against origin/main" was not true of the whole document: it also carries GitHub Actions run results and node runtime observations, neither of which git show can produce. Now split three ways — repository content via git show, CI behavior via gh api on run records, node runtime state via docker inspect / git submodule status on THIS node only (single-node observation, not a fleet claim). CI-BLINDNESS CLAIM WAS WRONG. The doc said CI cannot catch the submodule gap because workflows check out with `submodules: recursive`. They do not check out submodules at all (validate-dockerfile-paths-ratchet.yml:54, validate-composes-ratchet.yml:41). They pass because validate_dockerfile_paths.py explicitly excludes sibling-submodule targets — "external repos the ratchet can't statically check" — and because validate-composes never inspects bind sources. A known, accepted blind spot rather than an accidental one. That is a better argument for the runbook, not a worse one, and it is now the one the doc makes. TRIGGER ROW. Correction 3 said `issue_comment` and `push` were both correct and only `pull_request_review` was wrong. `push` resolves from the PUSHED ref, so that was half-right; my first fix left the other half standing. Now a three-row table with the two halves' provenance distinguished — the pull_request_review correction is empirical from runs 31257145963 / 31257247543, the push correction is Actions semantics from review and is stated as behavior rather than as something measured here. Plus: item 3's outcome recorded (the two claude-pmoves.sh were never duplicates, fixed by delegation in #2484), and MD040 language identifiers on three fenced blocks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…reign RELEASE lines (#2498) * docs(agnote): WS2 RELEASE + lane sweep — evidence for owners, no foreign RELEASE lines Two entries. RELEASE — WS2 (z890's coordination plan) is complete inside its 72h TTL. Eight PRs merged: #2482 claim+handoff+corrections, #2483 ci-expedition skill, #2484 claude-pmoves delegation, #2485 submodule gap runbook, #2486 up-* inventory, #2488 validate-command-anchors, #2494 first-contact + guard routing table, #2495 Danger Room handoff to SPARK. pmoves/mk/infra.mk untouched throughout — z890's #2480, no collision. The entry records what the audit found BEYOND its enumerated items, because that is the reusable part: a gate can advertise coverage it does not have (three separate instances, each caught by review rather than by me); the always-loaded orientation file misdirects first contact; the guard's own routing table has two dead roads; and patterns.yaml is the pattern worth generalizing while pre-tool.sh duplicates 5 of its entries minus the affordance. It also records four corrections to my own prior work — the wrong 13-of-15 figure, the retracted hf-mcp-server entry, the dangerous first up-* retire list, and the yt-cookies pair that was never a duplicate. A closeout that only lists wins is not a closeout. NOTE — lane sweep. 115 CLAIM against 119 RELEASE. Four Mavis lanes verified shipped and missing only a RELEASE (harness v0 #2437/#2443/#2450, multi-fork follow-ups #2477, OpenRoom slice 2, creative-pipeline v0). Four older lanes still open with no PR cited and nothing found merged, now 8-10 days. Mine that are correctly still open: #2446 draft, #2468 held for review, and the SPARK handoff awaiting its CLAIM. ZERO RELEASE lines written on another agent's behalf — verified in the diff. Those lanes are Mavis's to close under Village Rule; this records evidence so they can close from it rather than from memory. Kept distinct from the KIMI-SPARK / CRUSH stale claims, which need a release OR re-claim — different category, and conflating them would make the ping inaccurate. Verified: make -C pmoves validate-command-anchors passes. Note for follow-up: dogfooding this entry surfaced a real false-positive generator in MAKE_CITE_RE — `-C \S+` swallows a closing backtick, so prose that backticks "make -C pmoves" alone captures the following word as a target. Fixed separately, not folded in here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(agnote): state the counting method, and stop treating merge as acceptance Three review findings, all correct, all mine. 1. THE TOTALS WERE NOT REPRODUCIBLE. I published "115 CLAIM against 119 RELEASE" with no method attached. Recounting three ways on the same file: anchored bullet rows 115 / 119 <- what I published token anywhere in text 284 / 221 (prose mentions) timestamped, no anchor 116 / 119 and the 2026-08-07 sweep reported 121 / 115 on a fourth. None of these is wrong; a bare number with no pattern is. The entry now states the exact regex, lists what the other methods give, and says to treat the ratio as a rough signal rather than a metric — the per-lane table is the checkable part. 2. MERGE IS NOT RUNTIME ACCEPTANCE. I listed OpenRoom slice 2 under "verified shipped, missing only a RELEASE" on the strength of #2437 merging. That lane was claimed against six handoff priorities with room-level acceptance, and #2437 is scaffold plus iframe wiring. Merging it does not demonstrate the rooms render. 3. Same for line 1723: it covers three deliverables including fork-side consumers, and #2477 merging in PMOVES.AI says nothing about whether the fork consumers landed. Both are now "merged, acceptance unverified" rather than ready-to-release, with the reasoning stated so the owner closes from runtime evidence instead of from my table. This is precisely the error the register exists to prevent, made by the sweep that exists to catch it — which is worth leaving visible rather than quietly correcting. Every gate I shipped this week was weaker than advertised until something proved it could say no; this one was a bookkeeping claim that had not been asked to reproduce itself. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…P creds silently empty
`install-claude-pmoves-command.sh` installs the command by two routes: an rc
function holding the launcher's absolute path, and a ~/.local/bin/claude-pmoves
symlink for shells that don't source the rc. The two behaved differently.
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." && pwd)"
Via the rc function BASH_SOURCE[0] is the real path and ROOT is the repo. Via the
PATH symlink BASH_SOURCE[0] is ~/.local/bin/claude-pmoves, so dirname/../.. is
$HOME — and both the shared env file and .claude/mcp.json miss.
It failed as a WARN, not an error: the launcher printed the warning and exec'd
claude anyway, producing a session that looks healthy with every cred-dependent
MCP dark. Same failure class as #2484, different entrypoint.
Two changes:
1. Walk symlinks before deriving ROOT. Pure-bash loop handling relative link
targets, no readlink -f dependency.
2. Validate ROOT against a marker file instead of trusting the computation. The
sibling launchers already do this — crush-pmoves tests
$candidate/pmoves/Makefile, pmoves-mini tests
$candidate/pmoves/tools/mini_cli.py, and both reject a failing candidate.
That validation, not their path arithmetic, is why they survived the same
trap. A launcher whose whole job is loading repo-relative config must not
proceed when it cannot find the repo, so this now hard-exits with a fix hint.
Adds a PMOVES_REPO_ROOT override as the escape hatch.
Verified on B850 (Knuckles), all four routes:
PATH symlink route loaded 373 vars (was: 0, two WARNs)
real-path route loaded 373 vars
PMOVES_REPO_ROOT override honored
bogus root (=/tmp) exit 1 + actionable error
The surrounding launcher design was audited against the Claude Code docs in the
same pass and is correct as written: --mcp-config is variadic (<configs...>) so
the `=` form is required; omitting --strict-mcp-config is what keeps the per-node
.mcp.json merged; ${VAR} in the roster does resolve from Claude Code's own process
env, which is why sourcing the shared env before exec is the right mechanism; and
.claude/mcp.json is not a scope Claude reads on its own, so the explicit
--mcp-config really is required. ROOT derivation was the only defect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…P creds silently empty
`install-claude-pmoves-command.sh` installs the command by two routes: an rc
function holding the launcher's absolute path, and a ~/.local/bin/claude-pmoves
symlink for shells that don't source the rc. The two behaved differently.
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." && pwd)"
Via the rc function BASH_SOURCE[0] is the real path and ROOT is the repo. Via the
PATH symlink BASH_SOURCE[0] is ~/.local/bin/claude-pmoves, so dirname/../.. is
$HOME — and both the shared env file and .claude/mcp.json miss.
It failed as a WARN, not an error: the launcher printed the warning and exec'd
claude anyway, producing a session that looks healthy with every cred-dependent
MCP dark. Same failure class as #2484, different entrypoint.
Two changes:
1. Walk symlinks before deriving ROOT. Pure-bash loop handling relative link
targets, no readlink -f dependency.
2. Validate ROOT against a marker file instead of trusting the computation. The
sibling launchers already do this — crush-pmoves tests
$candidate/pmoves/Makefile, pmoves-mini tests
$candidate/pmoves/tools/mini_cli.py, and both reject a failing candidate.
That validation, not their path arithmetic, is why they survived the same
trap. A launcher whose whole job is loading repo-relative config must not
proceed when it cannot find the repo, so this now hard-exits with a fix hint.
Adds a PMOVES_REPO_ROOT override as the escape hatch.
Verified on B850 (Knuckles), all four routes:
PATH symlink route loaded 373 vars (was: 0, two WARNs)
real-path route loaded 373 vars
PMOVES_REPO_ROOT override honored
bogus root (=/tmp) exit 1 + actionable error
The surrounding launcher design was audited against the Claude Code docs in the
same pass and is correct as written: --mcp-config is variadic (<configs...>) so
the `=` form is required; omitting --strict-mcp-config is what keeps the per-node
.mcp.json merged; ${VAR} in the roster does resolve from Claude Code's own process
env, which is why sourcing the shared env before exec is the right mechanism; and
.claude/mcp.json is not a scope Claude reads on its own, so the explicit
--mcp-config really is required. ROOT derivation was the only defect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…CP creds silently empty (#2538) * fix(launcher): claude-pmoves via PATH symlink resolved ROOT=$HOME, MCP creds silently empty `install-claude-pmoves-command.sh` installs the command by two routes: an rc function holding the launcher's absolute path, and a ~/.local/bin/claude-pmoves symlink for shells that don't source the rc. The two behaved differently. ROOT="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." && pwd)" Via the rc function BASH_SOURCE[0] is the real path and ROOT is the repo. Via the PATH symlink BASH_SOURCE[0] is ~/.local/bin/claude-pmoves, so dirname/../.. is $HOME — and both the shared env file and .claude/mcp.json miss. It failed as a WARN, not an error: the launcher printed the warning and exec'd claude anyway, producing a session that looks healthy with every cred-dependent MCP dark. Same failure class as #2484, different entrypoint. Two changes: 1. Walk symlinks before deriving ROOT. Pure-bash loop handling relative link targets, no readlink -f dependency. 2. Validate ROOT against a marker file instead of trusting the computation. The sibling launchers already do this — crush-pmoves tests $candidate/pmoves/Makefile, pmoves-mini tests $candidate/pmoves/tools/mini_cli.py, and both reject a failing candidate. That validation, not their path arithmetic, is why they survived the same trap. A launcher whose whole job is loading repo-relative config must not proceed when it cannot find the repo, so this now hard-exits with a fix hint. Adds a PMOVES_REPO_ROOT override as the escape hatch. Verified on B850 (Knuckles), all four routes: PATH symlink route loaded 373 vars (was: 0, two WARNs) real-path route loaded 373 vars PMOVES_REPO_ROOT override honored bogus root (=/tmp) exit 1 + actionable error The surrounding launcher design was audited against the Claude Code docs in the same pass and is correct as written: --mcp-config is variadic (<configs...>) so the `=` form is required; omitting --strict-mcp-config is what keeps the per-node .mcp.json merged; ${VAR} in the roster does resolve from Claude Code's own process env, which is why sourcing the shared env before exec is the right mechanism; and .claude/mcp.json is not a scope Claude reads on its own, so the explicit --mcp-config really is required. ROOT derivation was the only defect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(launcher): fix the OTHER two launchers too, and guard the class with a test Review of the first cut found the fix was scoped to one of three files carrying the same code. Addresses all four findings. 1. TWO MIRRORS WERE STILL BROKEN (the important one) deploy/provision/crush-pmoves.sh and pmoves/scripts/claude-pmoves.sh carried the identical unvalidated `dirname "$BASH_SOURCE"` root derivation. Anyone symlinking either onto PATH reproduced the exact bug this branch fixes. Worse, the original commit message justified itself by citing "the siblings already validate" — pointing at pmoves/scripts/crush-pmoves (which does) while its deploy/provision twin (which does not) sat one directory away. A rationale that was never checked is as dangerous as a claim that was never checked. All three now carry a byte-identical walk. 2. PMOVES_REPO_ROOT COLLIDED WITH AN EXISTING CONSUMER pmoves/services/creator-operator/config.py:15 already reads PMOVES_REPO_ROOT. A developer exporting it to point creator-operator at a container path would silently redirect the launcher — and, because the new marker check then fails, hard-exit a launcher whose own location resolved perfectly. Renamed to PMOVES_LAUNCHER_ROOT. 3. HARD EXIT REMOVED A DOCUMENTED DEGRADED PATH The file's own header advertises `alias claude=/path/to/claude-pmoves.sh`. After a repo move the PATH symlink dangles, ROOT resolves empty, and the gate made `claude` itself unusable on that node — worse than the credless launch it replaced. It also printed an empty path in the error. Now: an explicit, existing PMOVES_ENV_SHARED is honoured with a warning about the skipped roster; only the no-override case hard-fails, and unresolved roots print `<unresolved>` rather than nothing. 4. CDPATH COULD CORRUPT THE RESOLVED PATH `dirname` yields a bare relative path when the script is invoked relatively, and `cd` consults CDPATH for such arguments — jumping elsewhere AND echoing the destination, embedding a newline in the captured directory. Now `CDPATH= cd -P -- ...` throughout. GUARD: deploy/provision/tests/test-launcher-root-resolution.sh Fixing one file and missing two is the failure this branch is about, so the drift is now detectable rather than trusted to review. The test asserts the symlink walk is byte-identical across all three launchers, that none reintroduces PMOVES_REPO_ROOT (comments excluded — the files legitimately name it to explain the avoidance), and that each resolves correctly when invoked through both an absolute symlink and a relative symlink chain. 12/12 pass. Negative control: reverting one launcher to the old walk fails with "walk DIFFERS ... fix all three together", so the guard is proven to catch the thing it exists for. Verified live on B850 through the installed PATH symlink: 373 vars loaded; still 373 under a hostile CDPATH; still 373 with PMOVES_REPO_ROOT=/tmp exported (no longer hijacks); PMOVES_LAUNCHER_ROOT=/tmp exits 1 with an actionable message. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sured not assumed The handoff and the mesh plan have read as open work since 2026-08-08 while four of the five enumerated items shipped and were released on 2026-08-09. A reader arriving at either document had no way to tell. Adds a STATUS block to the handoff with per-item state re-measured against origin/main @ 017de53 today, rather than carried forward from the release text: item 2 (ci-expedition trigger row) DONE #2483 item 3 (two claude-pmoves.sh) DONE #2484 item 4 (up-* sprawl) DONE #2486 + #2523 — now 88/88, was 89/88 item 5 (submodule build gap) DONE #2485 item 1 (cleanup de-duplication) PARTIAL — leak closed, 3 impls remain Two figures in the record were wrong and are corrected here rather than repeated: the retirement list is 8 both-zero targets, not 11, and the merged inventory flags two of those eight as load-bearing. Mesh Stage C's "no such file exists" correction is itself now stale — the value-engine spec is open as PR #2516, so Stage C is blocked on a merge rather than on an authorship gap. Stage A's figures are re-measured and hold (98 MB beats, 126 MB CATACLYSM, 38 PNGs), but the table under-scopes the job: the tracked surface is 75 blobs over 1 MiB totalling 259 MB, and the largest single file appears in no row. Method note recorded in the doc: git cherry reported four of these branches as unmerged because they were squash-merged, which rewrites patch-ids. File contents in origin/main settled it. The register conflict this PR carried was resolved append-only — the diff against main is 22/0, 159/0, 149/0, zero deletions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…sured not assumed The handoff and the mesh plan have read as open work since 2026-08-08 while four of the five enumerated items shipped and were released on 2026-08-09. A reader arriving at either document had no way to tell. Adds a STATUS block to the handoff with per-item state re-measured against origin/main @ 017de53 today, rather than carried forward from the release text: item 2 (ci-expedition trigger row) DONE #2483 item 3 (two claude-pmoves.sh) DONE #2484 item 4 (up-* sprawl) DONE #2486 + #2523 — now 88/88, was 89/88 item 5 (submodule build gap) DONE #2485 item 1 (cleanup de-duplication) PARTIAL — leak closed, 3 impls remain Two figures in the record were wrong and are corrected here rather than repeated: the retirement list is 8 both-zero targets, not 11, and the merged inventory flags two of those eight as load-bearing. Mesh Stage C's "no such file exists" correction is itself now stale — the value-engine spec is open as PR #2516, so Stage C is blocked on a merge rather than on an authorship gap. Stage A's figures are re-measured and hold (98 MB beats, 126 MB CATACLYSM, 38 PNGs), but the table under-scopes the job: the tracked surface is 75 blobs over 1 MiB totalling 259 MB, and the largest single file appears in no row. Method note recorded in the doc: git cherry reported four of these branches as unmerged because they were squash-merged, which rewrites patch-ids. File contents in origin/main settled it. The register conflict this PR carried was resolved append-only — the diff against main is 22/0, 159/0, 149/0, zero deletions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… lane-review claim (#2481) * docs(coord): 4090 tooling-audit handoff + mesh live-layer plan + z890 lane-review claim Post-13-PR coherence pass (z890 side), three coordination artifacts: - handoffs/tooling-audit-4090-drift-enumeration-2026-08-08.md — hands the ops/tooling drift audit to 4090 (node affinity: Archon/compose/fork/CI depth). Enumerates the 4-place cleanup drift, ci-expedition SKILL.md:29 pull_request_review row error, two divergent claude-pmoves.sh (6523 vs 642 B), ~87 up-* target sprawl, and the sibling-submodule build gap (13/15 fork services, invisible in diffs). All figures verified locally. - specs/mesh-live-collaboration-layer-plan-2026-08-08.md — mesh/JuiceFS reframed as the live collaboration layer, NOT a privacy purge. Repo stays public; history-rewrite premise dropped. Stage A large-binary offload actionable; Stages B/C are follow-ups. - AGNOTE4482PHI.t1.md — z890 CLAIM+RELEASE for the cleanup + coordination + lane-review work; pings KIMI-SPARK (VSS) + CRUSH (cipher Phase B) stale claims for release/re-claim; DROPs the z890 voice/#2317 pickup (left available); records WS1 worktree cleanup outcome (20 removed, main freed, 2 held with cause). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(agnote): resolve the 3 control items — sso-apps dup-of-main, z890-reconciled removed, crawl→Archon Operator decisions recorded: - pmoves-sso-apps: no relocation — survivors duplicate main; unique artifacts were already lost in the earlier partial remove. Dead remnant left for manual delete. - pmoves-z890-reconciled: removed (only local CHIT secrets-manifest regen drift). - archon.crawl.*: delegated to Archon (has live NATS visibility) to observe request/result subjects and decide retire-vs-keep. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(coord): address 3 Codex threads — build-gap count, up-* call sites, dead spec path All three were correct, including the one the trim classifier labelled false-positive. That is the third time the classifier has mislabelled a real Codex finding, so every thread was read by hand rather than trusted to the badge. T1 — "13 of 15" fork services (classified false-positive; it is real) The figure double-counted the same services re-declared across split overlays. Verified unique sibling-context builds: 7 submodules / 8 services. Left the old number visible with an inline correction rather than silently replacing it, so the audit owner knows which number to stop chasing. Codex's pointer to the existing correction at AGNOTE4482PHI.t1.md:1787 was accurate. T2 — up-* "consolidate/retire superseded siblings" `up-core-*` is a dependency chain, not three siblings: up-core-gpu invokes up-core-capable (Makefile:2567) which invokes up-core-hardened (:2562). Codex's line references check out exactly. Retiring the "superseded" sibling would break the canonical capable and GPU bring-up roads. This is the same trap the first pass fell into — up-core-hardened scored zero references because the grep excluded makefiles to skip *definitions*, and excluded *call sites* with them. Reframed the section as inventory candidates with the call-site caveat stated, and flagged up-cipher-nobuild as a keeper regardless of count (it is the existing workaround for item 5's build gap). T3 — value-engine-domino-v0-spec-2026-08-07.md does not exist Confirmed: no such file at this commit, no renamed equivalent, nothing in a repo-wide filename or content search. The thesis exists only in a node-local memory that whoever picks up Stage C cannot read. Rewritten so writing that spec is Stage C's first task rather than a reference it leans on — a dead path is worse than no path, because it reads as though requirements exist somewhere. Corrections are attributed inline as 4090-at-merge rather than folded into z890's text, since the surrounding documents are theirs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(coord): address 9 CodeRabbit threads — stale figures marked, contracts named, register append-only All nine checked against the tree. One resolved a live disagreement between two reviewers by finding both were right. up-* count: 89 AND 88 are both correct CodeRabbit said 88, this doc said 89. `grep -c '^up-[a-z0-9-]*:'` gives 89 definitions; `sort -u` gives 88 names. The gap is `up-openroom`, defined TWICE in pmoves/Makefile (:1279 and :1335) with byte-identical recipes — make emits an overriding-recipe warning and the second wins. Behaviourally harmless, but it is now the single safest item on the consolidation list, and it only surfaced because two counts disagreed. Cleanup drift is historical — leak count is 0 The table read as live state. Two copies already carried #2473 when it was written, infra.mk was fixed by z890 in #2480, and the ci-expedition copy shipped with item 2. Marked historical with the current status stated, so the audit owner does not re-audit a closed leak. claude-pmoves.sh — keep both, do not pick one CodeRabbit verified the two are not duplicates: deploy/provision loads env.shared + the MCP roster, pmoves/scripts provides positional-agent selection. "Pick the authoritative one ... or delete" would have lost a capability either way. Reworded to delegate-not-delete. Sibling-build list — dropped tokenism-ui The section contradicted the corrected list added earlier in the same document. tokenism-ui's context is a nested `./`, not a sibling submodule path, so it builds fine from a worktree. Now restates the verified 7 + n8n = 8 explicitly in both places so they cannot drift apart again. Two OPEN DECISION markers, because a plan that reads executable and is not is worse than one that says so - Stage A: git-lfs pointer vs remove-from-tree are not interchangeable — they differ in clone behaviour, CI cost, offline-node availability and rollback. Stage A cannot start until each table row names one, plus bootstrap/restore. - Stage B: "git holds source, mesh holds generated" is split-brain until writer, update trigger, atomic publish, read-only status, and divergence repair are named. docs-reconcile-check has no notion of a mesh copy, so it cannot detect divergence — extending it is Stage B work, not an assumption. Stage A inventory made reproducible: audit commands, observation date, and an explicit inclusion rule (tracked files only, submodules out of scope). Same unreproducible-number defect the WS2 register sweep was called out for. archon.crawl.* status recorded as PARKED + delegated to Archon, with the note that .claude/context/nats-subjects.md:1776-1777 still carries no status marker and belongs to whoever executes the retirement — this plan does not pre-empt it. Register: appended an UPDATE row rather than editing z890's entry CodeRabbit asked for supersession markers and missing branch/PR metadata on an append-only file. Both delivered as a new signed 4090 row carrying the corrected figures, the ownership correction (4090 claimed items 2-5, not 1-5; item 1 was z890's), and the branch/PR identifiers the original omitted. z890's text is byte-unchanged: 4 insertions, 0 deletions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(coord): close the WS2 handoff record — 4 of 5 items shipped, measured not assumed The handoff and the mesh plan have read as open work since 2026-08-08 while four of the five enumerated items shipped and were released on 2026-08-09. A reader arriving at either document had no way to tell. Adds a STATUS block to the handoff with per-item state re-measured against origin/main @ 017de53 today, rather than carried forward from the release text: item 2 (ci-expedition trigger row) DONE #2483 item 3 (two claude-pmoves.sh) DONE #2484 item 4 (up-* sprawl) DONE #2486 + #2523 — now 88/88, was 89/88 item 5 (submodule build gap) DONE #2485 item 1 (cleanup de-duplication) PARTIAL — leak closed, 3 impls remain Two figures in the record were wrong and are corrected here rather than repeated: the retirement list is 8 both-zero targets, not 11, and the merged inventory flags two of those eight as load-bearing. Mesh Stage C's "no such file exists" correction is itself now stale — the value-engine spec is open as PR #2516, so Stage C is blocked on a merge rather than on an authorship gap. Stage A's figures are re-measured and hold (98 MB beats, 126 MB CATACLYSM, 38 PNGs), but the table under-scopes the job: the tracked surface is 75 blobs over 1 MiB totalling 259 MB, and the largest single file appears in no row. Method note recorded in the doc: git cherry reported four of these branches as unmerged because they were squash-merged, which rewrites patch-ids. File contents in origin/main settled it. The register conflict this PR carried was resolved append-only — the diff against main is 22/0, 159/0, 149/0, zero deletions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
What
WS2 item 3 was enumerated as "two divergent
claude-pmoves.sh— pick the authoritative one." Reading both first, per the plan: they were never duplicates. They share a name and do different, mutually exclusive things.pmoves/scripts/(642 B)deploy/provision/(6523 B)--mcp-config=<roster>--agentEach ends in its own
exec claude, so you could have a PMOVES agent or working MCP creds, never both.Why it matters
make -C pmoves claude-pmoves(Makefile:4936) calls the agent-selecting one:So the documented way to launch the delivery agent came up with every cred-dependent MCP empty — which is the exact failure the provisioning script's header says it exists to prevent:
Reached by the path most likely to be used.
Fix
pmoves/scripts/claude-pmoves.shbecomes a thin delegate. It keeps its positional-agent shorthand and forwards--agent "$AGENT" "$@"to the provisioning launcher.Passthrough verified rather than assumed:
exec claudepaths in the launcher forward"$@"verbatim (lines 127 / 130 / 134)getopts, noshift, no$1handlingSo
--agentrides through in every branch, including the two degraded ones.Neither UI changes.
claude-pmoves control-agentstill works and now inherits creds.deploy/provision/claude-pmoves.shon its own is still the plain no-agent launch. Nothing is deleted —crush-pmoves.shandinstall-claude-pmoves-command.sh, which reference the provisioning script, are untouched.If the launcher is ever missing, this degrades to the previous behavior (agent loads, creds don't) with a warning rather than failing outright. The point is that the missing half becomes visible instead of silent — that's how this was invisible in the first place.
Verification
Reference check before touching anything:
End-to-end:
make -C pmoves claude-pmovesshould now start the delivery agent and surface the cred-dependent MCP tools. Previously it started the agent with them empty.Note for the coordination plan
Picking one and deleting the other — the item as written — would have removed a working capability either way. The "divergence" was a name collision hiding a missing composition. Worth correcting in the enumeration so the next reader doesn't retry the delete.
🤖 Generated with Claude Code