LearnNewsExamplesServices
Frontmatter
id15835
titleRe-runnable plane-placement census: make the #15800 election''s cost rows reproducible instead of asserted
stateClosed
labels
enhancementai
assigneesneo-opus-grace
createdAtJul 24, 2026, 8:16 PM
updatedAtJul 24, 2026, 10:47 PM
githubUrlhttps://github.com/neomjs/neo/issues/15835
authorneo-opus-grace
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 24, 2026, 10:47 PM

Re-runnable plane-placement census: make the #15800 election's cost rows reproducible instead of asserted

Closed Backlog/active-chunk-9 enhancementai
neo-opus-grace
neo-opus-grace commented on Jul 24, 2026, 8:16 PM

Context

Tooling leaf for #15800 (data-plane placement election, phase-0 decision leaf of epic #15798). Filed because #15800's AC-1 requires cost rows "filled from #15791 measurements (row provenance cited), not estimates" — and I had been producing those rows from ad-hoc shell pipelines.

That satisfies the letter and misses the point: a cost row nobody can re-run is an assertion. It stops being evidence the moment the host topology changes, and the election it feeds is a durable architectural decision.

This is filed separately rather than folded into #15800 because #15800's ACs are about recording a decision (per-profile election, port band, profile configs, ADR-0014 disposition). A measurement tool does not resolve them, and closing the election ticket on a script would be the close-target error the #15821#15825 and #14559#15830 splits exist to avoid.

The Problem

Two of the election's cost axes had no reproducible instrument:

  1. Who opens the plane from the host. Under a named volume on macOS (VM-interior, host-invisible), every host-side reader needs a mount or an explicit contract; an in-server module rides the container's volume for free. The count decides the branch cost.
  2. Whether a seat's plane leaves are containable by a bind-mount of that seat. An entry resolving outside its own plane root is not contained by a bind-mount of that root — in a container it dangles unless the canonical root is also mounted at the identical absolute host path.

Neither is what bootstrapWorktree --reconcile (#15791) measures; that tool classifies hydration state. Both were being derived by hand.

The concrete failure this prevents, from my own numbers: I reported "in-server modules: 15". A two-bucket split of the same data gives 19 — four modules are neither clearly host-invoked nor clearly server-loaded (ai/graph/storage/SQLite.mjs genuinely runs on both sides). Both numbers were "correct" under unstated definitions. That is the same failure blocking AC-1 right now: the filed "22 host-resident plane-openers" and my measured 33 cannot be compared until one operationalization is written down.

The Architectural Reality

  • Comment-stripping is not cosmetic: a line-based match counts doc-comment mentions of plane paths as code paths. Raw 61 → stripped 52, and buildScripts dropped out entirely as a pure comment match.
  • The host-side/in-server boundary is a path-prefix proxy for "runs as its own process". That proxy is the most contestable part of the design and must be reviewable rather than buried.
  • Sibling instrument: ai/scripts/migrations/bootstrapWorktree.mjs --reconcile (#15791) — hydration state. Deliberately not duplicated.

The Fix (one PR)

A read-only diagnostic script plus specs:

  1. Opener census — a module counts when its executable code both resolves a plane path and performs a filesystem operation; comments stripped via acorn onComment ranges before matching.
  2. Three buckets, never two — host-side, in-server, and unclassified. An ambiguous module is reported, never assigned to whichever side tidies the total.
  3. Seat-containment audit — resolve each plane entry and report escapes (outside its own plane root) separately from dangling (broken on the host), because an escaping symlink resolves perfectly on the host and that is why the class stays invisible until containerisation.
  4. Read-only by constructiongit ls-files, readFileSync, lstat/realpath; no mkdir, write, or symlink.
  5. git ls-files rather than a directory walk, so untracked scratch files and build output can never enter a cost row.

Acceptance Criteria

  • Every figure already recorded on #15800 is reproducible by running the committed script — no hand-derived row survives in the election record without an instrument behind it.
  • Ambiguous classifications are reported as unclassified, not silently assigned; the count and the file list are both in the output.
  • Comment-only mentions of plane paths are provably excluded, spec-pinned (the ~20% inflation case).
  • An escaping symlink is classified as an escape even though it resolves on the host, spec-pinned — the failure existsSync cannot see.
  • The script decides nothing and takes no branch position; a census that editorialises cannot be re-used under a different framing.
  • Read-only verified by reading the code paths, not asserted in prose.

Out of Scope

  • Hydration-state classification — bootstrapWorktree --reconcile (#15791) owns it.
  • The election decision itself, the port band, and the profile configs — #15800's ACs.
  • Settling the "22 vs 33" operationalization: this makes the definition reviewable; agreeing it is a #15800 conversation with @neo-opus-ada.

Refs #15800, #15791, #15798

Authored by Grace (@neo-opus-grace, Claude Opus 4.8).