Skip to content

docs(ops): runbook for the submodule build & mount gap — Docker creates missing binds as directories - #2485

Merged
POWERFULMOVES merged 1 commit into
mainfrom
docs/submodule-build-gap-runbook
Aug 8, 2026
Merged

docs(ops): runbook for the submodule build & mount gap — Docker creates missing binds as directories#2485
POWERFULMOVES merged 1 commit into
mainfrom
docs/submodule-build-gap-runbook

Conversation

@POWERFULMOVES

Copy link
Copy Markdown
Owner

What

WS2 item 4. A runbook for the case where the compose file is correct, the fork repo is correct, and it still fails — because the checkout can't satisfy the declaration.

Deliberately not a ratchet. The gap is a property of the checkout, so it cannot appear in a diff, and CI cannot catch it: every workflow checks out with submodules: recursive, so the validators run against a fully populated tree and correctly pass.

Two classes

Class A — build contexts. 8 services from 7 registered submodules (PMOVES-Archon, Pmoves-cipher, PMOVES.YT, PMOVES-OpenRoom, PMOVES-llama-throughput-lab, PMOVES-transcribe-and-fetch, PMOVES-n8n). The split overlays re-declare the same contexts rather than adding services — which is what inflated my earlier "13 of 15" count. Jellyfin is not in the list; it builds locally. Fails loudly.

Class B — bind-mount sources. 5 mounts from 2 submodules. This is the one that hurts:

Docker does not error on a missing bind source — it creates it, as a directory.

So a file mount silently becomes a directory mount, and the container then fails on its own config. The error never mentions submodules:

Container Error Actual cause
supabase-vector Configuration error. error=Is a directory (os error 21) vector.yml created as a directory
supabase-edge-functions could not find an appropriate entrypoint functions/ created empty

The diagnostic worth memorizing: a bind source that is a directory where a file is expected means the submodule was unpopulated when up ran.

Two non-obvious steps in the fix

Both cost real time to discover:

  1. Docker's stubs block the clone. They make the submodule directory non-empty, so git submodule update --init refuses with destination path ... already exists and is not an empty directory. Clear them first — the runbook uses -type d -empty as the guard, so the command cannot reach a real file, plus a find -type f | wc -l check beforehand.

  2. docker start is not enough for a file mount. Docker records the mount type at container creation, so a container created against a directory keeps failing even after the source becomes a real file:

    not a directory: Are you trying to mount a directory onto a file (or vice-versa)?
    

    Needs make -C pmoves supa-recreate-svc SVC=<name>. Directory mounts do recover on a plain docker start, since the type already matches — which is why edge-functions came back and vector didn't.

Worked example (2026-08-08, this node)

Two containers crash-looping since 08-05, supabase-vector at 78 restarts. Cause: 28 of 33 running containers were launched from a second clone whose 57 submodules were all unpopulated — only 5 commits behind main, not abandoned, just never --inited.

Two findings from that incident are in the doc because both would otherwise be re-derived the hard way:

  • supabase-kong declares two file mounts from the same submodule and was never affected. Its container has HostConfig.Binds: null and its Kong config inlined into the entrypoint. I checked before writing it up as broken — check the container, not the compose file, before assuming a service is affected.
  • git submodule status is the fast triage. Leading - = unpopulated (this bug). Leading + = populated at a different commit than the gitlink, which is drift and a different problem.

Worktrees

Worktrees don't inherit submodules, so every service above is unrunnable from a fresh one. The doc gives three options cheapest-first, and names up-cipher-nobuild as the existing escape hatch — flagged as a keeper for the WS2 item-5 target-consolidation pass, where it would otherwise look like redundant sprawl.

If a check is ever wanted

Runtime, not build time: on up, assert that every declared file-kind bind source is a file on disk. That is a handful of test -f calls at the moment it matters, not a new workflow. Noted in the doc rather than built, since nothing is currently broken by its absence and the last time I added a gate one already existed elsewhere.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@POWERFULMOVES, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 4 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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 87e5934b-9b72-4571-943b-a83b538683ca

📥 Commits

Reviewing files that changed from the base of the PR and between 22c78fb and 0e6351d.

📒 Files selected for processing (1)
  • pmoves/docs/operations/SUBMODULE_BUILD_AND_MOUNT_GAP.md

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the docs Documentation label Aug 8, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e56cf1b9f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pmoves/docs/operations/SUBMODULE_BUILD_AND_MOUNT_GAP.md Outdated
Comment thread pmoves/docs/operations/SUBMODULE_BUILD_AND_MOUNT_GAP.md Outdated
Comment thread pmoves/docs/operations/SUBMODULE_BUILD_AND_MOUNT_GAP.md Outdated
…mpose that still fails

WS2 item 4. A runbook and not a ratchet: the gap is a property of the CHECKOUT,
not of any file, so it cannot appear in a diff — and both relevant CI gates
decline to check it.

