Authored by Claude Opus 4.8 (Claude Code). Memory-core orchestrator deactivated this session — no Origin Session ID.
FAIR-band: operator-directed PR (explicit request to implement #12173) — not autonomous lane self-selection.
Resolves #12173
Adds the async backend-first CRUD layer on Neo.data.Store: remoteCreate / remoteUpdate / remoteDestroy. The sync mutators (add/insert/remove) stay sync; the new methods call api.{create,update,destroy} first and only mutate locally on success (applying the server-authoritative response), reject + fire a mutationFailed event on failure, and fall back to the local op when the matching api verb is not configured. No RPC plumbing was required — the api dispatch is already method-generic (register() auto-stubs every descriptor method; Message.onMessage routes by method+type), so create/update/destroy dispatch like read.
Evidence: L1 (unit: success / backend-failure / no-api fallback across the three verbs, with a fake api service registered in-namespace) → L1 required (no runtime-only ACs on the neo side; the live websocket round-trip is exercised by the consuming app's CRUD wiring, tracked separately). No residuals.
Deltas from ticket
remoteUpdate(record, data) takes the changed data explicitly (the caller passes the form values) rather than auto-deriving the trackModifiedFields delta. There is no public Record delta accessor yet, and the explicit form is cleaner for the Save/Cancel dialog flow. Auto-delta is deferred as a follow-up enhancement.
- Added
remoteRpc(verb, payload) as a @protected helper (resolves the stub and awaits Neo.remotes.Api.ready() when racing registration, mirroring load()).
- The
api config JSDoc already documented {create, read, update, destroy}, so no config change was needed — only the consuming methods were missing.
Test Evidence
npm run test-unit -- test/playwright/unit/data/StoreRemoteCrud.spec.mjs → 7 passed
npm run test-unit -- test/playwright/unit/data/ → 63 passed (no regression across Store/TreeStore)
Post-Merge Validation
Authored by Claude Opus 4.8 (Claude Code). Memory-core orchestrator deactivated this session — no Origin Session ID.
FAIR-band: operator-directed PR (explicit request to implement #12173) — not autonomous lane self-selection.
Resolves #12173
Adds the async backend-first CRUD layer on
Neo.data.Store:remoteCreate/remoteUpdate/remoteDestroy. The sync mutators (add/insert/remove) stay sync; the new methods callapi.{create,update,destroy}first and only mutate locally on success (applying the server-authoritative response), reject + fire amutationFailedevent on failure, and fall back to the local op when the matchingapiverb is not configured. No RPC plumbing was required — the api dispatch is already method-generic (register()auto-stubs every descriptor method;Message.onMessageroutes by method+type), socreate/update/destroydispatch likeread.Evidence: L1 (unit: success / backend-failure / no-api fallback across the three verbs, with a fake api service registered in-namespace) → L1 required (no runtime-only ACs on the neo side; the live websocket round-trip is exercised by the consuming app's CRUD wiring, tracked separately). No residuals.
Deltas from ticket
remoteUpdate(record, data)takes the changeddataexplicitly (the caller passes the form values) rather than auto-deriving thetrackModifiedFieldsdelta. There is no public Record delta accessor yet, and the explicit form is cleaner for the Save/Cancel dialog flow. Auto-delta is deferred as a follow-up enhancement.remoteRpc(verb, payload)as a@protectedhelper (resolves the stub and awaitsNeo.remotes.Api.ready()when racing registration, mirroringload()).apiconfig JSDoc already documented{create, read, update, destroy}, so no config change was needed — only the consuming methods were missing.Test Evidence
npm run test-unit -- test/playwright/unit/data/StoreRemoteCrud.spec.mjs→ 7 passednpm run test-unit -- test/playwright/unit/data/→ 63 passed (no regression across Store/TreeStore)Post-Merge Validation
remoteCreate/remoteUpdate/remoteDestroyover a live remotes-api websocket and persists create/update/delete end-to-end (tracked in that app's own backlog).