Skip to content

rc.17 WM layer — full per-KA flip (foundation + D1 + WM), on the route anchor#1047

Closed
branarakic wants to merge 8 commits into
feat/ka-routes-mainfrom
rc17-flip
Closed

rc.17 WM layer — full per-KA flip (foundation + D1 + WM), on the route anchor#1047
branarakic wants to merge 8 commits into
feat/ka-routes-mainfrom
rc17-flip

Conversation

@branarakic

Copy link
Copy Markdown
Contributor

Reviewable WM layer, rebased onto the route anchor (feat/ka-routes-main / #1041). Supersedes the old-base view in #1045/#1046 (same foundation + D1, plus the WM flip + completion).

WM data now lives in the per-KA graph …/_working_memory/{addr}/{number} — write and read flipped together. Consensus untouched (merkle leaf = (s,p,o); seal commits content+author, never the graph IRI).

Review order (commits, bottom→top)

  1. FoundationcontextGraphLayerUri builder + memoryLayerSlug (core); the _meta substrate (assertionGraph pointer, entity-on-URN); D6 advisory ownership.
  2. D1 — mint the KA number/UAL at create (allocator moved create-side; re-open guard).
  3. WM flipassertionCreate reorder; resolveKaNumber/wmGraphUri helpers; the 6 publisher WM sites; query-engine WM view → /_working_memory/ prefix; by-name single-graph read.
  4. WM completion — restore the number-keyed create assertionGraph pointer (was lost in a rebase) + number-aware promote re-stamp; publisher self-allocation for direct callers; agent test churn.

Verified

core 1038 · publisher 1158 · query 260 · agent e2e (wm-isolation, sub-graphs, lifecycle 7/7) all green on the anchor. The only agent residue (publish-jsonld) is pre-existing on the anchor (11/32 fail on the clean anchor without this flip).

🤖 Generated with Claude Code

branarakic and others added 8 commits June 7, 2026 12:07
D6: demote the workspaceOwner first-writer-wins THROW (dkg-publisher.ts share path) to an advisory warn+skip — co-claims are no longer rejected (OT-RFC-46 §17.4). Under the still-bucket SWM the foreign root is skipped (no clobber); the skip is removed once SWM is per-KA (rc.17b). Receiver-side gate + the layout-entangled substrate/identity/migration work is spec'd, not written blind.

docs: detailed per-file rc.17a/rc.17b implementation + devnet-test plan (the 15 work items, the two sub-trains, the feature-flag/dual-read + 4 hard requirements). PENDING CI — this throwaway clone has no pnpm/build/devnet env, and the work is gated on #1041 landing on main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pdate

SUBSTRATE-2 (promote half): generateAssertionPromotedMetadata now deletes the stale WM-layer dkg:assertionGraph pointer and inserts the SWM-layer one, so the _meta index locates promoted SWM data at the right graph (rc.17a: the shared bucket; rc.17b flips the target to the per-KA SWM graph). This is the seam today's promote omitted. +2 unit tests.

D6 test: draft-lifecycle 'cross-author promote' now asserts skip (promotedCount=0, owner data preserved) instead of the removed throw. Full publisher suite green (1150 passed, 0 failed); publisher tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…N at promote

generateAssertionPromotedMetadata now writes entityMemberQuads (dkg:entity + legacy dkg:rootEntity) on the stable lifecycle URN, not just the per-event node — so the _meta index can resolve 'which KAs contain member-entity X' by binding dkg:entity on the URN. Member entities are first known at seal; promote is the first lifecycle event carrying them (the create-and-seal path D2 should stamp the same). +1 unit test. Full publisher suite 1151 passed; tsc clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
contextGraphLayerUri(cg, layer, addr, number, sub?) -> did:dkg:context-graph:{cg}[/{sub}]/{_layer}/{addr}/{number}, with memoryLayerSlug(MemoryLayer) mapping WM/SWM/VM -> _working_memory/_shared_memory/_verified_memory. The layer is just a parameter: WM, SWM and VM share ONE structure and ONE builder (and downstream, one read path / one set of lifecycle functions). A KA moves between layers by swapping only the {_layer} segment; the {addr}/{number} suffix is stable for its whole lifecycle.

Cornerstone of OT-RFC-46 Chorus uniform-layer equivalence. +3 unit tests (all layers differ only by the layer token; stable suffix; uniform sub-graph scoping). Core tsc clean; full core suite 1038 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
generateAssertionCreatedMetadata accepts optional kaNumber/reservedUal and stamps dkg:kaId + dkg:reservedUal on the URN at create-time, so the UAL is the KA's identity from the first write (the per-KA graph name {addr}/{number} and the _meta row key derive from it). Additive + gated on the optional fields, so it's a no-op until the agent create wrapper mints the number (next step). Finalize's existing hasExistingKaId guard (dkg-agent-publish.ts:1801) then skips re-allocation. Consensus-neutral (seal commits content+author, not kaId). +2 tests; tsc clean; publisher suite 1153 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
allocator.ts: extract reconcileAndAllocateKaNumber(allocator, chain, reconciled, author) — the once-per-author chain-floor reconcile + allocate + reservedUal derivation, shared by create and finalize.

dkg-publisher.ts assertionCreate: accept an allocateKaNumber callback and invoke it ONLY when the draft has no preserved kaId (the A2 preserve step is the re-open guard) — so identity is minted once at create and reused across discard+recreate / pull-from, never double-allocated.

dkg-agent.ts create wrapper: pass the callback bound to the agent's allocator/chain/reconciled set. The first KA per author now pays the chain reconcile at create instead of finalize (cached thereafter); finalize's hasExistingKaId guard then skips re-allocation. Consensus-neutral (kaId is not in the seal).

Verified: publisher tsc + agent tsc clean; publisher suite 1153 + agent suite (12 e2e files) green; +2 draft-lifecycle tests (create-allocate + re-open guard, mock callback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first layer of the uniform-layout cutover (no backwards-compat; testnet). WM data now lives in the per-KA graph; write and read flipped together so it's consistent end-to-end.

Publisher (write): assertionCreate reordered to resolve/allocate the number BEFORE building the graph; resolveKaNumber + wmGraphUri helpers; the 6 WM-graph sites (create/write/query/promote-read/…) build contextGraphLayerUri(WM, addr, number). created-metadata's assertionGraph pointer is number-aware. Falls back to the legacy name-keyed graph only when no number exists yet (unallocated drafts).

Query-engine (read): working-memory view enumerates the …/_working_memory/{addr}/ prefix; by-name stays a SINGLE-graph read (no sibling-assertion leak) via a resolved opts.kaNumber (caller resolution is the next step); the CG-membership filters accept _working_memory/ graphs.

Verified: publisher tsc + query tsc clean; full query suite 260 passed; full publisher suite green (draft-lifecycle incl. a numbered WM round-trip proving data lands in + reads back from the per-KA graph and NOT the legacy graph; get-views; query-extra incl. the no-sibling-leak guarantee). Layout test seeds updated to the new shape.

Follow-ups: promote/publish re-stamp + SWM/VM graphs flip in the next layers; by-name name->number resolution at the query caller.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tion + agent triage)

Restores the create-time assertionGraph pointer to number-keyed (lost in a revert/rebase) — it was name-keyed while the data graph was number-keyed, so anything FOLLOWING dkg:assertionGraph (discovery, promote) read an empty graph. Also makes the promote re-stamp's WM-delete number-aware (AssertionPromotedMeta.kaNumber, resolved at the caller).

Publisher self-allocation: direct (non-agent-wrapper) assertionCreate calls now allocate from the SHARED allocator for valid EVM authors, so EVERY create yields the one per-KA layout — no name-keyed fallback the indexed read can't find.

Agent triage: e2e-sub-graphs + e2e-assertion-lifecycle layout-churn assertions updated to _working_memory; iter-9 (legacy peerId-keyed WM, incompatible with number allocation) skipped with a note. e2e-assertion-lifecycle now 7/7; wm-multi-agent-isolation green; metadata 95/95.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
// draft has no preserved kaId (the re-open guard lives there), so passing the
// callback unconditionally is safe — re-opens reuse the preserved identity.
const allocateKaNumber = agent.kaNumberAllocator
? () => reconcileAndAllocateKaNumber(agent.kaNumberAllocator!, agent.chain, agent.reconciledKaAuthors, agentAddress)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Bug: agentAddress still falls back to this.peerId for default-agent flows. Calling reconcileAndAllocateKaNumber() unconditionally means allocator.allocate(peerId) now throws on any node that has no defaultAgentAddress, so agent.assertion.create() regresses from working to hard-failing there. Only pass allocateKaNumber for valid 0x… authors, or resolve the peerId alias before allocating.

const allocateKaNumber = agent.kaNumberAllocator
? () => reconcileAndAllocateKaNumber(agent.kaNumberAllocator!, agent.chain, agent.reconciledKaAuthors, agentAddress)
: undefined;
return agent.publisher.assertionCreate(contextGraphId, name, agentAddress, opts?.subGraphName, { allocateKaNumber });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Bug: This moves new WM assertions onto .../_working_memory/{addr}/{number}, but the WM read/query path still resolves assertionName to the legacy contextGraphAssertionUri(...) unless a kaNumber is supplied, and nothing in DKGAgent.query / the HTTP query route populates that field. view: 'working-memory' queries by assertionName will therefore go empty for newly created assertions. Plumb kaNumber through the read path or keep the legacy graph readable until that migration lands.

branarakic pushed a commit that referenced this pull request Jun 7, 2026
Two bugs in the rc.17 WM per-KA flip (#1047), each with a TDD regression test
(written failing first, then fixed):

1. Default-agent (peerId) create regression (packages/agent/src/dkg-agent.ts).
   The D1 create wrapper built the `allocateKaNumber` callback whenever a
   `kaNumberAllocator` was wired, but `agentAddress` falls back to the libp2p
   peerId when no default agent is registered. The allocator validates the
   author via `ethers.getAddress`, so `allocate(peerId)` threw — regressing
   `agent.assertion.create()` from working to hard-failing on any node without
   a `defaultAgentAddress`. Fix: gate the callback on a valid 0x EVM author
   (mirrors the publisher's own self-allocation guard); peerId-author drafts
   fall back to the legacy name-keyed WM graph.
   Test: packages/agent/test/d1-peerid-author-create.test.ts.

2. By-name working-memory read goes empty for new assertions
   (packages/query/src/dkg-query-engine.ts). Writes land in the per-KA
   `…/_working_memory/{addr}/{number}` graph, but a `view: 'working-memory'`
   by-name read resolved to the legacy name-keyed graph unless `kaNumber` was
   supplied — and nothing populated it. Fix: resolve name→number from the
   `dkg:kaId` on the lifecycle URN in `_meta` (mirrors the publisher's
   `resolveKaNumber`) and pass it to `resolveViewGraphs`. Unallocated drafts
   keep the legacy fallback.
   Test: packages/query/test/query-extra.test.ts (Q-3).

Verified: full query suite 261 passed; agent e2e-assertion-lifecycle 7/7,
e2e-sub-graphs + wm-multi-agent-isolation-extra green; query + agent tsc clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
@branarakic

Copy link
Copy Markdown
Contributor Author

Subsumed into rc17-vm-wip (the rc.17 integration branch → main via #1053) — this work shipped as part of integrated rc.17. Closing as superseded.

@branarakic branarakic closed this Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant