Skip to content

show the pulsing 'anchoring' pill on fresh decisions, not the terminal 'not anchored' marker#21

Merged
AnkanMisra merged 1 commit intomainfrom
feat/decision-anchor-pending
May 3, 2026
Merged

show the pulsing 'anchoring' pill on fresh decisions, not the terminal 'not anchored' marker#21
AnkanMisra merged 1 commit intomainfrom
feat/decision-anchor-pending

Conversation

@AnkanMisra
Copy link
Copy Markdown
Owner

@AnkanMisra AnkanMisra commented May 3, 2026

Summary

The timeline already has a great pulsing pill (anchorPendingPillHtml) for in-flight 0G uploads, but it was only wired into the policies flow. Fresh decisions submitted via Evaluate were rendered with the terminal "— not anchored" marker immediately, even though the server's fire-and-forget anchor was still uploading. Users had to manually refresh to see the green link land 5-30s later.

This PR extends the same pattern from policies.ts to timeline.ts:

  • Module-level pendingDecisionAnchors: Map<id, startTime> tracks decisions whose anchor is still uploading on the server.
  • New exported markDecisionPending(id) is called from submitEvaluateForm right after POST /evaluate returns, gated on the response lacking a rootHash so existing anchored rows don't re-enter pending on a retry.
  • A single shared setInterval polls GET /timeline every 2s and re-renders. When a row's response carries a rootHash, the id is drained from the map and the pill flips to the lime "0G | 0xroot..." link without a visual jolt.
  • Per-id 30s timeout kicks abandoned ids out of the map so the pill drops to the terminal state if the upload genuinely fails.
  • The shared timer self-stops when the map drains (size === 0).

Test plan

  • bun run typecheck (server + Astro) — 0 errors / warnings / hints
  • bun test — 101 pass
  • bun run build:web — clean
  • Live: hit Evaluate against a real policy on the deployed app, confirm the new decision row's pill pulses "anchoring" then flips to lime "0G | 0xroot..." 5-15s later without any manual refresh

View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

…e timeline never sits on '— not anchored' for fresh rows: until this commit, hitting evaluate caused the new decision to render in the timeline immediately with the terminal '— not anchored' marker because the server returns the decision before the 0g storage upload settles (the upload is fire-and-forget per zeroGStore.scheduleAnchor for the same '50ms hot path' reason that policy creation uses), so users sat staring at a row that looked like it had failed when in reality the anchor would land 5-30s later — they had no way to know the difference without manually refreshing or watching the lime '0G | 0xroot...' pill appear; web/src/lib/timeline.ts now mirrors the policies.ts treatment with a module-level pendingDecisionAnchors Map<id, startTime> and a single shared poll loop (one window.setInterval shared across all in-flight ids, vs one timer per id) that fetches /timeline every 2s for up to 30s per id; markDecisionPending(id) is exported so the evaluate flow can register a fresh decision the instant POST /evaluate returns, the next loadTimeline render reads from the map and emits anchorPendingPillHtml() (pulsing lime dot + italic 'anchoring' text + breathing opacity) instead of the terminal anchorPillHtml(undefined) for any id still in flight; loadTimeline drains the map on every render — for each row whose response now carries a non-empty rootHash the id is pulled from the map and the pill flips to the green link without a visual jolt; the shared timer self-stops when the map drains (size === 0) so we don't burn an interval forever after all anchors land, and the per-id timeout (30s) kicks any id that fails to anchor (network blip, indexer down, wallet drained) out of the map so the pill drops to the terminal '— not anchored' state rather than pulsing forever; web/src/lib/evaluate.ts imports markDecisionPending and calls it from submitEvaluateForm right after the post returns, gated on the response carrying an id and lacking a rootHash so existing rows with already-landed anchors don't re-enter the pending state on a retry; the call happens before await loadTimeline() so the very first render of the new row already shows the pending pill rather than flashing 'not anchored' for one frame before the next poll catches up
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

Warning

Rate limit exceeded

@AnkanMisra has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 49 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9cafb06-c117-460c-8334-1ee7e4cec5c5

📥 Commits

Reviewing files that changed from the base of the PR and between 24466cd and 9d23105.

📒 Files selected for processing (2)
  • web/src/lib/evaluate.ts
  • web/src/lib/timeline.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/decision-anchor-pending

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
Review rate limit: 0/1 reviews remaining, refill in 28 minutes and 49 seconds.

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

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying chainshield with  Cloudflare Pages  Cloudflare Pages

Latest commit: 9d23105
Status: ✅  Deploy successful!
Preview URL: https://e1abb497.chainshield.pages.dev
Branch Preview URL: https://feat-decision-anchor-pending.chainshield.pages.dev

View logs

@AnkanMisra AnkanMisra merged commit ee1b5ea into main May 3, 2026
3 checks passed
@AnkanMisra AnkanMisra deleted the feat/decision-anchor-pending branch May 3, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant