LearnNewsExamplesServices
Frontmatter
id14939
titleProvider explicit-ID replacement loses the live Store binding
stateClosed
labels
bugaicore
assigneesneo-gpt
createdAt7:35 AM
updatedAt8:17 AM
githubUrlhttps://github.com/neomjs/neo/issues/14939
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAt8:17 AM

Provider explicit-ID replacement loses the live Store binding

neo-gpt
neo-gpt commented on 7:35 AM

Context

PR #14920 fixes same-key replacement for provider-owned Store descriptors that use generated IDs. Exact-head direct probes at d66f04a1a8e9424758a0dd7b816c8f2414c43db0 verified that path across repeated replacements, ownership teardown, StoreManager registration, null/re-add, different keys, and external instances.

One supported variant remains: a descriptor carrying a caller-supplied explicit id. The operator directed this residual out of the PR review loop. This ticket is self-assigned to @neo-gpt; #14920 is not asked for another author cycle.

The Problem

For a same-key descriptor such as {module: Store, id: 'explicit-store'}, the cycle-5 generation suffix is bypassed by storeValue.id || baseId. The replacement therefore keeps the same serialized identity as the old instance. Config equality can suppress the provider setter even though the old instance was destroyed and a distinct replacement was constructed.

The observed failure is internally inconsistent:

  • provider.getStore(key) retains the destroyed old instance.
  • StoreManager.get('explicit-store') can point at a different live replacement that the provider cannot resolve.
  • Further replacements can hit duplicate-ID registration.
  • Caller-chosen identity cannot simply be rewritten to a generated ID without breaking the existing descriptor contract.

The Architectural Reality

  • src/state/Provider.mjs owns Store instances created from its stores descriptors and exposes them by provider key.
  • StoreManager is the registration authority for explicit Store IDs.
  • The generation mechanism introduced by #14920 is correct for internally generated IDs, but explicit IDs are public caller input.
  • The broader Neo.isEqual instance-equality semantics have framework-wide blast radius and are not automatically part of this narrow repair.

The Fix

Make same-key replacement with an explicit descriptor ID atomic and reference-correct inside state.Provider:

  1. Preserve the exact caller-supplied ID.
  2. Destroy and deregister the old provider-owned instance in a collision-safe order.
  3. Ensure the Provider setter commits the distinct replacement rather than suppressing it through ID-based equality.
  4. Ensure StoreManager resolves the same live instance returned by provider.getStore(key).
  5. Preserve the cycle-5 generated-ID path and external-instance ownership rules.

Escalate into a global Neo.isEqual change only if focused falsifiers prove the Provider boundary cannot solve the supported contract safely.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
state.Provider.stores.<key> explicit-ID descriptor Existing Provider descriptor contract + #14920 ownership model Same-key replacement preserves the ID and commits a distinct live replacement Fail loud; never retain a destroyed binding Provider JSDoc Sequential replacement spec
StoreManager registration Existing StoreManager ID authority The explicit ID resolves exactly the Provider's current live instance No orphan replacement Existing StoreManager docs Identity-equality assertions
Provider destruction #14920 provider-owned lifetime contract Final explicit-ID replacement is destroyed and deregistered once External instances remain untouched Provider JSDoc Destroy-path spec

Decision Record impact

none — this is a contained correction inside the existing Provider/StoreManager contract. A global config-equality redesign would require a separate architectural decision and is out of scope unless proven unavoidable.

Acceptance Criteria

  • Two or more sequential same-key replacements with the same explicit ID each yield a distinct live Provider binding.
  • After each replacement, the prior provider-owned Store is destroyed and deregistered.
  • provider.getStore(key) and StoreManager.get(explicitId) resolve the same current instance.
  • Provider destruction destroys and deregisters the final replacement.
  • Generated-ID same-key replacement, different-key replacement, null/re-add, and passed-in external Store ownership remain green.
  • Focused state.Provider tests pin the exact failure and the collision-safe repair.

Out of Scope

  • Changing caller-supplied explicit IDs.
  • A framework-wide rewrite of Neo.isEqual.
  • The Observable mutation defect tracked by #14928.
  • AgentOS view/store topology already delivered by #14920.

Avoided Traps

  • Do not suffix or silently replace a caller-supplied ID.
  • Do not leave a live StoreManager orphan that the Provider cannot resolve.
  • Do not reopen #14920's author loop; Euclid owns this successor.
  • Do not broaden into global config equality without direct falsifiers.

Related

Origin PR: #14920
Origin ticket: #14909
Adjacent Observable defect: #14928

Live latest-open sweep: checked the latest 20 open issues plus GitHub title search and all-state A2A at 2026-07-10T05:34:13Z; no equivalent ticket or competing claim found.

Origin Session ID: de713f27-0e82-4960-b4c6-f281e0c36449

Retrieval Hint: "Provider explicit id same-key replacement destroyed binding StoreManager Neo.isEqual #14920"

tobiu referenced in commit ce4433d - "fix(state): preserve explicit-ID Store replacement (#14939) (#14948)" on 8:17 AM
tobiu closed this issue on 8:17 AM