Two classes, verified against origin/main @ 22c78fb.

CLASS A — build contexts. 8 services from 7 registered submodules (Archon,
cipher, PMOVES.YT, OpenRoom, llama-throughput-lab, transcribe-and-fetch, n8n).
Split overlays re-declare the same contexts rather than adding services. Fails
loudly at build time. Includes the second n8n path at
pmoves/compose/docker-compose.core.yml (../../PMOVES-n8n), which is live via
pmoves-integrations-ci.yml:73 and which a single-`../` scan misses.

CLASS B — bind-mount sources. 5 mounts from 2 submodules. The dangerous one:
Docker does NOT error on a missing bind source, it CREATES it as a directory. A
file mount silently becomes a directory mount and the container then fails on its
own config, so the error never mentions submodules.

WHY CI DOESN'T CATCH IT — corrected. An earlier draft said the workflows check
out with `submodules: recursive` and therefore see a populated tree. That is
wrong; neither validator checks out submodules at all
(validate-dockerfile-paths-ratchet.yml:54, validate-composes-ratchet.yml:41).
They pass for two different DELIBERATE reasons:

  - validate_dockerfile_paths.py skips anything failing
    _is_in_scope_build_target(), with the reasoning in the source: sibling
    submodule / vendor / provisions paths are "external repos the ratchet can't
    statically check". Class A is a known, accepted blind spot.
  - validate-composes never inspects bind sources; Class B is outside its
    question.

That is a defensible split — a static ratchet genuinely cannot reason about an
external repo's contents — but it means the only thing between this and a silent
production failure is a human knowing about it.

BRING-UP now covers both stopped services, and says why they differ. The recovery
stops vector AND edge-functions; an earlier draft only recreated vector, leaving
edge-functions down after the "complete" fix. Docker records the mount TYPE at
creation, so a FILE mount needs `supa-recreate-svc` while a DIRECTORY mount
recovers on a plain `docker start`. Getting that backwards costs a confusing
round — edge-functions came straight back while vector refused, from the same
fix. Non-Supabase services use `recreate-svc SVC=<name>` (Makefile:553).

up-cipher-nobuild DOWNGRADED from "escape hatch" to what it actually is. Its
recipe is `--no-build --force-recreate cipher-api`, and cipher-api declares only
a build: stanza with no image:, so it reuses an image Compose already built
LOCALLY. Its own help text calls it a gitlink-drift workaround. On a node or
worktree where that image was never built it cannot start Cipher — so it is not
a fresh-checkout answer, and the worktree section no longer offers it as one.

Worked example from 2026-08-08 on the 4090: two containers crash-looping since
08-05, supabase-vector at 78 restarts, 28 of 33 running containers from a SECOND
clone whose 57 submodules were all unpopulated.

Two incident findings kept because both would otherwise be re-derived the hard
way: supabase-kong declares two file mounts from the same submodule and was NEVER
affected (HostConfig.Binds is null; its config is inlined into the entrypoint —
check the container, not the compose file); and `git submodule status` is the
fast triage, where `-` is unpopulated (this bug) and `+` is gitlink drift
(different problem).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@POWERFULMOVES
POWERFULMOVES force-pushed the docs/submodule-build-gap-runbook branch from 3e56cf1 to 0e6351d Compare August 8, 2026 14:11
POWERFULMOVES added a commit that referenced this pull request Aug 8, 2026
…, not a worktree escape hatch

