feat(ui): operator event feed — bounded node ring + /api/v1/events + live panel - #152
Conversation
…live panel Phase 2B of the first-class UI effort: the node narrates its own lifecycle. Node side (zero new locks — everything rides the existing snapshot flow): - event_feed.rs: bounded EventFeedRing (CAP 512, monotonic seq, FIFO eviction) + a tick-diff deriver. Events are DERIVED, not instrumented: the single call site in snapshot_emit diffs successive per-tick observations already collected on the hot path — no subsystem grows an event hook. v1 kinds: blockApplied (newest-4-per-tick via the recent-blocks tail, so initial sync can't flood), reorg (tip id changed at same/lower height), peerConnected/Disconnected (peer-set diff, capped 16/tick), indexerStatus transitions. First tick primes the differ without emitting, so boot doesn't fabricate a connect-event per peer. - The ring tail (latest 100) projects into SnapshotParts/Snapshot as Arc<ApiNodeEvents>; SnapshotReadState serves it as a pure snapshot clone. API: - GET /api/v1/events?since=<seq> — flat camelCase ApiNodeEvent with optional per-kind fields; latestSeq for cursor polling; seq gaps mean ring eviction. Defaulted NodeReadState::events() keeps the many test fixtures untouched. utoipa-documented, native openapi snapshot regenerated, pinned by a 4-case endpoint test (full tail, strict since-filter, beyond-latest, defaulted-empty). UI: - Overview gains a full-width Events panel (silent when the endpoint is absent — older nodes): kind-colored pills, block heights deep-linking into the explorer, relative timestamps, newest first. fmt / clippy -D warnings / cargo test --all green (full workspace gate, including the regenerated openapi snapshot). Panel verified via the dev proxy with a mocked feed; the endpoint's wire shape is test-pinned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds an operator event feed from node snapshot state to a new ChangesOperator event feed feature
Estimated code review effort: 3 (Moderate) | ~35 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ergo-node/src/node/snapshot_emit.rs (1)
139-155: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winHandle
committed_tip()errors without advancing the event-feed cursor.
Err(e)currently becomes an empty tail, soderive_eventsseestip_height = 0/tip_id = ""and resetsFeedPrev; when the read succeeds again, the feed can replay already-emittedblockAppliedevents. KeepOk(None)as the genuine no-chain case, but skipderive_eventsor reuse the last projection on the error path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ergo-node/src/node/snapshot_emit.rs` around lines 139 - 155, The error path in snapshot emission is being treated like a real empty chain, which advances the event-feed cursor incorrectly. In `snapshot_emit.rs`, keep `Ok(None)` as the only case that yields an empty tail, but change the `Err(e)` branch from `ChainStoreReader::committed_tip()` so it does not feed `derive_events` with a fake zero tip; instead, skip updating the projection or reuse the previously computed tail state from `recent_blocks_for_tip`/`FeedPrev` handling. Make the fix around the `recent_blocks_committed` computation so transient read faults preserve the last emitted cursor and avoid replaying `blockApplied` events.
🧹 Nitpick comments (2)
ergo-api/tests/events_endpoint.rs (2)
39-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReduce duplicated boilerplate between
FeedStubandDefaultStub.The two stubs repeat identical
info/status/tip/sync/peers/mempool_summary/mempool_transactions/mempool_transaction/healthbodies. SinceDefaultStubmust keep NOT overridingevents()to actually exercise the trait default, full merging into one struct isn't possible, but the shared bodies can be factored into free functions both impls delegate to.♻️ Suggested refactor (illustrative)
+mod stub_defaults { + use super::*; + pub fn info() -> ApiInfo { ApiInfo { agent_name: "ergo-rust".into(), node_name: "stub".into(), network: "mainnet".into(), version: "0.1.0".into(), started_at_unix_ms: 0, uptime_seconds: 0, target_block_interval_ms: 120_000 } } + pub fn status() -> ApiStatus { ApiStatus { sync_state: SyncStateLabel::AtTip, peer_count: 0, best_header_height: 900_000, best_full_block_height: 900_000, headers_ahead_of_full_blocks: 0, mempool_size: 0, snapshot_age_ms: 0, bootstrap: None, last_block_apply_error: None, block_apply_errors_total: 0, mempool_tx_requested_total: 0, mempool_peer_tx_admitted_total: 0, mempool_peer_tx_rejected_total: 0 } } + // ...tip/sync/mempool_summary/mempool_transactions/health likewise... +} + impl NodeReadState for FeedStub { fn events(&self) -> ApiNodeEvents { /* ... */ } - fn info(&self) -> ApiInfo { ApiInfo { /* full literal */ } } + fn info(&self) -> ApiInfo { stub_defaults::info() } // ...same delegation pattern for the rest... } impl NodeReadState for DefaultStub { - fn info(&self) -> ApiInfo { ApiInfo { /* full literal, duplicated */ } } + fn info(&self) -> ApiInfo { stub_defaults::info() } // events() intentionally absent — exercises the trait default. }Also applies to: 205-299
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ergo-api/tests/events_endpoint.rs` around lines 39 - 141, The `FeedStub` impl duplicates the same `info`, `status`, `tip`, `sync`, `peers`, `mempool_summary`, `mempool_transactions`, `mempool_transaction`, and `health` bodies already present in `DefaultStub`; factor these shared return values into helper/free functions and have both impls delegate to them. Keep `DefaultStub`’s `events()` unimplemented so it continues to exercise the trait default, and only extract the repeated non-events methods from the `NodeReadState` impls.
178-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a test for a non-numeric
sincevalue.The endpoint's documented contract ("Omitted or non-numeric = the full retained tail") isn't exercised by any test — only the omitted, valid, and beyond-latest cases are covered.
#[tokio::test] async fn events_since_non_numeric_returns_full_tail() { let body = get_json(app(Arc::new(FeedStub)), "/api/v1/events?since=abc").await; assert_eq!(body["events"].as_array().unwrap().len(), 3); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ergo-api/tests/events_endpoint.rs` around lines 178 - 195, Add a test in events_endpoint.rs to cover the non-numeric since query behavior that is part of the endpoint contract. Extend the events_since_* test coverage by adding a new tokio::test alongside events_since_filters_strictly_greater and events_since_beyond_latest_returns_empty_list, using get_json(app(Arc::new(FeedStub)), "/api/v1/events?since=abc") and asserting the response returns the full retained tail (all events) rather than filtering or erroring.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ergo-api/src/server.rs`:
- Around line 1661-1697: The `/api/v1/events` handler documentation currently
describes the retained event tail as if it were the full 512-event ring, but
`build_events_projection()` only exposes `ring.latest(100)`, so the stated
retention is misleading. Update the `events_handler`/`ApiNodeEvents` description
to match the actual 100-event snapshot window, or change
`build_events_projection()` to publish the full 512 if that is the intended
behavior.
In `@ergo-node/src/node/snapshot_emit.rs`:
- Around line 916-979: `build_events_projection` is truncating the event feed to
`ring.latest(100)`, which breaks the intended resume semantics because clients
can miss still-retained events before ring eviction. Update this projection to
expose the full available ring window (or otherwise align the documented
catch-up guarantee with the actual cap) so `events_handler` in the API sees all
events still present in `EventFeedRing`, and keep the seq-keyed cache behavior
unchanged.
---
Outside diff comments:
In `@ergo-node/src/node/snapshot_emit.rs`:
- Around line 139-155: The error path in snapshot emission is being treated like
a real empty chain, which advances the event-feed cursor incorrectly. In
`snapshot_emit.rs`, keep `Ok(None)` as the only case that yields an empty tail,
but change the `Err(e)` branch from `ChainStoreReader::committed_tip()` so it
does not feed `derive_events` with a fake zero tip; instead, skip updating the
projection or reuse the previously computed tail state from
`recent_blocks_for_tip`/`FeedPrev` handling. Make the fix around the
`recent_blocks_committed` computation so transient read faults preserve the last
emitted cursor and avoid replaying `blockApplied` events.
---
Nitpick comments:
In `@ergo-api/tests/events_endpoint.rs`:
- Around line 39-141: The `FeedStub` impl duplicates the same `info`, `status`,
`tip`, `sync`, `peers`, `mempool_summary`, `mempool_transactions`,
`mempool_transaction`, and `health` bodies already present in `DefaultStub`;
factor these shared return values into helper/free functions and have both impls
delegate to them. Keep `DefaultStub`’s `events()` unimplemented so it continues
to exercise the trait default, and only extract the repeated non-events methods
from the `NodeReadState` impls.
- Around line 178-195: Add a test in events_endpoint.rs to cover the non-numeric
since query behavior that is part of the endpoint contract. Extend the
events_since_* test coverage by adding a new tokio::test alongside
events_since_filters_strictly_greater and
events_since_beyond_latest_returns_empty_list, using
get_json(app(Arc::new(FeedStub)), "/api/v1/events?since=abc") and asserting the
response returns the full retained tail (all events) rather than filtering or
erroring.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 771c1c16-8f8e-456e-844a-a3f650ed0457
📒 Files selected for processing (16)
ergo-api/src/server.rsergo-api/src/traits.rsergo-api/src/types.rsergo-api/tests/events_endpoint.rsergo-api/tests/fixtures/openapi_native.yamlergo-api/web/dashboard.cssergo-api/web/js/api-client.jsergo-api/web/js/overview.jsergo-node/src/api_bridge.rsergo-node/src/node/boot.rsergo-node/src/node/event_feed.rsergo-node/src/node/mod.rsergo-node/src/node/snapshot_emit.rsergo-node/src/node/state.rsergo-node/src/node/tests.rsergo-node/src/snapshot.rs
The projection served only latest(100) while the ring retains 512, so a client whose ?since cursor was 100-512 events stale saw a silent gap that was NOT eviction — violating the documented 'gaps only mean eviction' contract. Project EventFeedRing::CAP instead (cloned only when the seq advances, so cost is unchanged on quiet ticks) and state at the API level that eviction is the only gap source; openapi snapshot regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes AI-review-tool attributions (Codex plan finding/follow-up/audit citations, CodeRabbit PR #152), dangling internal task/milestone labels (Phase 0/1a/1b/2a/2b/2f-1/2f-3/2j/3a/3b/4/4a/4b/4d, sub-phase 14.6/14.10, Part 2 spec/§N, "M5 final slice in audit-todo", OBS-1/P2 work-item codes, bare commit hashes, "spec §7.3/§7.4"), and citations to internal design/spec docs confirmed absent from the repo (design §2/§5/§6/§6.2, "operator workload §D", "spec §2 Channel Sizing") across the wallet bridge, config, boot, api_bridge, snapshot, mining/sync, and node-identity modules. Doc-only. Fixes 2 real staleness bugs found along the way: - node/state.rs: doc comment called drive_popow_bootstrap/ handle_inbound_popow_proof "both follow-up commits" -- both are already implemented (sync_tick.rs, messaging.rs). - api_bridge/tests.rs: a monitoring-scraper note said a stale-field bug was fixed "Pre-r5" -- restated as the direct current-behavior guarantee without the version tag, since no such tag is used elsewhere in the repo. Preserved: every Scala/REST-compat citation, the crate's own stable Mode 1-6 operational-mode taxonomy and R1/R2/R5 Scala-parity validation codes, mainnet-incident rationale (h=28662 sign-flip, silent-stall and header-only-reset-stall bugs), and all consensus/sync-safety documentation (prune-sentinel gating, split-brain best_full_block_height sync, NiPoPoW resume-state classification). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi
…203) * docs(ergo-compiler): reference-implementation documentation pass (remaining files) Elevates the last ~30 uncovered ergo-compiler files (parse/*, typer core, AST/type/token core, and the transform layer + lib.rs) to the same documentation standard applied in #202: strips internal planning-artifact references (dev-docs citations, milestone/task-tracker labels, dangling finding codes) while preserving all Scala source citations, oracle vectors, and the crate's deviation ledger. Doc/comment-only, no behavior changes. Also fixes one real inaccuracy found along the way: lib.rs's module doc claimed CSE was not yet wired into compile() -- it is (tree/mod.rs:217). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-crypto): strip internal-artifact citations from test comments Removes Task-N labels and a dangling internal-report/design-doc citation ("Task-4 report", "g25-pegmint-packaging §5.2.5") from group_element.rs and merkle/mod.rs, restating the same facts directly. Doc-only; all Scala/scrypto citations and oracle vectors untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-difftest): strip internal-artifact references from doc comments Removes bare bug-tracker numbers (#97, #108/#115, bug #6), a dangling "gitignored dev-docs Autolykos note" pointer, and redundant citations into interface-contracts.md/findings-and-triage.md whose content was already stated inline, restating each as a direct technical claim. Doc-only. Preserved: all Scala/JVM-oracle protocol documentation, and the extensive Bug #N cross-references in gen/mod.rs, gen/sigma_expr.rs, ergo_tree.rs, box_candidate.rs, transaction.rs, header.rs, constant.rs, asm.rs -- these map to the checked-in ergo-difftest/docs/known-bug-catalog.md rediscovery gate and are the crate's own live API contract (Feature::bug_id()), not development history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-wallet): strip internal-artifact references from doc comments Removes a bare uncited bug label, "Task 38" tracker references, and roadmap-style "lands in following PRs"/"a later slice" phrasing from scan/mod.rs, scan/predicate.rs, address.rs, secret.rs, and storage.rs -- restated each as a direct statement of current scope. Doc-only. Preserved: all Fiat-Shamir/Schnorr/DHT protocol documentation, BIP32/BIP39/ EIP-3 citations, and the upstream Ergo issue #1627 legacy-derivation provenance baked into ExtendedSecretKeyLegacy/use_pre_1627. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-mining): strip internal design-doc citations from doc comments Removes dangling "v12 §N" / "design §N" internal design-plan citations from candidate.rs and handle.rs, and an uncited "audit-1" tracker label from error.rs -- restated each as a direct statement of the invariant. Doc-only. Preserved: all Scala consensus citations (CandidateGenerator.scala, EmissionRules.scala, ReemissionRules.scala), emission/coinbase/reward-script byte-layout documentation, and the "Component B" subsystem name where it functions as this crate's (and ergo-mempool's) stable cross-file name for the suspect-feed/targeted-recheck mechanism rather than a dangling doc pointer. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-mempool): strip internal-artifact references from doc comments Removes this repo's own PR #139 references, a dangling "§7"/"Phase 2A guidance" design-doc citation, and two code-review-thread references ("Item 3 of the code-review fixes", "reviewer finding 1") from lib.rs and admission/tests.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala mempool-parity citations (OrderedTxPool, MempoolAuditor, CleanupWorker), the "Component B" and numbered admission-step naming (both confirmed stable, cross-referenced internal pipeline structure, not dangling doc pointers), and mempool invariant #7's cross-reference to its real definition in admission.rs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-p2p): strip internal-artifact references, fix stale connection-limit doc Removes dangling internal labels (Sync-S3/Lever 1/plan §240 in sync.rs, Sync-S2 in delivery.rs, an AI-audit-session narrative and a "checklist contract" pointer in peer_manager/mod.rs) and roadmap phrasing in handshake.rs test docs, restating each as a direct technical statement. Doc-only. Also fixes a real inaccuracy: peer_manager/mod.rs's module doc still said "Max 80 total / 60 outbound" connections by default; the actual Default (limits.rs) is 384 total / 96 outbound / up to 256 inbound (decoupled). Updated to match. Preserved: all Scala P2P-protocol citations, wire-format byte-layout documentation, the out96/in256/cap384 connectivity-limit rationale, and the 2026-07-04 testnet-stall regression note in throttle.rs (genuine incident documentation, not development history). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-indexer): strip internal-artifact references from doc comments Removes a dangling "audit-2 M11" milestone label from handle.rs, and an AI-agent reference plus two citations to an uncommitted internal spec file (2026-05-01-storage-rent-eligibility.md, confirmed absent from the repo) from rollback.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala indexer-parity citations, the testnet-431,366 and h=740,362 mainnet-incident notes, and the crate's own stable Phase 0/Phase 1 rebuild-state naming. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-sync): strip internal-artifact references from doc comments Removes AI-agent/review-tool references ("Codex supervisor plan", "codex review notes", "codex round-N guard"), internal task-tracker labels ("M5 final slice tracked in audit-todo"), and dangling internal increment/design-plan labels ("Sync-S0/S1/S3", "Plan §240") from executor/mod.rs, block_proc.rs, and coordinator/{mod,tests}.rs -- restated each as a direct technical statement. Doc-only. Preserved: all Scala sync-parity citations (ToDownloadProcessor.scala, ElementPartitioner.distribute), and the operational rationale behind the real merged "headers-synced stale-tip stall" and "caught-up-to-peers fallback" fixes, which document actual observed behavior rather than development history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-validation): strip internal-artifact references, fix mojibake Removes dangling internal-plan/spec citations across block/header, voting, popow, and tx modules ("v12 §5 step N", "spec §8.1", "2026-04-28-voted- parameters-phase2.md" (confirmed absent from the repo), "R5 security gap / §11", "14.10", "§6.3", "T4 live differential", "codex P0-1", "§3.5") and an AI-review-tool tracker label, restating each as a direct technical statement. Doc-only. Also fixes a real encoding bug: voting/votes.rs and its oracle test carried double-encoded UTF-8 em-dashes ("—" instead of "—") -- restored throughout both files. The same corruption exists in ergo-sigma and will be fixed when that crate's pass runs. Preserved: every Scala consensus citation (ErgoStateContext.scala, NipopowAlgos.scala, Parameters.scala, RuleStatusSerializer.scala, etc.), mainnet-incident-derived rationale (blocks 290684/422179/1802240, h=1821696), EIP-27/storage-rent documentation, and all oracle-pinned test vectors -- this is the workspace's consensus-validation crate and none of its correctness specification was touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-ser): strip internal-artifact references, fix broken citation Removes AI-review-tool tracker labels ("codex P1", "codex review of the MAX_EXPR_DEPTH=110 fix") from ergo_tree.rs and sigma_value.rs, and dangling citations to internal spec files confirmed absent from the repo (.superpowers/sdd/task-1-report.md, dev-docs/context-ext-count-signedness- recon.md, dev-docs/.../recon-segregation.md, "Phase 0 §11.5") from address.rs, input.rs, opcode/tests.rs, and popow_proof.rs. Also drops dangling "sub-phase 14.3"/"§14.3" cross-crate milestone labels from popow_header.rs, matching the same cleanup already done in ergo-validation's popow module. Doc-only. Also fixes a real broken citation: extension.rs's proptest doc comment named two test functions that don't exist in the file (extension_too_many_fields_returns_invalid_data / extension_value_too_long_returns_invalid_data); corrected to the actual names (extension_field_count_above_u16_returns_invalid_data / extension_field_value_above_255_returns_invalid_data). Preserved: every Scala/sigma-state wire-format citation, opcode-by-opcode byte-layout documentation, oracle-derived test vectors, the KMZ17 interlinks-sizing rationale, and the STypeVar/JVM-UTF8 and MAX_TYPE_DEPTH divergence notes -- this crate's entire purpose is byte-exact parity with the Scala reference and none of that specification was touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-sigma): fix mojibake, strip internal-artifact references Fixes 42 instances of double-encoded UTF-8 mojibake ("—" -> "—") in evaluator/opcodes/method_call.rs, matching the same corruption already fixed in ergo-validation. Removes AI-review-tool/PR-number dev-history references from evaluator/tests.rs (codex P1, "per CodeRabbit on PR #38", "Reviewer finding:", a bare commit hash), evaluator/opcodes/method_call.rs ("PR #13/#14 oracle vectors"), and evaluator/opcodes/binding.rs ("CodeRabbit PR #161 finding") -- restated each as a direct technical statement. Doc-only. Preserved: every Scala/sigma-state citation across the evaluator (opcode dispatch, cost accounting, method_call semantics, Schnorr/DHT proof verification, AVL+ operations, verify.rs's top-level reduction path), oracle-pinned test vectors, and the GHSA-hfj8-hjph-7r78 security-advisory citation. Left one "TODO v6.0: implement" comment untouched in evaluator/opcodes/errors.rs -- it's a verbatim quote of the Scala reference source's own class comment (trees.scala:77), not this repo's dev history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-state): strip internal-artifact references from doc comments Removes AI-review-tool attributions (Codex flagged/identified, "codex risk flag in 2h plan"), dangling internal task/milestone labels (Task 1.6/1.7, Phase 0/1a/1b/1c/2/2a/2b/3/3a/3b/4/5, sub-phase 14.5/14.10, audit-2 M5, Task 38), and citations to internal spec/incident docs confirmed absent from the repo (spec §7.1/§7.4, "2026-05-02-voted-params-first-epoch- boundary", "dev-docs/incident-2026-06-11-adproofs/") across the store, digest, avl, wallet, and persist modules -- restated each as a direct technical statement. Doc-only. Preserved: every Scala consensus citation, the crate's own stable Mode 2/3/5/6 operational-mode naming and per-function "Phase 1/2/3" step labels (these describe a single function's own algorithm steps, not a development roadmap -- same pattern as ergo-sync's kept "Step 2.5"), the mainnet incident at height 1,805,523 (technical substance kept, only the dangling doc pointer dropped), and all AVL+/digest-mode byte-layout documentation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-api): strip internal-artifact references, fix 3 stale docs Removes a systemic pattern found across nearly every v1/* file: citations to dev-docs/v1-api-design.md and its section numbers (§N.N), work-breakdown codes (G-N/O-N used as dangling pointers), "locked decision" labels, and a sibling dev-docs/v1-design-fragments/*.md fragment doc -- all confirmed absent from the repo. Also strips compat/blockchain module citations to a nonexistent "spec inventory"/section-12 label, and AI-review-tool references (CodeRabbit #170, "codex", "see the PR report"). Doc-only. Fixes 4 real staleness bugs found along the way: - v1/mod.rs: said v1 "isn't mounted on a route yet" -- it is (server.rs). - v1/auth.rs: said tiers/boot-warn aren't wired per-group yet -- they are. - v1/mempool_depth.rs: called stats/mempool-depth "future" -- it's live. - v1/realtime/bus.rs: called webhooks "a future PR" -- webhooks is built and is itself a live RealtimeBus subscriber. Preserved: every Scala/REST-compat citation, the compat/ module's byte-for-byte quirk-compatibility documentation, T0/T1/T2 tier naming and G-N/O-N primitive-numbering (real, pervasively cross-referenced internal names, not dangling doc pointers), and all storage-rent/wallet/mempool correctness rationale. Two residuals flagged but intentionally NOT touched (would be a behavior change, out of scope for a docs-only pass): three JSON response `detail`/ `note` string literals in operator/node.rs, accounts/mod.rs, and script/handlers.rs leak the same internal jargon into live API responses; and decode/registry.rs's `rent` protocol entry has `reference: "dev-docs/demurrage"`, a nonexistent path returned live via GET /api/v1/protocols. Both are real product bugs worth a follow-up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * docs(ergo-node): strip internal-artifact references, fix 2 stale docs Removes AI-review-tool attributions (Codex plan finding/follow-up/audit citations, CodeRabbit PR #152), dangling internal task/milestone labels (Phase 0/1a/1b/2a/2b/2f-1/2f-3/2j/3a/3b/4/4a/4b/4d, sub-phase 14.6/14.10, Part 2 spec/§N, "M5 final slice in audit-todo", OBS-1/P2 work-item codes, bare commit hashes, "spec §7.3/§7.4"), and citations to internal design/spec docs confirmed absent from the repo (design §2/§5/§6/§6.2, "operator workload §D", "spec §2 Channel Sizing") across the wallet bridge, config, boot, api_bridge, snapshot, mining/sync, and node-identity modules. Doc-only. Fixes 2 real staleness bugs found along the way: - node/state.rs: doc comment called drive_popow_bootstrap/ handle_inbound_popow_proof "both follow-up commits" -- both are already implemented (sync_tick.rs, messaging.rs). - api_bridge/tests.rs: a monitoring-scraper note said a stale-field bug was fixed "Pre-r5" -- restated as the direct current-behavior guarantee without the version tag, since no such tag is used elsewhere in the repo. Preserved: every Scala/REST-compat citation, the crate's own stable Mode 1-6 operational-mode taxonomy and R1/R2/R5 Scala-parity validation codes, mainnet-incident rationale (h=28662 sign-flip, silent-stall and header-only-reset-stall bugs), and all consensus/sync-safety documentation (prune-sentinel gating, split-brain best_full_block_height sync, NiPoPoW resume-state classification). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi * fix(ergo-api): regenerate OpenAPI golden fixtures after doc cleanup utoipa embeds doc comments directly into the generated OpenAPI spec, so the internal-artifact citations stripped from wallet/v1 doc comments in 46cdb66 changed the generated native and v1 specs, drifting them from the checked-in golden fixtures. CI caught this (openapi_native_matches_snapshot and openapi_v1_matches_snapshot both failing on all three platforms). Regenerated both fixtures via the documented `regenerate` test target; no other change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kw7uCwqmiGna8fpg6TvxGi --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
What
Phase 2B — the last Phase 2 item of the first-class UI effort: the node narrates its own lifecycle through a live Events panel.
Node side (zero new locks)
event_feed.rs— boundedEventFeedRing(512, monotonicseq, FIFO eviction) plus a tick-diff deriver. Events are derived, not instrumented: one call site insnapshot_emitdiffs successive per-tick observations already collected on the hot path — no subsystem grows an event hook.blockApplied(newest-4/tick from the committed tail, so initial sync can't flood),reorg(committed-tail comparison — including reorg-with-advance, detected when the tail shows a different id at the previous tip height),peerConnected/peerDisconnected(sorted, deterministic 16/tick cap),indexerStatustransitions. The first tick primes the differ silently.Arc<ApiNodeEvents>, seq-key-cached so a quiet tick re-publishes the same allocation.API
GET /api/v1/events?since=<seq>— flat camelCase events with optional per-kind fields;latestSeqfor cursor polling; gaps = ring eviction; the reorg approximation is documented at the API level. DefaultedNodeReadState::events()keeps the many test fixtures untouched. utoipa-documented, native openapi snapshot regenerated.UI
Review & testing
codexadversarial pass found 1 High + 2 Medium + 1 Low + 1 Nit — all fixed in this commit: the High (committed-vs-in-memory tip desync permanently losing block events) is closed by the same-source contract above and pinned by a dedicated test; reorg-with-advance detection added; the differ gained 8 unit tests (priming, idempotent ticks, caps, both reorg shapes, deferred-not-lost lag, peer determinism, indexer transitions); peer caps made deterministic; projection Arc cached by seq.since/ beyond-latest / defaulted-empty); openapi snapshot + runtime-mount + ring tests green.-D warnings/cargo test --all).Closes out Phase 2. Phase 3 (mining panel, light theme completion, responsive/a11y) is next.
🤖 Generated with Claude Code
Summary by CodeRabbit
GET /api/v1/eventsto the operator API, including sequence-based polling viasince.latestSeq.since(including empty/zero states).