LearnNewsExamplesServices
Frontmatter
titlefix(data): api stores no longer auto-create a default Pipeline (#12170)
authorneo-opus-ada
stateMerged
createdAtMay 29, 2026, 2:04 PM
updatedAtMay 29, 2026, 2:22 PM
closedAtMay 29, 2026, 2:22 PM
mergedAtMay 29, 2026, 2:22 PM
branchesdevclaude/inspiring-villani-0feb1f
urlhttps://github.com/neomjs/neo/pull/12171
Merged
neo-opus-ada
neo-opus-ada commented on May 29, 2026, 2:04 PM

Authored by Claude Opus 4.8 (Claude Code). Memory-core orchestrator was deactivated this session, so no Origin Session ID is available.

FAIR-band: operator-directed PR (explicit request) — not autonomous lane self-selection; swarm band-gating N/A.

Resolves #12170

api-configured stores were silently getting a default Pipeline instance, so Store.load()'s if (me.pipeline) branch always shadowed the else if (me.api) remotes-api branch — an autoLoad: true api store never fired its RPC. Surfaced while dogfooding #12134 in a real websocket-backed remotes-api app. A one-line guard in beforeSetPipeline() keeps api stores at pipeline === null so they reach the api branch (which already carries the #12132/#12134 fix).

Evidence: L1 (unit: api store → pipeline === null + non-api default preserved; api-branch reachability is deterministic once pipeline === null) → L3 live RPC confirmation deferred to the consuming app post dependency-bump. Residual: live autoLoad ws RPC.

Root cause

ClassSystemUtil.beforeSetInstance(value, Pipeline, …) mints a default instance for a falsy value (if (!config && DefaultClass) Neo.create(...)). beforeSetPipeline() only skipped that path for the url case, so every api store got a spurious Pipeline (plus its onPipelinePush listener) and load() never reached the api branch.

The fix

src/data/Store.mjs beforeSetPipeline(): return null early when me.api is set — api stores load via remotes-api, never a pipeline. The url guard simplifies to !value && me.url (the !me.api term is now subsumed by the early return). Order-independent: Neo resolves reactive configs on demand via configSymbol, so me.api reads correctly regardless of config processing order.

Deltas from ticket

None of substance — implements #12170's prescribed if (me.api) return null guard verbatim (strict api XOR pipeline form). The !value && me.api permissive variant (which would preserve runtime api→pipeline switching) was considered and rejected per the ticket, weighed as a ~0.001% case.

Test Evidence

New test/playwright/unit/data/StoreApiPipeline.spec.mjs — 3 cases: api → pipeline===null; api + autoLoad:truepipeline===null; non-api → default Pipeline preserved.

  • npm run test-unit -- test/playwright/unit/data/StoreApiPipeline.spec.mjs3 passed (555ms)
  • npm run test-unit -- test/playwright/unit/data/56 passed (830ms) — no regression across the Store/TreeStore suite

Post-Merge Validation

  • A consuming remotes-api app (api store + autoLoad: true) renders data over the websocket after npm update neo.mjs — i.e. load() fires the RPC end-to-end.
github-actions commented on May 29, 2026, 2:05 PM

🚨 Agent PR Body Lint Violation

@neo-opus-ada — your PR body on PR #12171 does not match the pull-request template structure.

Required action: read .agents/skills/pull-request/SKILL.md BEFORE editing the PR body. The skill points at:

  • Minimum-viable PR body structure: .agents/skills/pull-request/references/pull-request-workflow.md §9
  • Self-Identification mandate: .agents/skills/pull-request/references/pull-request-workflow.md §5

Do NOT compose a substitute template or hallucinate section headings. The validator checks more structural anchors than this comment names. The only reliable path to passing is reading the actual workflow file and following its structure.

Diagnostic hint: visible anchors appear present but the structural template anchors do not.

Visible anchors missing (full list)

(none — visible layer passed; invisible structural layer caught the miss)

This is the CI tool-boundary lint companion to PR #11494's MCP manage_pr_review validator and PR #11502's agent-pr-review-body-lint.yml reviewer-side lint. Resolves #11501.