Skip to content

Show transaction status, action, and timestamp in social link previews - #3596

Draft
tom2drum wants to merge 14 commits into
mainfrom
issue-3593
Draft

Show transaction status, action, and timestamp in social link previews#3596
tom2drum wants to merge 14 commits into
mainfrom
issue-3593

Conversation

@tom2drum

Copy link
Copy Markdown
Collaborator

Resolves #3593

A shared link to a transaction page currently produces a near-useless social preview: the OG title carries the full 66-character hash and there is no og:description at all, so Telegram and X fall back to the generic page description. This task makes the preview describe the actual transaction — a short hash in the title, and {status} · {action} · {timestamp} as the description, with the action reading the same as the transaction details page subheading, including its fallback chain and amount rounding.

Plan: .agents/tasks/3593-tx-og-title-description/spec.mdmedium, five subtasks.

This is a spec-first draft: only the spec is committed so far. The branch will receive the task's work subtask by subtask, and the final description will be written when the PR is marked ready for review.

Medium task, five subtasks: make the `og` block a default/enhanced
template layer, share the interpretation currency rounding and render
summaries as plain text, derive the status/action/timestamp params, wire
the bot-gated server-side fetch plus the /tx/[hash] templates, and verify
on a demo (agent deploys, human confirms the real card).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tom2drum tom2drum added the enhancement New feature or request label Jul 28, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. To trigger a review, include @coderabbitai review in the PR description. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3312c304-09f8-44c5-8602-439d2af14bf4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

tom2drum and others added 5 commits July 28, 2026 19:29
The `og` entry in the route template map was static data: `og.description`
was passed through to the meta tag without ever reaching `compileValue`, so
it could hold no placeholders, and the record required a description and an
image together. That ruled out a per-route dynamic OG description.

OG title and OG description now each accept the same `default`/`enhanced`
shape as the metadata templates and are compiled against the same params;
the image is independent of both. A route that declares no OG template falls
back to the page title and description — written out explicitly so the
resolution rule is uniform, which is why routes without an OG description now
emit an `og:description` carrying the text crawlers previously inferred from
`<meta name="description">`. The new `hash_short` param shortens a route's
hash the way `truncation="constant"` does on the page.

No route declares OG templates yet — `/tx/[hash]`'s land in the next steps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The OG description needs the transaction action to read exactly as the
subheading on the page does, but the summary is a template of typed
variables that only `TxInterpretation` knows how to turn into React
elements. A plain-text renderer walks the same parsing pipeline and maps
each variable type to the text its UI counterpart displays.

Two pieces of that mapping were inline in components and are now shared, so
the preview cannot drift from the page: the currency rounding ladder, which
the interpretation component calls instead of holding its own copy, and the
address name chain, extracted into the address slice and called by
`AddressEntity` itself. Neither component's output changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Turns the transaction and its interpretation summary into the three strings
the OG description template compiles — status word, action, UTC timestamp —
or nothing at all when any of them is missing, which is what keeps the
template's all-or-nothing rule true at the source.

The unit lives in the tx slice rather than beside `generate()`: metadata is
regenerated on every client-side route change, so anything reachable from
there ships to all users, and the responses would otherwise be serialized
into `__NEXT_DATA__` whole. Three short strings instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A worktree under `.claude/worktrees/` is a full checkout of the repo, so
every tool that walks the tree from the root sees each file twice: cspell
and the two test runners duplicate their work, tsc type-checks a copy with
no dependencies installed, and eslint exhausted the Node heap outright.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A shared transaction link produced a card titled with the full 66-character
hash and described by the generic page copy, since the route declared no OG
templates and crawlers never run the client-side metadata update.

`/tx/[hash]` now carries a short-hash OG title for every crawler, and its
`getServerSideProps` fetches the transaction and its interpretation summary
for social-preview bots specifically, turning them into a status · action ·
timestamp description. Anything less than all three parts falls back to the
generic description, so a pending transaction or a failed request degrades
to exactly today's card.

Both requests run in parallel with a 2 s timeout. That is longer than the
other routes allow because both endpoints compute their response on the
first request for a transaction and cache it afterwards, and a crawler is
always that first request: on eth mainnet a cold summary averages 0.95 s
against 0.30 s warm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tom2drum and others added 3 commits July 29, 2026 13:31
TEAM.md mixed the roster with the rules for using it: who picks a task's
contacts, that product questions go to a channel rather than a DM, which
channel, and how to mention the addressee. Those already lived in
`grill-the-task` and `to-spec`, so the file was a second, drifting copy —
the skills are what an agent actually reads when routing a question.

What stays in TEAM.md is the data plus what makes it readable: the meaning
of the `default` marker, where IDs come from, and each team's ownership. One
rule was only implied in the skill and is now explicit there: the roster
default is what to record when the developer has no task-specific pick.

The backend section also gains Slack group IDs beside its members, so a
question can be addressed to a whole team once a skill has a rule for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The demo proved the wiring: every branch of the description was observed on
a public URL, including the interpretation summary and the called-method
fallback with a named address. It also showed the feature barely enhances on
that instance, so the subtask now carries the sampling behind that — both
transaction endpoints measured against a network control, and the ruling not
to raise the timeout, since no crawler waits as long as the API takes.

The latency goes to the backend team as Q2; it gates the release decision
rather than any remaining work, because the code degrades to today's card
wherever the API is slow.

Also corrects a claim the spec made from the start: `logRequestFromBot` and
`fetchApi` do record their metrics, but the SSR bundle keeps a registry of
its own, so `/api/metrics` never exports them and the timeout evidence had
to come from sampling the API directly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tom2drum and others added 4 commits July 29, 2026 15:53
The `review` variant exports them, `review-2` did not, so `/api/metrics`
answered 404 there — and the metrics are how a demo shows what the app did
server-side, which is the point of deploying one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
All three open questions came back. The demo verification is done: the card
was confirmed in Telegram and X on an eth-mainnet demo, and the timeout
question was settled by the metrics once they worked — on the loaded instance
the mandatory call aborted on every crawler request, so the answer is to keep
2 s and change where the data comes from.

That leaves two pieces of work rather than one. The backend is building an
endpoint shaped for this preview, with switchable ens/metadata/summary
preloads, going to staging to be measured — subtask 6, a brief until its shape
is agreed. And the Noves decision needs code: the product call is to emit no
enhanced description there, but an instance running Noves currently still
requests the Blockscout summary and lands on the called-method fallback, which
is the option that was rejected — subtask 7, scoped and ready.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An instance runs a single interpretation provider. On a Noves one the transaction page renders Noves' prose
and the Blockscout summary endpoint has nothing to serve, so the preview fell through to the
`called … on …` line — the option the PM ruled against, since pointing crawler traffic at a third party's
slow API is not ours to decide.

Both gates now require the provider to be `blockscout`: the util has no action without it, and the page makes
no request at all. That also drops the `core:tx` request on instances with the feature off entirely, where it
could never produce a description — and `none` is the provider's default.
All three read OG tags, none of them was in `detectBotRequest`, so their crawlers were treated as ordinary
visitors and every route that enhances its preview for social bots — transaction, address, token, NFT
instance, stats — served them the generic description instead. Reported for WhatsApp from a real card.

Discord and LinkedIn match the `…bot` suffix rather than the bare product name, because both also ship an
in-app browser whose user agent carries that name and whose requests are real visitors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate transaction OG title and description from transaction details

1 participant