feat: dashboard delta details#257
Conversation
Both delta listing endpoints (per-account and global) now carry a closed
`category` enum, an optional `kind` (echoes `metadata.proposal_type`),
and a `summary` block with asset/counterparty/note-count fields so the
operator dashboard can render a one-line human description of each
transaction without drilling into the detail view. Existing fields are
preserved verbatim — no breaking change.
This is the MVP slice of feature 007 (Phases 1-3 of plan.md). Detail
endpoint (US2) and uniform-404 contract (US3) are scaffolded but
deferred.
Server-side
- New `delta_summary` module: shared decode + classify pipeline,
callable from both listing services. Handles both persisted
`delta_payload` shapes (multisig wrapper and raw push_delta) per
research.md Decision 10.
- `DashboardDeltaEntry` (account feed) and `DashboardGlobalDeltaEntry`
(global feed) extended with the three new fields, kept in lockstep
via the shared `classify_delta_payload` helper.
- `classify_delta_payload` returns `(category, kind, summary)`; decode
failures fold to `category = Custom`, `kind = None`, empty summary,
preserving FR-004 (entry never dropped).
- 11 new inline tests across the two services covering each category,
multisig vs single-key push paths, malformed payload tolerance, and
the `kind: null` (not skipped) serialization invariant.
- 13 new `delta_summary` unit tests covering both payload shapes plus
EVM and malformed-base64 fallbacks. Full server lib suite: 496/0.
TS operator client
- `DashboardDeltaEntry` extended with `category`, `kind`, `summary`
(matching server wire shape). New types exported: `DashboardDelta-
Category`, `DashboardDeltaActivitySummary`, `DashboardDeltaAsset-
Summary`, `DashboardDeltaCounterpartySummary`, `DashboardDeltaNote-
Counts`, `DeltaAssetKind`, `DeltaCounterpartyDirection`.
- `parseDeltaEntry` validates the new required fields with strict
enum/shape checks. Existing tests updated to include the new wire
fields; 4 new tests cover happy paths and contract rejections.
- Full http.test.ts suite: 74/0.
Side fix
- Removed pre-existing duplicate `export { ACCOUNTS_PAUSE, ... }` block
in packages/guardian-operator-client/src/index.ts that was blocking
`npm run build` workspace-wide (lines 19-25 were a verbatim repeat
of lines 11-17). Unrelated to feature 007 substance but required to
unblock the TS workspace build.
Spec artifacts (speckit/features/007-dashboard-delta-details/)
- spec.md, plan.md, tasks.md, research.md, data-model.md, quickstart.md
- contracts/{http-list-account-deltas, http-list-global-deltas,
http-get-account-delta-detail}.md
- checklists/requirements.md
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…/summary) Adds a dedicated "Delta feed (enriched)" panel to the operator smoke harness that displays the feature-007 wire fields directly instead of relying on the raw JSON dump at the bottom of the page. Each delta is rendered as a card showing: - A one-line human summary derived from `category` + `kind` + `summary` (proves SC-001 end-to-end: an operator can read what happened without hitting the detail endpoint). - The `category` as a colored badge. - `kind` (or `null` chip for single-key push entries). - Nonce, status, status timestamp. - `summary.asset` (assetId + amount + kind) and `summary.counterparty` (accountId + direction). - `summary.note_counts` (input / output). - Account id when the source is the global feed. - Collapsible "Debug commitments" details with prev/new commitment, retry_count, and the legacy proposal_type field for cross-checking against `kind`. `listAccountDeltas` and `listGlobalDeltas` now populate the panel state in addition to the raw JSON. The status filter label is carried so the operator can see which filter produced the visible list. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR introduces “delta enrichment” for the operator dashboard by persisting derived delta activity metadata at push time, extending delta listing endpoints with dashboard-friendly fields, and adding a new per-delta detail endpoint with a structured decoded projection. It also updates the TypeScript operator client (types, parsing, tests) and the operator smoke-web example to consume the new shapes.
Changes:
- Add push-time derivation + persistence of a typed
deltas.metadataJSONB blob, and spread key enrichment fields onto listing responses. - Add a new
GET /dashboard/accounts/{account_id}/deltas/{nonce}detail endpoint and a matching TS client method/parser. - Update Speckit feature docs/contracts and the operator smoke-web example to reflect and exercise the new API surface.
Reviewed changes
Copilot reviewed 47 out of 47 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| speckit/features/007-dashboard-delta-details/spec.md | Draft feature spec for enrichment + detail endpoint requirements and invariants. |
| speckit/features/007-dashboard-delta-details/data-model.md | Proposed data model / wire shapes for metadata and listing/detail endpoints. |
| speckit/features/007-dashboard-delta-details/contracts/http-list-global-deltas.md | Contract doc for global delta listing response extensions. |
| speckit/features/007-dashboard-delta-details/contracts/http-list-account-deltas.md | Contract doc for per-account delta listing response extensions. |
| speckit/features/007-dashboard-delta-details/contracts/http-get-account-delta-detail.md | Contract doc for the new per-delta detail endpoint. |
| packages/guardian-operator-client/src/types.ts | Add TS types for delta categories, enrichment fields, and delta detail projection. |
| packages/guardian-operator-client/src/index.ts | Re-export new delta-related types and detail options. |
| packages/guardian-operator-client/src/http.ts | Add getAccountDeltaDetail() and parsers for new listing/detail fields. |
| packages/guardian-operator-client/src/http.test.ts | Extend client tests for enriched listing parsing and the new detail endpoint. |
| packages/guardian-operator-client/README.md | Document enriched delta feed fields and the new delta detail method. |
| examples/operator-smoke-web/vite.config.ts | Point the example at the client source entry for local development. |
| examples/operator-smoke-web/src/index.css | Add styles for enriched delta list/detail rendering. |
| examples/operator-smoke-web/src/App.tsx | Add enriched delta feed rendering + “View detail” UI using the new endpoint. |
| crates/server/src/storage/postgres.rs | Add JSONB metadata column plumbing for deltas (read/write). |
| crates/server/src/storage/filesystem.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/services/sign_delta_proposal.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/services/push_delta.rs | Build/persist DeltaMetadata at push time; lookup matching proposal payload to lift intent. |
| crates/server/src/services/push_delta_proposal.rs | Update proposal persistence to include metadata: None on DeltaObject. |
| crates/server/src/services/mod.rs | Export the new delta detail service API. |
| crates/server/src/services/get_delta_since.rs | Populate new metadata field when constructing merged delta responses. |
| crates/server/src/services/get_delta_proposals.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/services/get_delta_proposal.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/services/delta_commit.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/services/dashboard_global_deltas.rs | Spread DeltaMetadata onto global listing entries (category/assets/counterparty/note_counts). |
| crates/server/src/services/dashboard_accounts.rs | Add account_id_bech32 to account summary/detail responses. |
| crates/server/src/services/dashboard_account_proposals.rs | Add tests ensuring proposal_type is surfaced from wrapper metadata for pending proposals. |
| crates/server/src/services/dashboard_account_deltas.rs | Spread DeltaMetadata onto per-account listing entries. |
| crates/server/src/services/dashboard_account_delta_detail.rs | Implement the new per-delta detail endpoint service + projection and include=raw support. |
| crates/server/src/schema.rs | Add Diesel schema for deltas.metadata. |
| crates/server/src/metadata/network.rs | Add MidenNetworkType::to_miden_network_id() mapping for bech32 HRP selection. |
| crates/server/src/lib.rs | Export the new delta_summary module. |
| crates/server/src/jobs/canonicalization/processor.rs | Preserve push-time metadata on canonicalization (status flip only). |
| crates/server/src/delta_summary/tests/fixtures.rs | Add test fixture module placeholder. |
| crates/server/src/delta_summary/projection.rs | Implement detail projection + listing asset/counterparty derivations from tx summary. |
| crates/server/src/delta_summary/mod.rs | Define metadata/detail types and module API surface. |
| crates/server/src/delta_summary/decode.rs | Decode tx summaries and proposal metadata from persisted JSON shapes. |
| crates/server/src/delta_summary/category.rs | Implement category mapping/inference rules. |
| crates/server/src/delta_summary/build.rs | Implement push-time metadata builder/orchestrator. |
| crates/server/src/delta_object.rs | Add typed metadata field and prefer it for proposal_type() lookup. |
| crates/server/src/builder/handle.rs | Wire the new detail route into the dashboard router. |
| crates/server/src/api/http.rs | Update test fixtures to include the new metadata field on DeltaObject. |
| crates/server/src/api/grpc.rs | Ensure inbound deltas initialize metadata: None (derived server-side). |
| crates/server/src/api/dashboard_feeds.rs | Add handler + parsing for /dashboard/accounts/{account_id}/deltas/{nonce} and canonical nonce parsing. |
| crates/server/migrations/2026-05-25-000001_delta_metadata/up.sql | Add metadata JSONB column to deltas. |
| crates/server/migrations/2026-05-25-000001_delta_metadata/down.sql | Drop metadata column rollback. |
| crates/server/Cargo.toml | Add miden-standards dependency for note decoding/classification. |
| .agents/skills/speckit-implement/SKILL.md | Add agent-facing code style discipline notes for spec-driven implementations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/server/src/services/dashboard_account_deltas.rs (1)
198-215:⚠️ Potential issue | 🟠 Major | ⚡ Quick winCompute
has_morefrom raw storage rows, not filtered entries.
has_morecurrently usesentries.len()afterfilter_map. If a leakedPendingrow is dropped, pagination can incorrectly stop early and hide remaining rows.Proposed fix
- let mut entries: Vec<DashboardDeltaEntry> = rows + let limit_us = limit as usize; + let has_more = rows.len() > limit_us; + + let mut entries: Vec<DashboardDeltaEntry> = rows .iter() .filter_map(DashboardDeltaEntry::from_delta) .collect(); - - let limit_us = limit as usize; - let has_more = entries.len() > limit_us; entries.truncate(limit_us);As per coding guidelines, "Preserve canonicalization semantics (pending/candidate/canonical/discarded lifecycle)".
🤖 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 `@crates/server/src/services/dashboard_account_deltas.rs` around lines 198 - 215, has_more is computed from filtered entries after calling DashboardDeltaEntry::from_delta, which can drop Pending rows and cause pagination to stop early; change the logic to compute has_more from the raw rows length (use rows.len() > limit_us) before filtering, then keep truncating entries and building next_cursor using entries.last() as before (references: rows, entries, DashboardDeltaEntry::from_delta, has_more, limit_us, entries.truncate, next_cursor, Cursor::account_deltas, cursor::encode, state.dashboard.cursor_secret()).
🧹 Nitpick comments (2)
crates/server/src/storage/postgres.rs (1)
430-461: ⚡ Quick winDowngrade: current lifecycle preserves
DeltaObject.metadata, butsubmit_deltawill NULLdeltas.metadataif a caller passesmetadata: None
crates/server/src/storage/postgres.rsPostgresService::submit_deltaderivesmetadata_jsonfromdelta.metadataand always writes it onON CONFLICTupdates (None→ DB column set toNULL).- Canonicalization does not trigger a wipe: it clones the candidate delta pulled from storage and only changes
status(canonical_delta = delta.clone(); canonical_delta.status = ...), so whatevermetadatawas persisted is preserved.- Production push-time also does not trigger a wipe:
push_deltasetsresult_delta.metadata = derived_metadatabefore calling the storagesubmit_delta.- The
metadata: Nonesubmit_deltacalls found indashboard_feeds.rs/dashboard_account_deltas.rsare test fixtures, so they don’t exercise “overwrite existing row with NULL” in the real lifecycle.Optional: if future code paths ever re-submit the same
(account_id, nonce)withmetadata: Nonefor a row that previously had metadata, the current upsert will erase it—consider a defensive SQLCOALESCE(or an invariant/assertion) if that behavior is undesirable.🤖 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 `@crates/server/src/storage/postgres.rs` around lines 430 - 461, PostgresService::submit_delta currently upserts NewDelta with metadata_json which can be None and the ON CONFLICT do_update unconditionally writes that NULL, wiping existing deltas.metadata; change the upsert so the update preserves existing metadata when the incoming metadata is None (e.g. use SQL COALESCE between the incoming/excluded metadata and deltas::metadata in the DO UPDATE SET for deltas::metadata or the Diesel equivalent), targeting the insert_into(...).on_conflict(...).do_update().set(...) block that sets deltas::metadata; keep all other fields the same and ensure NewDelta/submit_delta still accepts Option metadata but does not overwrite stored metadata with NULL.crates/server/src/services/push_delta.rs (1)
173-179: 💤 Low valueConsider typed error discrimination instead of string matching.
The string-based detection for "not found" errors is fragile—if a backend changes its error message format or a new backend is added, log levels could silently shift. Since errors are already typed as
Stringacross backends, this is pragmatic for now, but could be improved by introducing a structured error enum with aNotFoundvariant at the storage trait level.Given the non-fatal nature (only log level is affected), this is low priority.
🤖 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 `@crates/server/src/services/push_delta.rs` around lines 173 - 179, The current fragile string-matching on err in push_delta.rs should be replaced by a typed storage error; introduce a StorageError enum (e.g. StorageError::NotFound(String) and StorageError::Other(String)) at the storage trait level, change the storage trait's error type to Result<..., StorageError>, update all backend implementations to map their errors into StorageError variants, and then in push_delta.rs match Err(StorageError::NotFound(_)) to set the "not found" branch instead of using err.to_lowercase()/contains; update log calls to include the inner String from the enum.
🤖 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 `@packages/guardian-operator-client/README.md`:
- Around line 110-111: The README example uses the wrong API field name "asset"
but the client expects "assets" (an array); update the example occurrences of
"asset" to "assets" in the snippet so the documented response shape matches the
actual client shape (search for the example block that references asset,
noteCounts, TransactionSummary and proposalType and replace asset -> assets in
each occurrence, including the second snippet around noteCounts/proposalType).
In `@packages/guardian-operator-client/src/http.ts`:
- Around line 1655-1670: The code currently silently filters non-string items
for array fields (e.g., proposal.noteIds, proposal.consumeNotesNotes,
proposal.signerCommitments) which mutates client data; instead validate and fail
fast: when Array.isArray(record.xxx) assert every item is typeof 'string' (e.g.,
if (!record.note_ids.every(v => typeof v === 'string')) throw new
TypeError("malformed record.note_ids: expected string[]");) and only then assign
the array directly (proposal.noteIds = record.note_ids as string[]); apply the
same pattern to other similar array assignments (including the other occurrence
referenced around the 1847–1848 region) so malformed arrays cause an explicit
error instead of being silently filtered.
- Around line 1710-1712: Ensure retry_count is validated and coerced to a
non-negative integer before assigning to detail.retryCount: read
record.retry_count, coerce to a number (e.g., Number(record.retry_count)), check
Number.isInteger(value) && value >= 0, and only then set detail.retryCount =
value; otherwise do not set it (or set undefined) so behavior matches listing
entries and avoids negative/fractional values; update the logic around
record.retry_count and detail.retryCount accordingly.
In
`@speckit/features/007-dashboard-delta-details/contracts/http-get-account-delta-detail.md`:
- Around line 7-9: The fenced code block containing the HTTP path snippet GET
/dashboard/accounts/{account_id}/deltas/{nonce} is unlabeled and triggers MD040;
update that code fence in the file to include a language tag such as text or
http (e.g., ```text) so the block is properly labeled and the lint error is
resolved.
In
`@speckit/features/007-dashboard-delta-details/contracts/http-list-account-deltas.md`:
- Line 65: The spec line under "Pre-feature-007 row / EVM" uses the incorrect
field name `asset`; update it to `assets` to match the contract's defined array
field (`assets`) and remove ambiguity—ensure the enrichment fields list includes
`assets` (and not `asset`) so it aligns with other references to the `assets`
array in the contract.
- Around line 7-9: The fenced code block containing the HTTP path for the GET
endpoint "GET /dashboard/accounts/{account_id}/deltas" is missing a language tag
(causing MD040); update the fence from ``` to include an appropriate language
(e.g., ```http or ```text) so the snippet is properly tagged and the Markdown
linter warning is resolved.
In
`@speckit/features/007-dashboard-delta-details/contracts/http-list-global-deltas.md`:
- Around line 7-9: The fenced code block containing the request line "GET
/dashboard/deltas" is unlabeled and triggers MD040; add an explicit language tag
(for example ```http or ```text) to the fence so the snippet is annotated
(update the fenced block around GET /dashboard/deltas in the markdown).
- Line 41: The invariant currently forces a non-null category for every global
feed entry; change it so category is required only when enrichment is present
(i.e., preserve non-null account_id but make category conditional on
enrichment). Update the sentence "Every entry includes a non-null `account_id`
and a non-null `category`" to read something like "Every entry includes a
non-null `account_id`; `category` MUST be non-null when enrichment is present
(legacy/EVM/undecodable entries may omit it)" and adjust the SC-002
reference/validation language accordingly so that downstream validators check
enrichment-before-category.
In `@speckit/features/007-dashboard-delta-details/data-model.md`:
- Around line 85-99: The data-model docs claim `metadata` is nested and that
top-level `proposal_type` was removed, but the implemented listing exposes
flattened fields (category, proposal_type, assets, counterparty, note_counts) on
entries; update this section to match the contract returned by GET
/dashboard/accounts/{account_id}/deltas and GET /dashboard/deltas by replacing
the "metadata?: DeltaMetadata" description with explicit flattened fields
(category, proposal_type, assets, counterparty, note_counts) and note
compatibility for pre-feature rows (i.e., metadata omitted for historical/EVM
rows and proposal_type recoverable from metadata.proposal?.proposal_type),
ensuring the examples and narrative reflect the flattened wire shape used by the
implementation.
In `@speckit/features/007-dashboard-delta-details/spec.md`:
- Around line 98-99: FR-002 and FR-002a conflict with SC-002 by specifying two
different wire shapes (nested metadata vs flattened L1 enrichment); pick one
canonical shape and update the spec text accordingly: decide whether listing
entries use a nested "metadata" object with "metadata.category" and optional
"metadata.proposal" (and keep the FR-002a deterministic mapping from
"proposal.proposal_type") OR switch to flattened L1 enrichment fields (remove
"metadata" nesting and expose category/proposal fields at top-level), then edit
FR-002, FR-002a and the referenced SC-002 passages (and the duplicate block at
lines 149-153) to consistently describe that single chosen shape, including the
closed enumeration for category, the rule that category MUST be non-null when
present, and the mapping rules from proposal.proposal_type to category.
---
Outside diff comments:
In `@crates/server/src/services/dashboard_account_deltas.rs`:
- Around line 198-215: has_more is computed from filtered entries after calling
DashboardDeltaEntry::from_delta, which can drop Pending rows and cause
pagination to stop early; change the logic to compute has_more from the raw rows
length (use rows.len() > limit_us) before filtering, then keep truncating
entries and building next_cursor using entries.last() as before (references:
rows, entries, DashboardDeltaEntry::from_delta, has_more, limit_us,
entries.truncate, next_cursor, Cursor::account_deltas, cursor::encode,
state.dashboard.cursor_secret()).
---
Nitpick comments:
In `@crates/server/src/services/push_delta.rs`:
- Around line 173-179: The current fragile string-matching on err in
push_delta.rs should be replaced by a typed storage error; introduce a
StorageError enum (e.g. StorageError::NotFound(String) and
StorageError::Other(String)) at the storage trait level, change the storage
trait's error type to Result<..., StorageError>, update all backend
implementations to map their errors into StorageError variants, and then in
push_delta.rs match Err(StorageError::NotFound(_)) to set the "not found" branch
instead of using err.to_lowercase()/contains; update log calls to include the
inner String from the enum.
In `@crates/server/src/storage/postgres.rs`:
- Around line 430-461: PostgresService::submit_delta currently upserts NewDelta
with metadata_json which can be None and the ON CONFLICT do_update
unconditionally writes that NULL, wiping existing deltas.metadata; change the
upsert so the update preserves existing metadata when the incoming metadata is
None (e.g. use SQL COALESCE between the incoming/excluded metadata and
deltas::metadata in the DO UPDATE SET for deltas::metadata or the Diesel
equivalent), targeting the
insert_into(...).on_conflict(...).do_update().set(...) block that sets
deltas::metadata; keep all other fields the same and ensure
NewDelta/submit_delta still accepts Option metadata but does not overwrite
stored metadata with NULL.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: cee60898-895a-4878-b149-f1db12212973
📒 Files selected for processing (47)
.agents/skills/speckit-implement/SKILL.mdcrates/server/Cargo.tomlcrates/server/migrations/2026-05-25-000001_delta_metadata/down.sqlcrates/server/migrations/2026-05-25-000001_delta_metadata/up.sqlcrates/server/src/api/dashboard_feeds.rscrates/server/src/api/grpc.rscrates/server/src/api/http.rscrates/server/src/builder/handle.rscrates/server/src/delta_object.rscrates/server/src/delta_summary/build.rscrates/server/src/delta_summary/category.rscrates/server/src/delta_summary/decode.rscrates/server/src/delta_summary/mod.rscrates/server/src/delta_summary/projection.rscrates/server/src/delta_summary/tests/fixtures.rscrates/server/src/jobs/canonicalization/processor.rscrates/server/src/lib.rscrates/server/src/metadata/network.rscrates/server/src/schema.rscrates/server/src/services/dashboard_account_delta_detail.rscrates/server/src/services/dashboard_account_deltas.rscrates/server/src/services/dashboard_account_proposals.rscrates/server/src/services/dashboard_accounts.rscrates/server/src/services/dashboard_global_deltas.rscrates/server/src/services/delta_commit.rscrates/server/src/services/get_delta_proposal.rscrates/server/src/services/get_delta_proposals.rscrates/server/src/services/get_delta_since.rscrates/server/src/services/mod.rscrates/server/src/services/push_delta.rscrates/server/src/services/push_delta_proposal.rscrates/server/src/services/sign_delta_proposal.rscrates/server/src/storage/filesystem.rscrates/server/src/storage/postgres.rsexamples/operator-smoke-web/src/App.tsxexamples/operator-smoke-web/src/index.cssexamples/operator-smoke-web/vite.config.tspackages/guardian-operator-client/README.mdpackages/guardian-operator-client/src/http.test.tspackages/guardian-operator-client/src/http.tspackages/guardian-operator-client/src/index.tspackages/guardian-operator-client/src/types.tsspeckit/features/007-dashboard-delta-details/contracts/http-get-account-delta-detail.mdspeckit/features/007-dashboard-delta-details/contracts/http-list-account-deltas.mdspeckit/features/007-dashboard-delta-details/contracts/http-list-global-deltas.mdspeckit/features/007-dashboard-delta-details/data-model.mdspeckit/features/007-dashboard-delta-details/spec.md
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #257 +/- ##
==========================================
+ Coverage 75.28% 76.37% +1.09%
==========================================
Files 131 136 +5
Lines 23314 24888 +1574
==========================================
+ Hits 17551 19009 +1458
- Misses 5763 5879 +116 Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@crates/server/src/services/dashboard_account_delta_detail.rs`:
- Around line 178-181: The docstring for extract_raw_tx_summary_base64() is
misleading because it states it returns None for "EVM-shaped payloads" while the
function actually does not branch on payload type and simply returns any string
found at tx_summary.data or at the top-level data field; update the docstring to
reflect the real behavior by describing that the function returns the raw string
found at tx_summary.data or top-level data (if present) and returns None only
when those fields are absent, removing the example about EVM-shaped payloads so
callers/tests are not misled; reference extract_raw_tx_summary_base64(),
tx_summary.data, and the top-level data field when editing the comment.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dc0db755-2684-4f1f-8406-215548dbba7e
📒 Files selected for processing (15)
crates/server/src/delta_summary/mod.rscrates/server/src/delta_summary/projection.rscrates/server/src/evm/proposal.rscrates/server/src/schema.rscrates/server/src/services/dashboard_account_delta_detail.rscrates/server/src/storage/postgres.rsexamples/operator-smoke-web/src/App.tsxpackages/guardian-operator-client/README.mdpackages/guardian-operator-client/src/http.test.tspackages/guardian-operator-client/src/http.tsspeckit/features/007-dashboard-delta-details/contracts/http-get-account-delta-detail.mdspeckit/features/007-dashboard-delta-details/contracts/http-list-account-deltas.mdspeckit/features/007-dashboard-delta-details/contracts/http-list-global-deltas.mdspeckit/features/007-dashboard-delta-details/data-model.mdspeckit/features/007-dashboard-delta-details/spec.md
✅ Files skipped from review due to trivial changes (1)
- speckit/features/007-dashboard-delta-details/spec.md
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
crates/server/src/services/dashboard_account_delta_detail.rs (1)
184-193:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winProbe both raw locations before returning
raw_unavailable.Line 189 only falls back to top-level
datawhentx_summaryis absent, not whentx_summaryexists but has no stringdata. That makes the new docstring overstated and can incorrectly emitraw_unavailablefor mixed/malformed wrapper payloads.Suggested fix
fn extract_raw_tx_summary_base64(payload: &serde_json::Value) -> Option<String> { - let candidate = payload.get("tx_summary").unwrap_or(payload); - candidate - .get("data") + payload + .get("tx_summary") + .and_then(|tx_summary| tx_summary.get("data")) + .or_else(|| payload.get("data")) .and_then(|v| v.as_str()) .map(str::to_string) }🤖 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 `@crates/server/src/services/dashboard_account_delta_detail.rs` around lines 184 - 193, The function extract_raw_tx_summary_base64 currently prefers tx_summary by using payload.get("tx_summary").unwrap_or(payload) which fails to fall back when tx_summary exists but contains a non-string or missing data; change the lookup to first try payload.get("tx_summary").and_then(|t| t.get("data").and_then(|v| v.as_str())) and only if that returns None then probe payload.get("data").and_then(|v| v.as_str()), finally mapping the found &str to String—this ensures both the wrapped (tx_summary.data) and top-level data locations are probed before returning None.
🤖 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 `@packages/guardian-operator-client/src/types.ts`:
- Around line 326-329: The field type currently allows both undefined and null
("key?: string | null;"), causing two encodings for "no storage map key"; change
the public contract to a single representation by removing null and keeping the
optional field (use "key?: string"). Then update parseStorageChange(...) to
return undefined (not null) when a storage map key is absent and replace any
null checks for key in callers or serializers with undefined checks so all
clients see one consistent "no key" value.
---
Duplicate comments:
In `@crates/server/src/services/dashboard_account_delta_detail.rs`:
- Around line 184-193: The function extract_raw_tx_summary_base64 currently
prefers tx_summary by using payload.get("tx_summary").unwrap_or(payload) which
fails to fall back when tx_summary exists but contains a non-string or missing
data; change the lookup to first try payload.get("tx_summary").and_then(|t|
t.get("data").and_then(|v| v.as_str())) and only if that returns None then probe
payload.get("data").and_then(|v| v.as_str()), finally mapping the found &str to
String—this ensures both the wrapped (tx_summary.data) and top-level data
locations are probed before returning None.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 38550148-d627-4cb4-a710-dcf9636aa732
📒 Files selected for processing (11)
crates/server/src/api/grpc.rscrates/server/src/delta_summary/mod.rscrates/server/src/delta_summary/projection.rscrates/server/src/schema.rscrates/server/src/services/dashboard_account_delta_detail.rscrates/server/src/services/push_delta.rsexamples/operator-smoke-web/src/App.tsxpackages/guardian-operator-client/src/http.test.tspackages/guardian-operator-client/src/http.tspackages/guardian-operator-client/src/index.tspackages/guardian-operator-client/src/types.ts
💤 Files with no reviewable changes (2)
- packages/guardian-operator-client/src/index.ts
- packages/guardian-operator-client/src/http.test.ts
Summary by CodeRabbit
New Features
Bug Fixes
Documentation