Caught on review of the companion runbook (#2485). This file listed
up-cipher-nobuild as keep-regardless-of-reference-count because it was "the only
way cipher-api comes up from a worktree". That reason is wrong.

Its recipe is `--no-build --force-recreate cipher-api`, and cipher-api declares
only a build: stanza with no image:. So `--no-build` can only reuse an image
Compose already built LOCALLY under its default tag — on a cold worktree, or a
node that never built it, there is nothing to reuse and it cannot start Cipher.

Its own help text was accurate and I read past it: "applies env/port changes when
the Pmoves-cipher submodule build is unavailable (gitlink drift)". Gitlink drift
means you HAVE the image and the submodule is at the wrong commit — the opposite
of a fresh checkout.

Verdict is unchanged — still a keeper, still no substitute, still zero
references. Only the reason changes, and the wrong reason is left visible rather
than quietly swapped, since a keep-this justified by a false premise is exactly
what a reviewer needs to be able to re-check.

Also adds a `text` language identifier to the singleton block (MD040).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@POWERFULMOVES
POWERFULMOVES merged commit f09719c into main Aug 8, 2026
31 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the docs/submodule-build-gap-runbook branch August 8, 2026 14:25
POWERFULMOVES added a commit that referenced this pull request Aug 8, 2026
…Makefile edits (#2486)

* docs(ops): up-* target inventory — 88 targets grouped, 11 with zero references

WS2 item 5. Inventory only: no Makefile is edited by this commit. The operator
picks what to retire; consolidation is a separate follow-up.

88 targets — 82 in pmoves/Makefile, 6 across mk/{egress,infra,yt-cookies}.mk.
Grouped into 12 families plus 46 singletons, each with a count of how many files
outside the makefiles mention it.

The count is a conversation starter, not a kill list, and the doc says so up
front. A zero means nothing in the repo writes the target down — not that it is
dead. Shell history is not in the repo. Two of the eleven zero-reference targets
are already known to be load-bearing:

  up-cipher-nobuild  the documented escape hatch for the submodule build gap;
                     the only way cipher-api comes up from a worktree
  up-tokenism        deliberate Known Road from #2326, env fix in #2334,
                     paired with down-tokenism

That up-cipher-nobuild scores 0 while being the answer to a live operational
problem is the argument for inventory-only in one line.

Patterns worth an operator decision, ordered by risk:

  1. up-yt-cookies-rebuild (0) vs up-yt-cookies-recreate (1) — the clearest
     near-duplicate pair in the set. One pair, one decision.
  2. The -hardened suffix looks like a convention that only partly took:
     up-core-hardened 0, up-workers-hardened 0, up-agents-hardened 4,
     up-yt-hardened 2. One decision covers four targets. Retiring them does not
     retire hardening — that lives in docker-compose.hardened.yml and the
     hardening-validation workflow.
  3. up-all (21) vs up-all-new (5) — both referenced, and the names give no clue
     which supersedes which. That ambiguity is the cost. Needs a naming decision
     more than a delete.
  4. up-agents-* (8) splits along two independent axes — image source
     (published/integrations/standalone) and profile (ui/stack/hardened/auto).
     Possibly flags on one target rather than seven targets. Biggest surface,
     most likely to break a habit, so last.

Explicitly NOT redundant: up-archon-native vs up-archon-submodule. Archon 0.6.0
is TS/SQLite-native with its own compose, so those are two different
deployments. Keep both.

Method and its bias are recorded so the numbers can be re-derived and doubted:
word-boundary matching lets a prefix target inflate on its own suffixes (up-yt
matches inside up-yt-egress). That biases HIGH counts upward and never creates a
false zero — so the zero list is trustworthy and the ordering among high-count
targets is not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ops): correct the up-cipher-nobuild rationale — drift workaround, not a worktree escape hatch

Caught on review of the companion runbook (#2485). This file listed
up-cipher-nobuild as keep-regardless-of-reference-count because it was "the only
way cipher-api comes up from a worktree". That reason is wrong.

Its recipe is `--no-build --force-recreate cipher-api`, and cipher-api declares
only a build: stanza with no image:. So `--no-build` can only reuse an image
Compose already built LOCALLY under its default tag — on a cold worktree, or a
node that never built it, there is nothing to reuse and it cannot start Cipher.

Its own help text was accurate and I read past it: "applies env/port changes when
the Pmoves-cipher submodule build is unavailable (gitlink drift)". Gitlink drift
means you HAVE the image and the submodule is at the wrong commit — the opposite
of a fresh checkout.

Verdict is unchanged — still a keeper, still no substitute, still zero
references. Only the reason changes, and the wrong reason is left visible rather
than quietly swapped, since a keep-this justified by a false premise is exactly
what a reviewer needs to be able to re-check.

Also adds a `text` language identifier to the singleton block (MD040).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(ops): count makefile callers too — the first retire list was dangerous

Three review findings, all correct, and the third invalidates the method rather
than a detail.

MAKEFILE CALLERS WERE NOT COUNTED. The scan excluded pmoves/Makefile and
pmoves/mk/ to avoid counting each target's own definition. That also excluded
every CALL SITE, so targets invoked by other targets scored zero and landed on a
retire list. Three did:

  up-core-capable  ->  up-core-hardened          (Makefile:2542)
                          |-> up-workers-hardened  (Makefile:2506)
                          `-> up-agents-hardened   (Makefile:2507, 2533)

Retiring up-core-hardened on its zero external count breaks up-core-capable.
The file now carries two counts — external references and intra-makefile callers
— and a target is a candidate only when BOTH are zero. That drops the list from
11 to 8 and removes up-core-hardened, up-workers-hardened, and up-creator-collab
(Makefile:3846).

The withdrawn "-hardened is an abandoned convention" reading was the opposite of
true: it is a working dependency-ordered bring-up chain.

up-yt-cookies-rebuild IS NOT A DUPLICATE. The first revision called it "the
clearest near-duplicate pair in the whole set" and put it first in the retire
order. mk/yt-cookies.mk:141-149 shows two distinct flows — `--force-recreate`
for env changes, `--build --force-recreate` for code changes. Consolidating
either direction is a real loss: no image-rebuild path, or every routine env
refresh pays for a rebuild. Kept, with the distinction documented.

THE REPRODUCTION COUNTED ITSELF. This file names every target, so running the
documented command on the committed tree turns every zero into a one and the
list cannot be reproduced from the commit that states it. The commands now
exclude UP_TARGET_INVENTORY.md and say to scan the parent revision.

Both scans are now given, with their biases stated — including the one that
caused this: scan (1) answers "does anything written down mention this", NOT "is
anything broken if this disappears". Only the caller scan answers the second,
and treating the first as sufficient is what made the original retire list
unsafe.

Both counts still miss a human who types a target and never writes it down.
That caveat is unchanged and is why this file remains inventory-only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Aug 9, 2026
…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>
POWERFULMOVES added a commit that referenced this pull request Aug 16, 2026
…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>
POWERFULMOVES added a commit that referenced this pull request Aug 18, 2026
…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>
POWERFULMOVES added a commit that referenced this pull request Aug 18, 2026
… 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>
POWERFULMOVES added a commit that referenced this pull request Aug 18, 2026
Operator asked for a refresh against current main rather than a cold assignment of
an 8-day-old handoff. Re-measured against origin/main @ 017de53. Append-only --
z890's and 4090's original text is untouched.

The scope holds. Three claims re-verified rather than assumed:

  E2B gitlink still drifted -- working copy 7a38b33b, origin/main records 78f7c5d8.
  The pre-req is unresolved and is the first task, not a footnote.
  Still 31 skills. Still zero skills declaring the verification contract.

One thing is newly available. Acceptance criterion 1 ("sandbox has populated
submodules") was an eyeball check when written; it can now be two commands, because
SUBMODULE_BUILD_AND_MOUNT_GAP.md merged (#2485) and bind-sources-check landed
(#2581). A sandbox passing both cannot silently be the empty-submodule case, which
is the case that yields confident false negatives.

One thing got sharper, and it changes the artifact contract. Piece 5 cites
archon.crawl.* as "a subject registered against an operation nobody built". That was
too kind. It HAS a handler: _process_crawl echoes the request's own metadata back as
extracted_text and fragments, stamped "status": "completed", and nothing fetches the
URL (documented 2026-08-16, #2582).

An unimplemented subject times out and you notice. That one reports success. For
skill.verified.v1 the same failure is a receipt reading PASS because the harness
echoed what the request handed it -- so the artifact must carry the skill content
hash AND something only an actual run could produce: exit codes, wall time, emitted
paths. A receipt derivable from the request alone is archon.crawl.result.v1 under a
different name.

That promotes acceptance (5) -- a deliberately broken skill must produce a RED
artifact -- from "the one I would cut last" to the one that defines the lane. A
Danger Room that cannot emit RED is a publish-and-echo circuit.

Not claimed by 4090. SPARK remains the named owner; this refreshes the lane, it does
not take it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Aug 18, 2026
#2584)

Operator asked for a refresh against current main rather than a cold assignment of
an 8-day-old handoff. Re-measured against origin/main @ 017de53. Append-only --
z890's and 4090's original text is untouched.

The scope holds. Three claims re-verified rather than assumed:

  E2B gitlink still drifted -- working copy 7a38b33b, origin/main records 78f7c5d8.
  The pre-req is unresolved and is the first task, not a footnote.
  Still 31 skills. Still zero skills declaring the verification contract.

One thing is newly available. Acceptance criterion 1 ("sandbox has populated
submodules") was an eyeball check when written; it can now be two commands, because
SUBMODULE_BUILD_AND_MOUNT_GAP.md merged (#2485) and bind-sources-check landed
(#2581). A sandbox passing both cannot silently be the empty-submodule case, which
is the case that yields confident false negatives.

One thing got sharper, and it changes the artifact contract. Piece 5 cites
archon.crawl.* as "a subject registered against an operation nobody built". That was
too kind. It HAS a handler: _process_crawl echoes the request's own metadata back as
extracted_text and fragments, stamped "status": "completed", and nothing fetches the
URL (documented 2026-08-16, #2582).

An unimplemented subject times out and you notice. That one reports success. For
skill.verified.v1 the same failure is a receipt reading PASS because the harness
echoed what the request handed it -- so the artifact must carry the skill content
hash AND something only an actual run could produce: exit codes, wall time, emitted
paths. A receipt derivable from the request alone is archon.crawl.result.v1 under a
different name.

That promotes acceptance (5) -- a deliberately broken skill must produce a RED
artifact -- from "the one I would cut last" to the one that defines the lane. A
Danger Room that cannot emit RED is a publish-and-echo circuit.

Not claimed by 4090. SPARK remains the named owner; this refreshes the lane, it does
not take it.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant