Consolidate the agent publish/share surface onto the canonical KA lifecycle (#1087)#1265
Consolidate the agent publish/share surface onto the canonical KA lifecycle (#1087)#1265Jurij89 wants to merge 47 commits into
Conversation
… seal-retry recovery Addresses the PR #1265 review (otReviewAgent). - Removed the ensureContextGraphOnChain pre-call (+ unused import) from both publish CTAs (MemoryLayerView publishAssertions, ka.tsx VerifyOnDkgButton). The daemon /vm/publish route deliberately runs local preconditions FIRST and only registers the CG on the CG_NOT_REGISTERED retry path, rehydrating the STORED publishPolicy. The pre-call burned registration gas on a doomed publish and risked the #1085 default-policy (the UI register call sends no policy). The CTAs now call knowledgeAssetPublishWithSeal directly and let the daemon register at the right time. - Added 3 tests for the recovery contract: 409 PUBLISH_NOT_FULL_SHARE and VM_PUBLISH_PRECONDITION each -> wm/finalize{layer:'swm'} -> retry-once succeeds; SWM_SUBSET_NOT_SEALABLE -> typed throw, no retry loop. tsc clean; ui-api-pure 52/52. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…deleted publish route Addresses 2 PR #1265 review comments. - publish-get benchmark: the sync-leg KA name was benchmark-sync-<runId>-<iteration>, but runIteration runs for both warmup and measured phases with the same numeric iteration, so warmup-N and measured-N collided (name/idempotency-based create) and the GET validated the wrong marker. Name now includes the phase (benchmark-sync-<runId>-<warmup|measured>-<iteration>), mirroring the payload's own warmup-/measured- root+marker uniqueness. - context-graph-write-path-validation: added a negative test that POSTs the deleted /api/shared-memory/publish with a VALID CG and asserts 404 (unambiguous route-not-found) -- guards the route deletion against accidental reintroduction. cli tsc clean; the benchmark unique-roots + marker tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…te the api mocks Addresses 2 PR #1265 review comments. - /api/knowledge-assets/:name/vm/publish returns 207 when the KA minted on-chain but the CG binding failed (contextGraphError in the body; post() treats 207 as ok, so it rides through un-thrown). Typed contextGraphError on PublishResult + knowledgeAssetPublishWithSeal, and surfaced it: ka.tsx Verify CTA renders a warning ("binding incomplete") instead of a clean check; MemoryLayerView counts a `partial` tally, prefers a clean sample, and downgrades the result card to a warning when partial>0. Added a ui-api-pure test (207+contextGraphError resolves, no seal/retry). - Completed the full vi.mock('../src/ui/api.js') in the two component tests that load the components barrel (-> ka.tsx) with the new exports it imports (knowledgeAssetPublishWithSeal + the real SwmSubsetNotSealableError class), avoiding a missing-mock module-load failure. tsc clean; ui-api-pure 53/53; component-mock suites green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
otReviewAgent
left a comment
There was a problem hiding this comment.
Operational Notice: Review Agent could not complete this review.
Synthesizer produced only invalid comment anchors.
✅ Ready for human review/merge — convergence reachedAll CI checks green (38 pass / 5 skip / 0 fail); every review thread resolved across 10 rounds with otReviewAgent, on top of 2 internal adversarial review passes before opening. What shipped (#1087)
Deferred (tracked in #1260, untouched here)
Product/agent surface has zero callers of the deleted route. Ready for human review + merge. |
otReviewAgent
left a comment
There was a problem hiding this comment.
Operational Notice: Review Agent could not complete this review.
Synthesizer produced only invalid comment anchors.
otReviewAgent
left a comment
There was a problem hiding this comment.
Operational Notice: Review Agent could not complete this review.
Synthesizer produced only invalid comment anchors.
otReviewAgent
left a comment
There was a problem hiding this comment.
Operational Notice: Review Agent could not complete this review.
Synthesizer produced only invalid comment anchors.
✅ Converged — all review rounds resolved, CI greenFollowing up on the summary above: review continued through several more rounds (all now resolved), including:
Final state: CI green (38 pass / 5 skip / 0 fail), 0 unresolved review threads, MERGEABLE. Ready for human review + merge. |
…) param spelling otReviewAgent: the shared dkg-node SKILL documents the D3 flag as camelCase `alsoShareSwm`, but the OpenClaw + Hermes tools expose all fields in snake_case (`also_share_swm`, `context_graph_id`, `sub_graph_name`). An agent copying the example on those adapters would pass a key they ignore -- sealing the asset but silently not sharing it. Added a parameter-spelling note to the Tool-vs-HTTP section (the systemic fix; applies to every param, not just this flag). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…deleted bridge route otReviewAgent (escalated): the deleted /api/shared-memory/publish left active devnet callers 404-ing. Re-pointed the 3 PURE-assertionName files (no selection sibling, so they become fully working) to /api/knowledge-assets/:name/vm/publish, mirroring the W1 ApiClient migration: - devnet/v10-core-flows/automated.test.ts (:283, :448) - scripts/testnet-publish-stress/publish-loop.mjs (:299) - devnet/_bootstrap/bootstrap.cjs (:353, :375) Response shape verified statically: /vm/publish returns kaId/status/txHash/blockNumber via the same engine publishFromFinalizedAssertion as the deleted fork, so the test assertions hold unchanged. The remaining callers are MIXED (assertionName + selection in one file) or pure selection (loose publish-by-selection) -- they need the named-KA rework deferred to #1260; a compat handler is rejected (it would re-introduce the bridge route + the #1179 authz-bypass). Devnet-only, not in CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…publish route
Round-8 batch 1 of completing the caller cleanup (no product callers remain; these are
out-of-CI devnet validation suites). otReviewAgent: the route deletion must be matched
by a complete caller migration.
- agent-provenance + rich-scenario: the selection-publish (loose write + {rootEntities}/
{selection:'all'}) steps became a named-KA flow (create one-shot {finalize,
alsoShareSwm} -> /api/knowledge-assets/:name/vm/publish); the assertionName helpers
-> /vm/publish. Provenance/status/kaId/txHash assertions preserved (same engine).
- v10-stress: assertionName publish -> /vm/publish; RETIRED the obsolete residual-SWM
drain (it pre-drained loose SWM the removed bridge created -- the named-KA flow leaves
no residue). Updated the FINDINGS repro string + doc comments.
All 3 now have zero /api/shared-memory/publish references. Devnet-only (separate
harness, not in CI); response-shape compatibility static-verified (W1 in-CI proof).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… pending #1260) The selection-publish ops scripts used the removed loose publish-by-selection. Per decision, neutered (not deleted) + marked for the #1260 named-KA rework: - drain-swm-duplicates.mjs: DISABLED header (a named KA self-drains its roots on vm/publish, so this may be obsolete); the per-batch publish loop is now a logged no-op. - redistribute-memory.mjs: the SWM->VM leg is a logged no-op (WM/SWM legs intact). - seed-dkg-code-project.mjs: dropped the best-effort step-4 VM publish (seed still populates WM+SWM). All three: zero /api/shared-memory/publish refs; node --check passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on interface otReviewAgent: the W3.5 BenchmarkClient interface change (publishFromSharedMemory -> publishAssertion in publish-get/types.ts) orphaned the checked-in bench/ implementation, breaking the bench TS build / pnpm bench (out-of-CI, hence the matrix stayed green). Updated bench/support/layered-dkg-client.ts (method + in-memory impl) + the 2 esbench scenarios (analyze-publish-async-get.ts, publish-async-get.bench.ts) to the named-KA publishAssertion flow, mirroring packages/cli/src/benchmark/publish-get/runner.ts. tsc -p bench/tsconfig.json clean; zero publishFromSharedMemory refs in bench/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the seal-retry wrapper otReviewAgent: these 2 CTAs called knowledgeAssetPublish directly, bypassing the catch-409->seal->retry + 207 partial-publish warning that knowledgeAssetPublishWithSeal centralizes. Switched both to the wrapper and surfaced contextGraphError via the shared partialPublishWarning (matching MemoryLayerView + ka.tsx). Removed the now-redundant ensureContextGraphOnChain pre-register in layer-widgets (the publish path was separable); kept it in entities (shared with the finalize/promote branch — that pre-register removal stays deferred, flagged with a NOTE). tsc --noEmit clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hes; coherent redistribute neuter otReviewAgent round-10: - The batch-1 devnet migration carried clearSharedMemoryAfter:true onto the per-KA /vm/publish, which the daemon honors as a CG-WIDE SWM wipe (clears ALL unpublished SWM in the CG, not just the published KA's roots) -- it would clobber the SWM-only assets staged earlier in the same CG. Removed the flag from the 3 migrated sites (rich-scenario x2, agent-provenance); the per-KA publish already clears its own roots. - redistribute-memory.mjs: the neutered (no-op) publishBatches left the algorithm promoting the VM-bound cohort into SWM with no drain -> a mixed (wrong) partition. Now bails before any SWM mutation unless --skip-vm is set (promote-to-SWM-only), pending the #1260 named-KA rework. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rity) otReviewAgent: dkg_knowledge_asset_create forwarded the quad `object` verbatim while OpenClaw + Hermes normalize it through their write normalizers -- so a bare literal was auto-quoted there but had to be pre-quoted in MCP (portable-agent drift). Inlined normalizeRdfObject (replicating dkg-core's normalizeDkgPublisherObject / isDkgRdfTerm / escapeDkgRdfLiteral verbatim, with a keep-in-sync note -- matching MCP's existing inline validateAssertionName convention; MCP stays dep-light). The create one-shot now does normalizeRdfObject(strip(object)) -- strip angle brackets first, then auto-type (bare literal -> quoted; URI/blank/already-quoted pass through). Added a 6-case parity test; updated the object schema description. The MCP write path is unchanged (pre-existing, daemon-normalized). tsc clean; assertion-lifecycle 55/55; parity proven byte-identical across 12 cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ysis traces otReviewAgent: after the publishAssertion migration (r9), the analysis traces still called traceSharedMemoryWrite before publishAssertion, which now stages the same quads internally -- a double SWM write the ESBench path no longer does, making the measured publish trace unrepresentative of the canonical create/write/share/publish flow. Removed the pre-write from analyzeGetFlow + analyzeSyncPublishFlow (publishAssertion stages internally). KEPT it in analyzeAsyncPublishFlow, which needs the returned shareOperationId for the async publisherEnqueue/lift path. bench tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…> /vm/publish serialization otReviewAgent: the #1087 compatibility wrapper (publishFromFinalizedAssertion -> /vm/publish, used by `dkg shared-memory publish`/`dkg index`/the benchmarks) was only validated indirectly. Added 3 focused serialization tests: publishFromFinalizedAssertion POSTs the per-KA /vm/publish route with clearAfter translated to options.clearSharedMemoryAfter (and omits the options object when no flags are set); publishAssertion runs the create -> /vm/publish two-call sequence. api-client 49/49. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…Name + partial/error) otReviewAgent: the publish panel was rewritten (root-entity selection -> named SWM assertions + knowledgeAssetPublishWithSeal) but only the api helper was tested. Added a component test that renders the panel with mocked SWM assertions, selects by graphUri, and asserts the publish call receives the assertion name + subGraphName, plus that a 207 contextGraphError renders the partial warning and a SwmSubsetNotSealableError surfaces. Exported PublishPanel for the test (testability only, no behavior change). node-ui memory-layer-publish-panel 4/4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ize fixtures, dep-light) otReviewAgent: the inline normalizeRdfObject (the dkg_knowledge_asset_create quad-object contract) duplicates core's normalizeDkgPublisherObject/escapeDkgRdfLiteral and could drift silently. MCP is deliberately dep-light (3 prod deps; inlines validateAssertionName + share-warning constants for the same reason; core's normalizer isn't exported from core's entry), so rather than add a dependency we centralize the conformance fixtures: - Exported normalizeRdfObject/isRdfTerm/escapeRdfLiteralBody + a new conformance test: 24 hand-written golden cases (bare->quoted, http/https/urn/did passthrough, blank node, already-quoted/typed/lang-tagged, every ECHAR escape, empty) asserting the inline matches the documented contract (verified byte-identical to core's actual output). A future drift in either copy now trips a red test. - Bidirectional keep-in-sync pointers between core's normalizeDkgPublisherObject and the conformance test. tsc clean; conformance 26/26; mcp-dkg 254 pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…publish warning + assert it
otReviewAgent: the publish-panel partial test mocked partialPublishWarning with an
arg-ignoring stub, so it stayed green even if the component dropped the daemon's
contextGraphError detail. Tightening the assertion (toHaveBeenCalledWith the detail)
exposed a real gap: the batch ("Publish All") path called partialPublishWarning() with
NO detail -- only a count. Now the batch captures the first 207's contextGraphError and
forwards it (partialPublishWarning(firstPartialError)) so the operator sees WHAT failed,
not just how many; the strengthened test asserts the detail is forwarded + rendered.
tsc clean; memory-layer-publish-panel 4/4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mote CTAs otReviewAgent: entities.tsx ran ensureContextGraphOnChain unconditionally before knowledgeAssetPublishWithSeal, defeating the /vm/publish register-then-mint contract -- on a never-registered CG a doomed publish (unsealed/subset/stale) would burn registration gas and only THEN 409, and the same shared pre-register needlessly fired for WM->SWM promote. Removed it from both entities handlers (handleAction + handlePromoteAll) and the matching stale pre-register in layer-widgets' promote branch. The daemon owns the ordering: /vm/publish checks preconditions FIRST and auto-registers only if a valid publish's sole remaining blocker is an unregistered CG (knowledge-assets.ts:1150 -> ensureRegisteredForPublish, idempotent + race-safe; #1116). The seal is CG-independent (#1116: finalize works on an unregistered CG with no chain write) and promote is off-chain, so neither path needs client-side registration. tsc clean; ui-api-pure 54/54; publish-panel 4/4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…aphUri disambiguation)
otReviewAgent: the publish-panel fixtures used distinct names (alpha/beta), so they
didn't exercise the graphUri disambiguation the selection keying exists for -- a
name-keyed regression would still pass. Added a case with the SAME name in both a root
and a sub-graph row: selecting only the sub-graph row publishes exactly one KA
('shared', {subGraphName:'sg1'}) and never the same-named root, which a name-keyed
selection (matching both) would fail.
publish-panel 5/5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…RDF root URN
otReviewAgent: the get + sync ESBench flows built the publishAssertion name as
esbench-<flow>-${payload.rootEntity}, but rootEntity is an RDF URN
(urn:dkg:benchmark:...:${runId}:...) whose ':' / '/' characters validateAssertionName
rejects -- so after the publishAssertion migration the bench would throw before measuring
on any CG id with the normal <curator>/<slug> form. Both flows now derive the name from
the safe run id (esbench-get-<seq> / esbench-sync-<seq>) -- the same slug already passed
to createPayload -- threaded via a syncName var for the sync flow whose publish runs in
the measured fn. The read still queries by rootEntity (unchanged); analyze-publish-async-
get was already slug-based.
bench tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
otReviewAgent: the sync benchmark's beforeIteration still called sharedMemoryWrite even though the measured publishAssertion stages the same quads internally -- a double SWM write that the analyze runner (and the get/read flow) already dropped, leaving the suite exercising both the retired loose-SWM write and the new named-KA composite. Removed the sync pre-write so the measured publish reflects the canonical create/write/share/publish flow. The async flow keeps its write -- it needs the returned shareOperationId for the publisher enqueue/lift path. bench tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… publish-ready
otReviewAgent: dkg_knowledge_asset_create's one-shot claimed "shared to SWM
(publish-ready)" from the requested alsoShareSwm flag, not the daemon outcome. The create
route returns 207 + errors:[{phase:"swm-share"}] when create+seal succeeds but the opt-in
share fails, and DkgClient treats 207 as success -- so an agent could be sent to publish
an asset that never reached SWM. Now inspects result.errors/publishReady and, when the
share tail failed, returns an errResult (create+seal OK, NOT publish-ready, retry
dkg_knowledge_asset_share). Added a 207-share-failed test.
mcp tsc clean; assertion-lifecycle 56/56.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ONDITION 409 otReviewAgent: the seal-then-retry test scripted a PUBLISH_NOT_FULL_SHARE publish 409 then a SUCCESSFUL finalize(layer:swm) retry -- an impossible daemon path, since PUBLISH_NOT_FULL_SHARE means the full-share marker is missing and finalize(layer:swm) checks that same marker and returns SWM_SUBSET_NOT_SEALABLE. Re-coded the recoverable case to VM_PUBLISH_PRECONDITION (the sealable 409 -- an unsealed full share), keeping the layer:swm + subGraphName seal-shape assertions; removed the now-redundant second VM_PUBLISH_PRECONDITION test. The PUBLISH_NOT_FULL_SHARE -> SWM_SUBSET_NOT_SEALABLE -> throws-no-retry case is unchanged. node-ui tsc clean; ui-api-pure 53/53. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… in OpenClaw + Hermes (MCP parity)
otReviewAgent: r19 fixed this in MCP but the byte-parallel OpenClaw and Hermes one-shot
create paths still forwarded the daemon result as a success. The create route returns 207
+ errors:[{phase:"swm-share"}] when create+seal lands but the opt-in alsoShareSwm tail
fails, and all three adapter clients treat 207 as success -- so OpenClaw/Hermes could send
an agent to publish an asset that never reached SWM. Both now judge from the outcome
(errors/publishReady) and return a tool error (create+seal OK, NOT publish-ready, retry
dkg_knowledge_asset_share) when the share failed. Hermes extracts a testable
_create_swm_share_error helper (mirrors _annotate_share_seal). Added a share-failed test
to each adapter.
OpenClaw tsc clean + plugin 61/61; Hermes pytest 115/115.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or commit) The main CI matrix (ci.yml) did not fire for f86bb5d — GitHub dropped the pull_request synchronize event. This empty commit re-fires it so the Kosava/Bura test matrix runs and registers on the PR. No code change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…y with MCP + Hermes) otReviewAgent (nit): OpenClaw only type-checked also_share_swm inside the `quads` branch, so a bare create with also_share_swm:"yes" was silently accepted and ignored -- while MCP and Hermes validate the shape even when ignored, and the shared tool schema advertises a boolean. Moved the check before the quads branch so the runtime contract is uniform across adapters. Added a bare-create boundary test. openclaw tsc clean; plugin 61/61. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r (de-drift the CTAs) otReviewAgent: the SWM->VM batch publish loop was hand-rolled in MemoryLayerView, entities, and layer-widgets, and the copies had drifted -- MemoryLayerView surfaced the first contextGraphError detail + sample while the others dropped it via partialPublishWarning(). Extracted the canonical loop into api.ts `publishAssertionsToVm` (returns one BatchPublishResult: published/sealed/partial/partialError/sample/lastError) and routed all three CTAs through it, so entities + layer-widgets now also render the partial detail. Moved the component test to assert the selection->helper handoff + rendering, and added publishAssertionsToVm forwarding/aggregation unit tests in ui-api-pure. node-ui tsc clean; ui-api-pure 55/55; publish-panel 5/5. (The unrelated :3000-backend store tests fail only locally with no node running, and pass in CI.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…onsToVm
otReviewAgent: the shared batch helper collapsed every per-KA failure into a single
`lastError`, so callers could only say "some failed" + show the last error -- losing the
count and the names/reasons of earlier failures. Replaced `lastError` with
`failures: Array<{ name, subGraph?, error }>` (the failed count is `failures.length`). All
three CTAs now report the failed count, and MemoryLayerView surfaces the first failure's
name + reason (+N more). Updated the helper unit tests + the component test.
node-ui tsc clean; ui-api-pure 55/55; publish-panel 5/5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…easured name uniqueness otReviewAgent: MockBenchmarkClient discarded the assertion `name`, so the warmup/measured KA-name-uniqueness fix (runner.ts names each publish benchmark-sync-<runId>-<warmup|measured>-<iteration>) was not validated -- a regression reusing the warmup name for the measured publish (KA create is name-idempotent) would still pass the root-only check. The mock now records `name` in publishCalls and the test asserts the warmup + measured names are unique and phase-tagged. cli tsc clean; the name-uniqueness test passes. (The one local failure is the pre-existing comma-locale flamegraph flake; CI renders en-US.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lel across MCP/OpenClaw/Hermes
otReviewAgent: Hermes _normalize_quads diverged from the MCP/core create-object contract
(lowercase-only schemes, no blank-node, no bracket strip), so the same
dkg_knowledge_asset_create({quads}) produced different triples per runtime. Fixed Hermes
to match: _is_rdf_term (CASE-INSENSITIVE http(s)/urn/did + `_:` blank + already-quoted) +
_strip_angle_brackets on subject/predicate/object. Also closed the bracket gap the
adversarial review found in OpenClaw -- only MCP stripped `<…>`, so fixing only Hermes
would have left a new MCP+Hermes-vs-OpenClaw split; OpenClaw's create one-shot now strips
too. Added a 25-case Hermes conformance pytest (mirrors the MCP golden fixture) + an
OpenClaw bracket/parity test; MCP's existing strip test stays green. (Follow-up, out of
scope: Hermes _normalize_semantic_quads + the MCP/OpenClaw WRITE-path object handling
diverge separately.)
OpenClaw 62/62; MCP 82/82; Hermes pytest 140/140.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rve padded literals) otReviewAgent: _normalize_quads .strip()'d subject/predicate/object before classifying, but MCP/OpenClaw only bracket-strip (no whitespace trim) -- so a padded literal ' x ' became '"x"' on Hermes while the other adapters preserved '" x "', breaking the cross-adapter create one-shot parity the prior commit established. Removed the .strip(); kept the bracket-strip + the empty-object rejection. Added a whitespace-preservation conformance case. Hermes pytest 141/141. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
) The main CI matrix did not fire on b7e8c7d — GitHub dropped the pull_request synchronize event (recurring on this branch). This empty commit re-fires it so the Kosava/Bura matrix runs and registers as the PR's required checks. No code change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
b6fc66e to
52cedc1
Compare
| // VM-bound cohort into SWM expecting to drain it to VM — without that drain it | ||
| // would leave a mixed SWM partition (VM-bound + SWM-bound). So bail BEFORE any | ||
| // SWM mutation unless --skip-vm is set (promote-to-SWM-only, which is coherent). | ||
| if (!SKIP_VM) { |
There was a problem hiding this comment.
🟡 Issue: This new early exit makes the rest of the VM-publish section unreachable: !SKIP_VM exits here, and the existing if (SKIP_VM) process.exit(0) exits at line 295. The register/publish/verify code below is now dead but still carries comments describing behavior that can never run, which makes this script harder to reason about and easy to drift. Collapse the disabled modes into explicit returns and remove or clearly isolate the unreachable publish section.
| return bool(value) and any(value.startswith(prefix) for prefix in ("http://", "https://", "urn:", "did:")) | ||
|
|
||
|
|
||
| # #1265 cross-adapter create/write one-shot quad-object contract — byte-parallel with |
There was a problem hiding this comment.
🔵 Nit: The comment claims this normalizer is “byte-parallel” with MCP/core, but Hermes still routes bare literals through _quote_literal, which also UCHAR-escapes remaining ASCII control bytes while the referenced MCP/core helpers only escape the ECHAR set. Either narrow the comment to the shared classification/bracket-stripping behavior or align the literal escaping contract so the parity claim is true.
| * `knowledgeAssetPublishWithSeal` (seal-in-SWM retry + 207 partial handling), aggregating | ||
| * into ONE `BatchPublishResult`. The canonical batch-publish loop reused by every CTA | ||
| * (MemoryLayerView / entities / layer-widgets) so the partial-detail, sample, and per-KA | ||
| * error accounting cannot drift between them. Per-KA failures are collected into |
There was a problem hiding this comment.
🔵 Nit: This JSDoc says per-KA failures are collected into lastError, but the implementation now accumulates structured entries in failures[]. Update the comment so callers and future maintainers do not look for a non-existent lastError flow.
Summary
create → write → seal → share → publish). This deletes the bypass/loose agent toolsdkg_publish(direct raw-quad mint),dkg_shared_memory_publish, anddkg_shareacross all three adapters (MCP, OpenClaw, Hermes), and re-points every internal caller onto the canonical per-KAPOST /api/knowledge-assets/:name/vm/publish.POST /api/shared-memory/publishentirely — both theassertionNameandselectionforks — and with it the Track C follow-up: numeric publishContextGraphId preflight bypass #1179 numeric-publishContextGraphIdbranch that trusted a caller-supplied on-chain CG id without an ownership check. The surviving publish routes enforce the ownership check.dkg_knowledge_asset_createwith optionalquads+alsoShareSwmso an agent cancreate → write → seal → sharein one call. It is default-false (sharing must be explicit), stops at SWM (never mints to VM), and is byte-parallel across all three adapters — so it cannot reintroduce a one-call bypass./vm/publish(named-only), with acatch 409 → seal-in-SWM → retry-oncesafety net; this also fixes a latent crash when a CG held ≥2 SWM roots.SKILL.mdfiles teach the single canonical flow and scrub every agent-facing loose-SWM/bridge reference;.cursor/rulesupdated; the skill-endpoint contract test is flipped to assert the bridge route is absent./api/shared-memory/write+/conditional-write) is kept — it is the staging buffer the source-worker bulk-ingest + async-LIFT pipeline depends on, and a live consumed channel (dkg_querySWM view, node-UI, gossip/sync). The SWM gossip/sync receive fabric (sync/host routes + handlers) is untouched. Three now-dead but publicly re-exported facade methods (DkgClient.publish,DkgPublisherExtension.publishVerifiableMemory/writeSharedMemory) that still call surviving routes are left for that follow-up.This change was implemented in waves and gated by a multi-angle adversarial review (plan-conformance, over-deletion, #1179 security, correctness, doc-truth, cross-adapter parity) before opening.
Related
publishContextGraphIdauthz-bypass branch (with the deleted bridge route)Files changed
packages/cli/src/daemon/routes/memory.tsPOST /api/shared-memory/publishroute (both forks) + the #1179 numeric-CG authz-bypass branch + the helpers it solely used; keep/write,/conditional-write,/memory/turn, and all sync/host routespackages/cli/src/api-client.tspublishFromFinalizedAssertiondelegates to/vm/publish; deleted thepublishFromSharedMemoryselection-fork shimpackages/cli/src/commands/shared-memory.ts,benchmark/publish-get/*/vm/publishflowpackages/mcp-dkg/src/tools/publish.ts(deleted),tools/assertions.ts,index.ts,client.tsdkg_publish/dkg_shared_memory_publish; extenddkg_knowledge_asset_create(D3); scrub the surviving publish descriptionpackages/adapter-openclaw/src/{tools/*,DkgNodePlugin.ts,dkg-client.ts,index.ts}dkg_publish/dkg_shared_memory_publish/dkg_share; extend create (D3); delete the 2 bridge-calling facade methodspackages/adapter-hermes/hermes-plugin/{__init__.py,client.py},src/types.ts,README.mddkg_memorypackages/core/src/publisher-extension.tspublishSharedMemoryfacade method + its transport member + dead request typepackages/node-ui/src/ui/{api.ts,views/MemoryLayerView.tsx,views/project/components/ka.tsx,hooks/useMemoryEntities.ts}/vm/publish(named-only) with a seal-retry chokepoint; remove dead loose-write codepackages/network-sim/src/{api.ts,components/ControlPanel.tsx,server/sim-engine.ts}/vm/publish; delete the loose-publish-by-selection helper + its buttonpackages/cli/skills/dkg-node/SKILL.md,dkg-importer/SKILL.md,.cursor/rules/dkg-annotate.mdcTest plan
dkg-core/dkg-storage/dkg-query, then run the impacted suites:pnpm -C packages/mcp-dkg test(227 pass; 2 known unicode inject-hook flakes)pnpm -C packages/adapter-openclaw test(1093 pass / 1 skip)PYTHON=python pnpm -C packages/adapter-hermes test(vitest 90) +pytest(113)pnpm -C packages/node-ui test(1273 pass; the better-sqlite3 native-binding suites are pre-existing env failures)pnpm -C packages/cli test(PR-touched suites green: auth, api-client, skill-endpoint)pnpm -C packages/core test(1084/1084)knowledge-assets-1116-share-errors,share-warning-parity, agente2e-memory-layers.SKILL.md; the D3 default-false / no-leak guard tests are green; cross-adapter parity holds.dkg_knowledge_asset_create({quads, alsoShareSwm:true})stops at SWM (no VM mint); publishing a named SWM assertion via/vm/publishworks; the node-UI publish button works for a named SWM root and is absent for un-named loose roots.Notes / known risks
dkg openclaw setupto pick up the newSKILL.md— the daemon serves/.well-known/skill.mdlive (MCP/Hermes/HTTP get it immediately), but OpenClaw copies the file into the agent workspace at setup./api/shared-memory/write+/conditional-write) — kept; the source-worker bulk-ingest + async-LIFT pipeline depends on it. Consolidating it onto the named-KA model is tracked in Consolidate daemon-level loose SWM writes onto the named-KA lifecycle (post agent-tooling cleanup) #1260.v10-core-flows,agent-provenance,rich-scenario,v10-stress) re-pointed to the named-KA flow, thepublish-loop.mjs+bootstrap.cjsscripts migrated, and the 3 ops.mjs(drain-swm-duplicates,redistribute-memory,seed-dkg-code-project) neutered (publish leg disabled + marked). The interconnected.shvalidation suite is deferred to Consolidate daemon-level loose SWM writes onto the named-KA lifecycle (post agent-tooling cleanup) #1260 and left untouched — the 10.shvalidators all publish through one shared bash helper (devnet_publish_swm_all_roots, 100% looseselection-publish) that ~9 more rfc38/rfc39 scenarios source; re-pointing it requires a per-scenario named-KA re-validation against a live devnet (mechanically gutting it would ship non-functional validators). Full scope documented in #1260. (A compat handler was rejected — it would resurrect the bridge route + the Track C follow-up: numeric publishContextGraphId preflight bypass #1179 authz-bypass.)entities.tsxpre-register — both sibling CTAs (entities.tsx,layer-widgets.tsx) now publish through the sharedknowledgeAssetPublishWithSealwrapper (seal-retry + 207 warning), andlayer-widgets' redundantensureContextGraphOnChainpre-register was removed. The one remaining deferred item isentities.tsx's pre-register, which is shared with the finalize/promote branch (removing it needs the promote-path analysis) — pre-existing, not introduced here.DkgClient.publish,DkgPublisherExtension.publishVerifiableMemory/writeSharedMemory) that still call surviving routes — left for a future library-API cleanup.