diff --git a/packages/agent/src/dkg-agent.ts b/packages/agent/src/dkg-agent.ts index 4dc7c2955a..f5c4901168 100644 --- a/packages/agent/src/dkg-agent.ts +++ b/packages/agent/src/dkg-agent.ts @@ -8865,6 +8865,10 @@ export class DKGAgent { ): Promise { const ctx = options?.operationCtx ?? createOperationContext('publishFromSWM'); const effectiveSubCG = options?.subContextGraphId ?? options?.contextGraphId; + // `ctxGraphIdStr` doubles as `publishContextGraphId` for REMAP-flow + // publishes — the publisher uses its presence as a signal to DELETE the + // original copy from the default data graph. Keep it empty for non-REMAP + // publishes so we don't accidentally trigger the delete. const ctxGraphIdStr = effectiveSubCG != null ? String(effectiveSubCG) : undefined; const onChainId = ctxGraphIdStr ?? (await this.getContextGraphOnChainId(contextGraphId)) ?? undefined; @@ -8963,6 +8967,16 @@ export class DKGAgent { if (result.status === 'confirmed' && result.onChainResult) { const rootEntities = result.kaManifest.map(ka => ka.rootEntity); + // Always carry the resolved on-chain CG id in the finalization gossip + // so receiving cores promote SWM into the per-cgId `_meta` namespace + // (`/context//_meta`) that the RS prover reads from. + // Without this the prover 404'd with `KCNotFoundError` on every + // freshly-published KC even though the SWM payload had been + // replicated — see scripts/devnet-test-rfc39-comprehensive.sh + // Scenario A. We pass the *publisher-resolved* `onChainId` (which + // includes both explicit REMAP targets and the auto-lookup fallback) + // rather than the REMAP-only `ctxGraphIdStr`. + const broadcastCgId = onChainId != null ? String(onChainId) : undefined; const msg: FinalizationMessageMsg = { ual: result.ual, contextGraphId: contextGraphId, @@ -8976,14 +8990,14 @@ export class DKGAgent { rootEntities, timestampMs: Date.now(), operationId: ctx.operationId, - targetContextGraphId: result.contextGraphError ? undefined : ctxGraphIdStr, + targetContextGraphId: result.contextGraphError ? undefined : broadcastCgId, subGraphName: options?.subGraphName, }; const topic = contextGraphFinalizationTopic(contextGraphId); try { await this.gossip.publish(topic, encodeFinalizationMessage(msg)); - this.log.info(ctx, `Broadcast finalization for ${result.ual} to ${topic}${ctxGraphIdStr ? ` (contextGraph=${ctxGraphIdStr})` : ''}${result.contextGraphError ? ' (ctx-graph registration failed, omitting targetContextGraphId)' : ''}`); + this.log.info(ctx, `Broadcast finalization for ${result.ual} to ${topic}${broadcastCgId ? ` (contextGraph=${broadcastCgId})` : ''}${result.contextGraphError ? ' (ctx-graph registration failed, omitting targetContextGraphId)' : ''}`); } catch { this.log.warn(ctx, `No peers subscribed to ${topic} yet`); } diff --git a/scripts/devnet.sh b/scripts/devnet.sh index e10adcfec9..16a6690a5e 100755 --- a/scripts/devnet.sh +++ b/scripts/devnet.sh @@ -927,7 +927,7 @@ cmd_start() { if (idId === 0n) { console.log('Node ' + (i+1) + ' (core): no identity after 60s, skipping'); continue; } const stakeAmount = ethers.parseEther('50000'); - const askAmount = ethers.parseEther('1'); + const askAmount = ethers.parseEther('${DEVNET_CORE_ASK_TRAC:-1}'); // Lock tier 1 (1-month). Cheapest tier with non-zero multiplier; sufficient // for devnet random-sampling soak tests where we need nodeStakeV10 > 0. const lockTier = 1;