Repository navigation
feat(traces): durable trace publication queue — wait for on-chain market, retry, confirm via indexer (#131) - #166
Merged
Levi-Ojukwu merged 4 commits intoOct 17, 2026
Conversation
…esk#131) Durable queue row per reasoning trace that should be published to reasoning-registry: exact payload, status, attempts/backoff, submitted tx and trace id, confirmation time. The migration backfills pinned-but- unpublished MARKET_CREATION traces (commented as a data migration); trade traces can't be backfilled because their direction isn't recorded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d confirm via indexer (OracleDesk#131) - enqueueTracePublication replaces pinAndPublishTrace in runMarketMakerCycle (step 7) and executeTrade (step 5); trade traces are no longer fire-and- forget or skipped when the market isn't on-chain yet. - src/jobs/trace-publication.worker.ts: claims due rows with FOR UPDATE SKIP LOCKED, pins, waits for onChainMarketId (voided -> FAILED), checks the trace link and the registry's market_trace_at index before publishing so a hash is never published twice, retries with capped exponential backoff, parks AgentNotRegistered/EmptyAction/EmptyCid as FAILED, and never confirms in dry-run. Runs every TRACE_PUBLISH_CRON (default 30 s). - Indexer TracePublished now sets verified and confirms the queue row. - Action strings come from src/lib/trace-actions.ts. - New env: TRACE_PUBLISH_ENABLED, TRACE_PUBLISH_CRON, TRACE_PUBLISH_MAX_ATTEMPTS, TRACE_CONFIRM_TIMEOUT_MS (validated). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d actions (OracleDesk#131) 13 worker tests (pending market, backoff vs permanent errors, pin retry, missing Pinata config, already-linked and on-chain duplicates, SUBMITTED re-check, dry-run, voided market, max attempts, claim loop, idempotent enqueue) plus an indexer assertion that TracePublished sets verified and confirms the queue row. docs/architecture.md gains the lifecycle; docs/api.md fixes the REASONING_PUBLISHED action example and defines verified; docs/contract-requests.md notes the buy vs buy_yes/buy_no mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@abayomiwav Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Publishing a reasoning trace's hash to
reasoning-registrywas best-effort and happened once. If the market wasn't on-chain yet (creation failed or ran in dry-run),pinAndPublishTracepinned, logged "not published" and returned, and nothing ever came back for that trace. Trade traces were published fire-and-forget, and skipped entirely when the market had no on-chain id, so an RPC timeout lost them silently. Such traces stayedonChainTraceId: null,verified: false, andPOST /traces/verifyreturned409 TRACE_NOT_PUBLISHEDforever.Changes
Schema (commit 1)
TracePublicationStatusenum andTracePublicationmodel /trace_publicationstable, with@@index([status, nextAttemptAt]). Fields per the issue, plussubmittedTraceId, which stores the trace id returned by the write so the chain can be re-checked.payloadis nullable only for backfilled rows.20261017000008_trace_publicationsalso backfills pinned-but-unpublishedMARKET_CREATIONtraces asAWAITING_MARKET, marked as a data migration at the top of the SQL. Trade traces can't be backfilled: the trace doesn't record its direction, sobuy_yes/buy_nocan't be reconstructed.ReasoningTrace.traceHashwas already indexed ondevelop(@@index([traceHash]), from the trace-audit migration), so no change was needed.Queue and worker (commit 2)
src/lib/trace-actions.ts:TRACE_ACTIONS(create_market,buy_yes,buy_no) plustradeTraceAction(). Both agents use it.enqueueTracePublication()replacespinAndPublishTraceinrunMarketMakerCycle()step 7 andexecuteTrade()step 5. The insert is awaited (durable, idempotent per trace), and a best-effort pass then runs in the background. Trade traces are queued even when the market isn't on-chain yet.src/jobs/trace-publication.worker.ts(processTracePublications) claims due rows withSELECT … FOR UPDATE SKIP LOCKEDin a short interactive transaction and leases them. Chain calls run after the claim commits. Per row:AWAITING_PIN: pin the stored payload and saveipfsCid/traceHash.IPFS_NOT_CONFIGUREDparks the row for 1 h without counting an attempt; other pin errors retry. The payload is kept.AWAITING_MARKET: wait foronChainMarketId(re-checked every 5 min, not counted as an attempt). ACANCELLEDmarket fails the row withMARKET_CANCELLED.READY: duplicate check first. A trace already linked by the indexer, or the same agent +trace_hashamong the market's 10 newest registry traces (market_trace_count/market_trace_at/get_trace), is confirmed without a write. Otherwisepublish_traceis called once and the row moves toSUBMITTED. In dry-run, the simulated publish is logged and the row staysREADYwith a long backoff.SUBMITTED: afterTRACE_CONFIRM_TIMEOUT_MSwithout indexer confirmation, the submitted trace id is re-read on-chain before anything is retried. This covers the ambiguoussignAndSendfailure.AgentNotRegistered/EmptyAction/EmptyCidmove the row toFAILEDwithlastError. Others retry withmin(2^attempts × 30 s, 1 h), andTRACE_PUBLISH_MAX_ATTEMPTSmoves it toFAILED.TracePublisher, the existingRegistryReader,pin,prisma,claim).src/cron/trace-publication.cron.tsruns the worker everyTRACE_PUBLISH_CRON(default every 30 s) and is registered inserver.ts.TracePublishedbranch now setsverified: truewhen linking (hash equality with our storedtraceHashis what verification means for our own traces) and moves the trace's queue row toCONFIRMED. Nothing setsverifiedfrom a write result alone, and dry-run never confirms or verifies.TRACE_PUBLISH_ENABLED,TRACE_PUBLISH_CRON,TRACE_PUBLISH_MAX_ATTEMPTS(integer 1–100) andTRACE_CONFIRM_TIMEOUT_MS(integer ≥ 10000), validated insrc/config/index.tsand listed in.env.example.Tests and docs (commit 3)
tests/trace-publication.test.tswith 13 tests:AgentNotRegisteredfails permanentlymarket_trace_atis confirmed without publishingSUBMITTEDrow is re-checked on-chain, then confirmed or retriedverifiedFAILEDtests/indexer.test.ts:TracePublishednow assertsverified: trueand aCONFIRMEDqueue update.docs/architecture.md: the lifecycle table and the rules (no re-pinning,SKIP LOCKED, dry-run).docs/api.md: theREASONING_PUBLISHEDexample now usesbuy_yes, with notes on action values and whatverifiedmeans.docs/contract-requests.md: a note that the contracts agents usebuy.Verification
tests/trace-publication.test.ts+tests/indexer.test.tsdevelop(2e1b725)audit-constraints,constraints,copy-trade-verify,resilience,trace-audit). None are introduced here.tsc --noEmitmonitor.cron.ts,resilience.ts,copy-trade.service.ts,stellar/clients.ts,subscription.service.ts,trace-audit.service.ts), and present ondeveloptoo. None in the changed files.npx prisma generateNot passing on
developeither:npm run buildandnpm testfail ondevelopbecause of those 14 type errors.tsconfig.test.jsonhasnoEmitOnError: true, so the test build never emits. I ran the suites withtsc -p tsconfig.test.json --noEmitOnError false.npm run check:contractsneeds thecontracts/oracledesk-stellarsubmodule, which isn't initialised in a plain clone. The migration hasn't been applied to a live Postgres (no database here). Please runnpx prisma migrate devagainst a dev database.Notes and deviations
generateReasoningTrace()before the queue row, not in one transaction. The insert is awaited right after, andupsertmakes it idempotent.Closes #131
Closes #126
Closes #129
Closes #130