LearnNewsExamplesServices
Frontmatter
id15842
titlePlane census: reconcile plane membership against the config contract instead of a name-shape proxy
stateClosed
labels
enhancementai
assigneesneo-opus-grace
createdAtJul 24, 2026, 9:15 PM
updatedAtJul 26, 2026, 3:17 AM
githubUrlhttps://github.com/neomjs/neo/issues/15842
authorneo-opus-grace
commentsCount2
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 26, 2026, 3:17 AM

Plane census: reconcile plane membership against the config contract instead of a name-shape proxy

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

Context

Successor for the deferred residual on #15835's Contract Ledger, flagged by @neo-gpt-emmy's review of PR #15836 as the durable fix behind the exact-head falsifiers that PR closes. Filed as its own ticket because #15836's Resolves #15835 must not bury it — same split discipline as #15821#15825 and #14559#15830.

The Problem

planePlacementCensus.mjs decides whether a module "opens the plane" by matching PLANE_PATH_SOURCE, which after PR #15836 recognises storagePaths., the AiConfig.<name>Path|Dir leaf shape, and literal .neo-ai-data. That closed the concrete miss (SwarmHeartbeatService via wakeDaemonHeartbeatAlivePath, and lifted the count 52 → 70), but it is still a name-shape proxy, not the config contract.

The failure it leaves open: configBase.mjs is the authority for which config leaves resolve into the plane. A leaf added there whose name does not end Path/Dir — e.g. a socket, a root, a store — is a real plane member the census silently drops. The election is decided on these counts, so a member that vanishes because of its name is exactly the authority-blindness @neo-gpt-emmy's [KB_GAP] named: the census invents its own definition of membership instead of reading the declared one.

The Architectural Reality

  • ai/scripts/diagnostics/planePlacementCensus.mjsPLANE_PATH_SOURCE (the shape proxy), censusPlaneOpeners.
  • ai/configBase.mjs — declares the plane-path leaves (backupPath, hierarchyPath, wakeDaemonHeartbeatAlivePath, socketPath, snapshotPath, dbPath, …).
  • The tension: the census is a diagnostic and importing the full AiConfig singleton (Neo bootstrap + Provider) into it is heavy and arguably a layering smell — which is why #15836 took the shape proxy. The durable fix needs a lightweight way to read the declared leaf names without paying full bootstrap, or an explicit accepted cost.

The Fix (direction)

Derive the plane-member leaf set from the config module's declarations and classify a read as a plane-path source when it references one of those leaves — so a leaf added to the config is picked up without a census edit, and a leaf removed stops matching. Options:

  1. Static-parse configBase.mjs for its declared * leaf names via acorn (no singleton import) — cheapest, no bootstrap, but couples to the declaration syntax.
  2. A pure-defaults export from the config layer listing the plane-member leaf names (the pure-defaults-module pattern ADR-0019 §5.5 already sanctions for non-entrypoints) — the census imports names only, no Neo.
  3. Accept the bootstrap and read AiConfig directly — simplest semantically, heaviest, and the layering question is real.

Recommend (2): it makes the contract explicit and shared, which is the point.

Acceptance Criteria

  • The census's plane-membership decision is derived from the config module's declared leaves, not a Path/Dir name shape — spec-pinned by adding a differently-named plane leaf to a fixture config and asserting the census sees it.
  • A leaf removed from the config stops being counted — the reconciliation is bidirectional, not additive.
  • The chosen mechanism does not import the full Neo/AiConfig bootstrap into the diagnostic, OR the PR states explicitly why that cost is accepted.
  • PLANE_PATH_SOURCE's JSDoc stops describing itself as a proxy once it reconciles against the contract — the disclosure and the code stay in sync (the both-sides-of-a-contract discipline).
  • #15835's ledger deferred-residual section links here.

Out of Scope

  • The four exact-head falsifiers — closed by PR #15836.
  • The election decision itself (#15800) and the WAL/containment axes.
  • Re-tuning HOST_SIDE_PREFIXES — a separate proxy with its own review.

Refs #15835, #15800, #15836

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