feat(api): expose action summaries across API surfaces - #8693
Conversation
JSONbored#8371 (Epic T5) shipped human-readable "action sentence" summaries for extrinsics and chain events, but only client-side: an API or MCP consumer still received raw call_module/call_function/call_args or pallet/method/args and would need to reimplement the ~35 templates to get the same legibility. Extract the template logic (apps/ui/src/lib/metagraphed/chain-summaries.ts, plus its nested-call decode/SS58/byte-blob helpers) into a new shared workspace package, packages/chain-summaries, importable identically by apps/ui and workers/. apps/ui now consumes the package instead of holding its own copy; the route-matching/display helpers that lived alongside it (isValidExtrinsicHash, extrinsicCall, proxyRealAccount, multisigCallHash, etc.) stay in apps/ui since they're app-specific, importing the shared decode primitives from the package. Add an optional summary: string | null field to the extrinsic and chain-event schemas, computed once at the single shared builder each surface already funnels through (formatExtrinsic in src/extrinsics.ts; coerceEvent in workers/data-api.ts, reusing its already-decoded args rather than decoding twice) and exposed at parity on REST, GraphQL, and the 5 relevant MCP tools. null when no template matches, never a guessed or partially-templated sentence. Regenerates openapi.json, the OpenAPI-derived contract types, and the GraphQL types via `npm run build`. Closes JSONbored#8525
Root's typecheck never needed to build a packages/* workspace package first, since nothing under src/workers/tests previously imported one directly. Now that src/extrinsics.ts and workers/data-api.ts import @jsonbored/chain-summaries, root tsc needs its dist/index.d.ts to exist -- gitignored by design (matching packages/client's own committed-dist pattern), so a fresh checkout doesn't have it. Add the same pretypecheck lifecycle hook apps/ui/package.json already uses for packages/client.
apps/ui/src/routes and apps/ui/src/components/metagraphed continue importing from @/lib/metagraphed/* unchanged; those files now only re-export the corresponding symbols from @jsonbored/chain-summaries instead of importing the package directly, so this PR's diff carries no visual-code changes.
Its dist/index.js and dist/index.cjs are compiled tsup build output (committed the same way packages/client and packages/ui-kit already are), not hand-written JS, so validate:no-hand-written-mjs should not flag them.
|
Caution 🛑 LoopOver review result - fixes requiredReview updated: 2026-07-29 16:22:05 UTC
Review summary Nits — 1 non-blocking
CI checks failing
Decision drivers
Context & advisory signals — never blocks the verdict
Linked issue satisfactionAddressed Manifest validation
Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.
|
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
LoopOver is closing this pull request on the maintainer's behalf (CI is failing (test, codecov/patch)). This is an automated maintenance action — to pursue this change, please open a new pull request with the issues resolved. Closed PRs may be analyzed later to improve review accuracy, but they are not automatically reopened or re-reviewed. |
…ock (#9868) * fix(selfhost): re-drive the review a restart orphaned, not just its lock #9802 heals the active_review_tracking row at boot so the next pass cannot bounce off a stale lock. That is only half the failure: the interrupted pass had ALREADY published the "LoopOver is reviewing..." placeholder comment, and terminalizing the row does not replace it. Nothing else re-drives the PR either -- the head has not moved so no webhook fires, and the review cache is empty because the pass never finished. The PR sits claiming a review is in progress, forever. Observed on JSONbored/metagraphed#8693: three container recreates in one afternoon -- two of them routine config reloads -- each killed a mid-flight review. That PR showed "reviewing..." for 25+ minutes with zero published reviews and zero queued work until a human noticed. Every deploy during a review does this, which is why it has recurred. So the boot sweep now enqueues an agent-regate-pr for each row it heals. `force` bypasses the AI-review cache and reuse cooldown, which is right here: the interrupted pass produced nothing to reuse, and the one-shot cadence would otherwise replay a stale review or none at all. prCreatedAt is carried deliberately (#9499): omitting it INVERTS the queue order -- jobClaimSortKey would fall back to a ~9.5e11 base that sorts ahead of every real 2026 PR, so an orphan re-queue would jump the whole contributor backlog. The repo's regate-sort-key check caught exactly that on the first attempt. Fail-safe throughout: a lookup or enqueue failure logs and continues, because a healed row with no re-queue is still strictly better than a wedged one, and the remaining rows still need healing. An unregistered repo logs a named skip rather than enqueueing a job that cannot act. * docs: cite the real issue number — #9866 is an unrelated open issue
Summary
summaryfield (already rendered by the UI) throughthe REST API, GraphQL, and MCP tools — not just
apps/ui— by extracting the sentence-templatelogic into a shared package.
What Changed
packages/chain-summariesworkspace package (@jsonbored/chain-summaries): the call/eventsentence templates and their decode helpers, moved out of
apps/ui/src/lib/metagraphed/*so bothapps/uiandworkers//src/can share one implementation.apps/ui's ownsrc/lib/metagraphed/*files now re-export from the package (no logic of their own, no import-sitechanges in
apps/ui/src/components/**orapps/ui/src/routes/**— this PR carries no visual diff).src/extrinsics.ts:formatExtrinsicnow computessummaryviasummarizeCall(...)from thealready-decoded call args.
workers/data-api.ts:coerceEventnow computessummaryviasummarizeEvent(...), reusing thesame decoded
argsused for the existingargsfield.schemas-src/routes/extrinsics.ts,account-extrinsics.ts,chain-events.ts,block-chain-events.ts) and MCP schemas (schemas-src/mcp-tools/shared.ts,account-extrinsics.ts,chain-events.ts,chain-events-activity.ts) each declare the newsummaryfield, matching each file's existing nullable/optional convention.src/graphql-sdl.ts/src/graphql.ts:summary: Stringadded toExtrinsicandChainEventRow, resolvers populate it.package.jsongets apretypecheckhook sopackages/chain-summaries's.d.tsis builtbefore root
tsc --noEmitruns (mirrorsapps/ui's existingpretypecheck: build:client)..github/workflows/validate.yml, rootvitest.config.ts/eslint.config.ts: wire up the newpackage the same way
packages/client/packages/ui-kitare wired up.tests/graphql.test.ts,tests/mcp-server.test.ts,tests/zod-schemas.test.ts,tests/data-api.test.ts, and the new package's own unit tests.Closes #8525
Registry Safety
Closes #8525).summaryfield on extrinsics and chain events, REST + GraphQL + MCP).
Validation
npm run checknpm run validatenpm run validate:schemasnpm run validate:apinpm run validate:openapinpm run validate:typesnpm run validate:artifact-budgetsnpm run validate:docsnpm run validate:intakenpm run validate:workflowsnpm run worker:testnpm run test:coverage(vianpm run test:ci, the fileParallelism/coverage-safe CI equivalent)npm run scan:public-safetygit diff --check