Conversation
… banner Each API-server instance serves reads from a per-instance cache refreshed by an event listener polling the chain ~every 10s, so after an on-chain write an instance didn't originate (notably ChainSecured wallet writes) its reads can be stale for up to one poll interval. Document this read-after-write window in the SDK sovereign-mode reference, the core_sdk.js header, and the dashboard user docs. Expose the listener's lag via a new account_event_listener_lag_seconds field on GET /health, and add a dashboard banner that warns when a connected instance reports more than 30s of lag. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds end-user and SDK documentation for the API server’s read-after-write cache staleness in sovereign mode, and introduces a listener-lag signal surfaced via /health that the dashboard uses to warn when an instance’s cached reads may be meaningfully out of date.
Changes:
- Add
account_event_listener_lag_secondsto the unauthenticated health response, derived from the account-event listener’s catch-up tracking. - Add a dashboard poller + UI banner that warns when the connected instance reports >30s listener lag.
- Document cache staleness semantics and the new lag field in management docs and the SDK header.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| lit-static/dapps/dashboard/styles.css | Adds --warning theme color and styles for the new listener-lag banner. |
| lit-static/dapps/dashboard/listener_lag.js | New module that polls health and toggles the listener-lag staleness banner. |
| lit-static/dapps/dashboard/index.html | Adds the banner container with appropriate live-region attributes. |
| lit-static/dapps/dashboard/app.js | Starts the listener-lag monitor on auth-ready. |
| lit-static/core_sdk.js | Documents read-after-write cache staleness and points to /health lag field. |
| lit-api-server/src/core/v1/health.rs | Adds account_event_listener_lag_seconds to /health JSON and tests for key presence. |
| lit-api-server/src/account_events.rs | Introduces lag tracking via a process-global timestamp updated by the listener. |
| docs/management/dashboard.mdx | Documents dashboard-visible staleness scenarios and the amber banner meaning. |
| docs/management/account_modes.mdx | Documents the read-after-write staleness window and the /health lag field. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
# Conflicts: # lit-static/dapps/dashboard/app.js
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
cargo-deny 0.20 moved `--config` from a `check` subcommand flag to a top-level option, so the unpinned `taiki-e/install-action` (now resolving to 0.20.2) rejects the existing `cargo deny check --config ...` step with "unexpected argument '--config'", failing every rust-ci matrix job. Pin to the last 0.19.x, which accepts the current invocation, until the command is migrated to the new CLI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # .github/workflows/rust-ci.yml
🤖 Code review (Claude)Summary: This PR documents a read-after-write staleness window for sovereign-mode writes (in Findings1. The central documented claim is factually wrong: list reads are not cached. ( The docs state that API-mode reads (
The per-instance cache ( 2. Wrong endpoint path in docs: Health routes are mounted under 3. Staleness when the listener dies is bounded by TTL, not open-ended. ( Cache entries expire on their own: 300s for positive results, 30s for negative ( 4. Lag metric reports "caught up" after a restart that skipped events. ( On (re)start, Nits
VerdictNeeds changes. The Rust lag-tracking and the dashboard banner are solid and correctly wired, but the documentation — the stated point of the PR — misattributes the staleness window to list reads, which are uncached and read the chain live. The docs should be rewritten around the actual cached surface (permission checks and wallet-derivation on the execute path), plus the |
Address the Claude PR review: the docs incorrectly claimed list reads (listApiKeys/listGroups/listWallets/listActions) go through the per-instance cache. They don't — every list_* handler does a live contract call, so list/read endpoints (and the dashboard's tables) always reflect chain head. The cache sits on the action-execution path (authorization decisions + wallet-derivation lookups). Rewrite account_modes.mdx, dashboard.mdx, the core_sdk.js header, the dashboard banner copy, and the Rust doc comments to describe the actual cached surface: after an unobserved on-chain permission change, execute-path authorization can be stale for up to one poll interval (~10s) while the listener is healthy, or up to the cache TTL (30s denials / 5min grants) if it is stalled — never open-ended. Also: use the canonical /core/v1/health path in client-facing docs (the root /health mount still exists for NLB probes); note the lag metric resets on listener restart (which skips events); revert EVENT_POLL_INTERVAL to private; and document the process-global test-race constraint on the lag static. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the review — the central finding was correct and I've pushed AddressedFinding 1 — docs misattributed the staleness to list reads (the important one). Confirmed: every Finding 3 — dead-listener staleness is TTL-bounded, not open-ended. Fixed. Docs now state the window is at most ~one poll interval (~10s) while the listener is healthy, falling back to the cache TTL (30s denials / 5min grants) if it stalls — explicitly "never open-ended." Also switched "refreshes" → "invalidates" throughout. Finding 4 — lag resets on restart, which skips events. Added a caveat to the Finding 2 — health path. Partial correction: Nits: reverted Intentionally not changed
Verified after the changes: |
# Conflicts: # lit-api-server/src/core/v1/health.rs
pool_warm_hit and pool_memory_limit_bypass intermittently failed in CI with "no pre-warmed worker became ready within 15s". Root cause: every TestServer::start() warms LIT_ACTIONS_POOL_SIZE workers (production default 10), and ~a dozen server-spawning integration tests run in parallel — a ~120-way concurrent V8-snapshot bootstrap storm that, on a loaded/constrained runner, starves the warmup gate so not even one worker becomes ready in time. Reproduced locally by amplifying the storm (LIT_ACTIONS_POOL_SIZE=64 → identical panic on exactly those two warmup-gated tests, while pool_concurrent_exhaustion, which tolerates a cold pool, passes). Cap the pool to 2 for the test process via the existing #[ctor] (respecting an explicit LIT_ACTIONS_POOL_SIZE override, incl. 0 to disable), cutting the storm ~5x while still exercising pool hits/refills/fallbacks. Also bump the warmup deadline 15s→30s for extra CI margin. Production DEFAULT_POOL_SIZE is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A new RustSec advisory (RUSTSEC-2026-0258, h2 unbounded empty DATA frames, Low severity) fails `cargo deny check advisories` in every rocket workspace (lit-payments and lit-billing-core in the attached logs). Two h2 copies fire: h2 0.3.27 via rocket 0.5.1 -> rocket_http -> hyper 0.14, which has NO patched 0.3.x release (only 0.4.16) and is unmovable without rocket 0.6; and an h2 0.4.x copy on the hyper-1.x chain, covered by the same advisory id. Same rocket-0.5.1-bound blocker class as the existing 2026-0098/0099/0104 entries, so add it to the root deny.toml ignore list with a documented reason plus a dated changelog note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…c-bound) New RustSec advisory RUSTSEC-2026-0249 (smartstring unmaintained — repo archived 2026-05-03, all versions affected, no safe upgrade) fails `cargo deny check advisories` in the lit-actions workspace. smartstring 1.0.1 comes in transitively via swc_ecma_lexer/swc_ecma_parser <- deno_ast 0.53.2 <- deno_node/deno_runtime, i.e. the same frozen deno_ast/swc chain that already holds RUSTSEC-2026-0009. Not removable without forking deno, so add it to the root deny.toml ignore list (unmaintained section) with a documented reason and a dated changelog note. Verified locally against the lit-actions workspace: the advisories check fails without the entry (reproducing CI) and passes with it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # deny.toml
The merge of main brought in derived-actions.mdx (#644), which advises "poll the real path rather than sleeping a fixed amount" for newly granted permissions. My read-after-write staleness section contradicted that with a fixed "wait ~10s" recommendation — which is also technically weak: on a lagging or just-restarted instance a grant can take until the 5-min positive TTL to apply, so a fixed 10s wait can under-wait. Align account_modes.mdx to recommend polling the execute path, and cross-link the two docs so the eventual-consistency behaviour has a single canonical explanation (the "why") next to the how-to. Verified: all doc constants (10s poll, 30s/5min TTLs, 30s banner, account_event_listener_lag_seconds, live list_* reads) still match the merged code; all cross-reference pages/anchors resolve and are in nav. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documents the read-after-write cache staleness window for CPL-267: each API-server instance serves reads from a per-instance cache refreshed by an event listener polling the chain ~every 10s, so after an on-chain write an instance didn't originate (notably ChainSecured/sovereign wallet writes) its reads can be stale for up to one poll interval — this is now spelled out in the SDK sovereign-mode reference (
account_modes.mdx), thecore_sdk.jsheader, and the dashboard user docs. The listener now tracks how far behind the chain head it is and exposes it as a newaccount_event_listener_lag_secondsfield on the unauthenticatedGET /health(informational; does not affect health status). The dashboard polls/healthand shows an amber staleness banner whenever a connected instance reports more than 30s of lag. New unit tests cover the lag semantics (Nonebefore first poll → small → large) and the always-present/healthfield.🤖 Generated with Claude Code