Skip to content

refactor: heights per wallet#117

Merged
xdustinface merged 2 commits into
v0.42-devfrom
refactor/heights-per-wallet
Apr 27, 2026
Merged

refactor: heights per wallet#117
xdustinface merged 2 commits into
v0.42-devfrom
refactor/heights-per-wallet

Conversation

@xdustinface
Copy link
Copy Markdown
Owner

No description provided.

@manki-review
Copy link
Copy Markdown

manki-review Bot commented Apr 27, 2026

Manki — Review complete

Planner (28s)
    refactor · 108 lines · 3 agents
    review effort: medium · judge effort: medium

Review — 11 findings
    ✅ Correctness & Logic — 0 (207s)
    ✅ Architecture & Design — 6 (138s)
    ✅ Testing & Coverage — 5 (151s)

Judge — 10 kept · 1 dropped (25s)
    kept: 4 warning · 3 suggestion · 3 nitpick
    dropped: 1 suggestion

Review metadata

Config:

  • Models: reviewer=claude-sonnet-4-6, judge=claude-opus-4-7
  • Review level: small (auto, 108 lines)
  • Team: Correctness & Logic, Architecture & Design, Testing & Coverage
  • Memory: disabled
  • Nit handling: issues

Judge decisions:

  • ✓ Kept: "max() aggregation for last_processed_height() gives misleading manager-level height" (warning, medium confidence) — "Impact: High (callers using manager-level height for safety decisions get over-reported value), Likelihood: Possible (depends on caller semantics). Single reviewer but technically sound — min vs max semantics are inconsistent with synced_height."
  • ✓ Kept: "First-wallet import always gets birth_height = 0 because last_processed_height() returns 0 with no wallets" (warning, high confidence) — "Impact: High (full rescan from genesis on first import), Likelihood: Probable (every fresh manager + first import). Real regression of prior pre-seeding capability."
  • ✓ Kept: "Removed implicit last_processed_height advance from update_synced_height breaks prior invariant" (warning, medium confidence) — "Impact: Medium (downstream callers relying on prior coupling silently break), Likelihood: Possible. Intentional per integration test, but a behavioral contract change worth flagging."
  • ✓ Kept: "synced_height added to WalletMetadata without addressing deserialization compatibility" (warning, high confidence) — "Impact: High (existing persisted wallets fail to load), Likelihood: Probable for any deployed users with bincode-serialized state. Two reviewers flagged this (findings 4 and 9) — strong consensus. Field inserted mid-struct compounds the risk for positional encodings."
  • ✓ Kept: "Tightening WalletManager bound to Send + Sync + 'static in accessors.rs is a silent API break" (nitpick, medium confidence) — "Impact: Low (compile error is loud, not silent), Likelihood: Unlikely (most real T already satisfy these). Documentation suggestion is reasonable but not critical."
  • ✓ Kept: "WalletInfoInterface trait grows without default implementations, burdening all implementors" (suggestion, medium confidence) — "Impact: Low (compile error, easy to fix), Likelihood: Possible for external implementors. Reasonable ergonomics improvement."
  • ✓ Kept: "test_last_processed_height only covers no-wallet case; max() logic untested" (suggestion, medium confidence) — "Impact: Medium (regression risk), Likelihood: Possible. Integration test does cover the path per the reviewer's own note, so unit test gap is real but mitigated."
  • ✓ Kept: "No test verifies synced_height() returns min() when wallets diverge" (suggestion, high confidence) — "Impact: Medium (asymmetric aggregation could regress undetected), Likelihood: Possible. Genuine test gap worth filling."
  • ✗ Dropped: "WalletMetadata gains synced_height field with no serde default — may break deserialization of persisted data" (ignore, high confidence) — "Merged with finding 4 — same underlying issue (deserialization compatibility for new synced_height field)."
  • ✓ Kept: "Removal of synced_height → last_processed_height coupling lacks a regression test" (nitpick, medium confidence) — "Impact: Low (test documentation only), Likelihood: Possible. The integration test already covers this implicitly per finding 3's note; explicit assertion is a minor improvement."
  • ✓ Kept: "FFI test test_wallet_manager_synced_height only tests no-wallet path" (nitpick, high confidence) — "Impact: Low (test coverage gap), Likelihood: Possible. Reviewer's own severity is appropriate."

Timing:

  • Parse: 1.3s
  • Review agents: 236.2s
  • Judge: 24.8s
  • Total: 262.3s

Move committed sync height into wallet metadata and expose it through `WalletInfoInterface` so `WalletManager` no longer relies on global cached heights.

Compute manager-level synced_height and tip_height as the minimum across wallet infos, propagate committed sync updates per wallet, and keep tip_height as per-wallet applied chain state.

Update tests and example messaging to match the new aggregation semantics.
@xdustinface xdustinface force-pushed the refactor/heights-per-wallet branch from dd9596d to 5b7c419 Compare April 27, 2026 01:10
manki-review[bot]
manki-review Bot previously requested changes Apr 27, 2026
Copy link
Copy Markdown

@manki-review manki-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per-wallet height refactor introduces semantic risks: max() aggregation for last_processed_height misreports manager state, first-wallet imports get birth_height=0 erasing the pre-seeding capability, and the new synced_height field lacks serde(default) for backward-compat with persisted wallets.

📊 10 findings (4 warning, 3 suggestion, 3 nitpick) · 108 lines · 262s

Review stats
{
  "model": "claude-sonnet-4-6",
  "reviewTimeMs": 262305,
  "diffLines": 108,
  "diffAdditions": 62,
  "diffDeletions": 46,
  "filesReviewed": 8,
  "agents": [
    "Correctness & Logic",
    "Architecture & Design",
    "Testing & Coverage"
  ],
  "findingsRaw": 11,
  "findingsKept": 10,
  "findingsDropped": 1,
  "severity": {
    "blocker": 0,
    "warning": 4,
    "suggestion": 3,
    "nitpick": 3
  },
  "verdict": "REQUEST_CHANGES",
  "prNumber": 117,
  "commitSha": "dd9596dde4029d5e865a43519a6de0e3db272b65",
  "agentMetrics": [
    {
      "name": "Correctness & Logic",
      "findingsRaw": 0,
      "findingsKept": 0,
      "responseLength": 4892
    },
    {
      "name": "Architecture & Design",
      "findingsRaw": 6,
      "findingsKept": 6,
      "responseLength": 7744
    },
    {
      "name": "Testing & Coverage",
      "findingsRaw": 5,
      "findingsKept": 4,
      "responseLength": 7235
    }
  ],
  "judgeMetrics": {
    "confidenceDistribution": {
      "high": 5,
      "medium": 6,
      "low": 0
    },
    "severityChanges": 11,
    "mergedDuplicates": 0,
    "defensiveHardeningCount": 1,
    "verdictReason": "novel_suggestion"
  },
  "fileMetrics": {
    "fileTypes": {
      ".rs": 8
    },
    "findingsPerFile": {
      "key-wallet-manager/src/process_block.rs": 4,
      "key-wallet-manager/src/lib.rs": 1,
      "key-wallet/src/wallet/metadata.rs": 1,
      "key-wallet-manager/src/accessors.rs": 1,
      "key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs": 1,
      "key-wallet-manager/tests/integration_test.rs": 1,
      "key-wallet-ffi/src/wallet_manager_tests.rs": 1
    }
  },
  "reviewerModel": "claude-sonnet-4-6",
  "judgeModel": "claude-opus-4-7"
}

Comment thread key-wallet-manager/src/process_block.rs
Comment thread key-wallet-manager/src/lib.rs
Comment thread key-wallet-manager/src/process_block.rs
Comment thread key-wallet/src/wallet/metadata.rs
Comment thread key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs
Comment thread key-wallet-manager/src/process_block.rs
Comment thread key-wallet-manager/tests/integration_test.rs
@manki-review
Copy link
Copy Markdown

manki-review Bot commented Apr 27, 2026

Manki — Review complete

Planner (22s)
    refactor · 108 lines · 3 agents
    review effort: medium · judge effort: medium

Review — 7 findings
    ✅ Architecture & Design — 2 (97s)
    ✅ Correctness & Logic — 1 (333s)
    ✅ Testing & Coverage — 4 (90s)

Judge — 6 kept · 0 dropped (20s)
    kept: 2 suggestion · 4 nitpick

Review metadata

Config:

  • Models: reviewer=claude-sonnet-4-6, judge=claude-opus-4-7
  • Review level: small (auto, 108 lines)
  • Team: Architecture & Design, Correctness & Logic, Testing & Coverage
  • Memory: disabled
  • Nit handling: issues

Judge decisions:

  • ✓ Kept: "Trait bounds on struct definition is a Rust anti-pattern" (nitpick, high confidence) — "Merged findings 1 and 3 — same issue (struct-level Send+Sync+'static). Two reviewers flagged it. Impact: Medium (API ergonomics, cascading bound creep), Likelihood: Possible (only matters for non-default T). Default T satisfies bounds so no current breakage, but the pattern is widely discouraged."
  • ✓ Kept: "Unrelated change: accessors.rs impl block unnecessarily broadened" (nitpick, medium confidence) — "Cascading consequence of finding 1; same root cause and fix. Single reviewer, cosmetic in practice but tied to the API-design concern."
  • ✓ Kept: "test_last_processed_height unit test reduced to no-wallet-only path, losing with-wallet coverage" (suggestion, high confidence) — "Single reviewer, but a legitimate coverage regression — the with-wallet path is now only covered by integration tests. Impact: Low-Medium (slower regression detection), Likelihood: Possible."
  • ✓ Kept: "No test verifies synced_height() returns min() when wallets diverge" (suggestion, high confidence) — "Single reviewer; valid gap — a max()/min() swap would not be caught. Matches an existing open thread (PRRT_kwDOQSlaXs59tDSP) that remains unaddressed."
  • ✓ Kept: "update_synced_height on ManagedWalletInfo has no dedicated unit test" (nitpick, medium confidence) — "Single reviewer. Invariant is simple (direct field write) and is covered indirectly through integration tests. Downgrading from suggestion to nitpick — a unit test would be nice but the trivial implementation makes regression risk low."
  • ✓ Kept: "FFI synced-height test exercises only the no-wallet path" (nitpick, high confidence) — "Reviewer themselves marked as nitpick and non-blocking. Test name vs. scope mismatch is minor."

Timing:

  • Parse: 3.9s
  • Review agents: 358.2s
  • Judge: 20.0s
  • Total: 382.1s

@manki-review manki-review Bot dismissed their stale review April 27, 2026 01:13

Superseded by new review

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.23529% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.52%. Comparing base (1e2a317) to head (5b7c419).

Files with missing lines Patch % Lines
key-wallet-manager/src/lib.rs 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           v0.42-dev     #117   +/-   ##
==========================================
  Coverage      70.51%   70.52%           
==========================================
  Files            319      319           
  Lines          66756    66758    +2     
==========================================
+ Hits           47074    47080    +6     
+ Misses         19682    19678    -4     
Flag Coverage Δ
core 75.81% <ø> (ø)
ffi 46.23% <ø> (ø)
rpc 20.00% <ø> (ø)
spv 86.72% <ø> (-0.04%) ⬇️
wallet 68.82% <88.23%> (+0.05%) ⬆️
Files with missing lines Coverage Δ
key-wallet-manager/src/accessors.rs 61.87% <ø> (ø)
key-wallet-manager/src/process_block.rs 91.70% <100.00%> (+3.82%) ⬆️
...allet/managed_wallet_info/wallet_info_interface.rs 75.55% <100.00%> (+1.13%) ⬆️
key-wallet-manager/src/lib.rs 61.00% <50.00%> (-0.18%) ⬇️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@manki-review manki-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous open threads remain unaddressed in this round. New findings are mostly about the struct-level Send + Sync + 'static bound spreading through impls (a Rust API anti-pattern) and thinned test coverage for the per-wallet height refactor.

📊 6 findings (2 suggestion, 4 nitpick) · 108 lines · 382s

Review stats
{
  "model": "claude-sonnet-4-6",
  "reviewTimeMs": 382090,
  "diffLines": 108,
  "diffAdditions": 62,
  "diffDeletions": 46,
  "filesReviewed": 8,
  "agents": [
    "Architecture & Design",
    "Correctness & Logic",
    "Testing & Coverage"
  ],
  "findingsRaw": 7,
  "findingsKept": 6,
  "findingsDropped": 1,
  "severity": {
    "blocker": 0,
    "warning": 0,
    "suggestion": 2,
    "nitpick": 4
  },
  "verdict": "APPROVE",
  "prNumber": 117,
  "commitSha": "5b7c4199983ab4dbf415cec2818f9abf0ad88c00",
  "agentMetrics": [
    {
      "name": "Architecture & Design",
      "findingsRaw": 2,
      "findingsKept": 2,
      "responseLength": 2329
    },
    {
      "name": "Correctness & Logic",
      "findingsRaw": 1,
      "findingsKept": 0,
      "responseLength": 1365
    },
    {
      "name": "Testing & Coverage",
      "findingsRaw": 4,
      "findingsKept": 4,
      "responseLength": 4356
    }
  ],
  "judgeMetrics": {
    "confidenceDistribution": {
      "high": 4,
      "medium": 2,
      "low": 0
    },
    "severityChanges": 6,
    "mergedDuplicates": 1,
    "defensiveHardeningCount": 2,
    "verdictReason": "only_nit_or_suggestion"
  },
  "fileMetrics": {
    "fileTypes": {
      ".rs": 8
    },
    "findingsPerFile": {
      "key-wallet-manager/src/lib.rs": 1,
      "key-wallet-manager/src/accessors.rs": 1,
      "key-wallet-manager/src/process_block.rs": 1,
      "key-wallet-manager/tests/integration_test.rs": 1,
      "key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs": 1,
      "key-wallet-ffi/src/wallet_manager_tests.rs": 1
    }
  },
  "reviewerModel": "claude-sonnet-4-6",
  "judgeModel": "claude-opus-4-7"
}

@@ -220,15 +217,14 @@ mod tests {
let mut manager: WalletManager<ManagedWalletInfo> = WalletManager::new(Network::Testnet);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 ✨ Suggestion: test_last_processed_height unit test reduced to no-wallet-only path, losing with-wallet coverage

The unit test was deliberately trimmed to only assert that update_last_processed_height is a no-op when no wallets are registered. The previous version at least exercised the state machine (values 1000 → 5000 → 10 were stored and checked), giving a local regression signal. Now the only unit-level coverage for the with-wallet path lives in the slower integration test suite, so a bug in the per-wallet update_last_processed_height call inside process_block.rs would not be caught by cargo test -p key-wallet-manager without the integration tests. Add a small with-wallet sub-case: create one wallet, call update_last_processed_height(1000), assert last_processed_height() == 1000 and that the wallet info also shows 1000.

Suggested fix
Suggested change
let mut manager: WalletManager<ManagedWalletInfo> = WalletManager::new(Network::Testnet);
// After the existing no-wallet assertions, add:
let wallet_id = manager
.create_wallet_from_mnemonic(TEST_MNEMONIC, "", 0, WalletAccountCreationOptions::Default)
.unwrap();
manager.update_last_processed_height(1000);
assert_eq!(manager.last_processed_height(), 1000);
let info = manager.get_wallet_info(&wallet_id).unwrap();
assert_eq!(info.last_processed_height(), 1000);
AI context
{
  "file": "key-wallet-manager/src/process_block.rs",
  "line": 217,
  "severity": "suggestion",
  "confidence": "high",
  "flaggedBy": [
    "Testing & Coverage"
  ],
  "title": "test_last_processed_height unit test reduced to no-wallet-only path, losing with-wallet coverage",
  "fix": "// After the existing no-wallet assertions, add:\nlet wallet_id = manager\n    .create_wallet_from_mnemonic(TEST_MNEMONIC, \"\", 0, WalletAccountCreationOptions::Default)\n    .unwrap();\nmanager.update_las",
  "reachability": "reachable"
}

assert_eq!(wallet_info1.last_processed_height(), 30000);
assert_eq!(wallet_info2.last_processed_height(), 25000);
assert_eq!(manager.last_processed_height(), 30000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 ✨ Suggestion: No test verifies synced_height() returns min() when wallets diverge

The expanded test_block_height_tracking test calls update_synced_height once and verifies both wallets reach the same value, but never sets the two wallets to different synced_height values to confirm the manager-level min() aggregation. A bug that accidentally uses max() instead of min() would pass all current assertions. Add a step that mutates each wallet's synced_height independently (e.g., wallet1 to 30 000, wallet2 to 20 000) and asserts manager.synced_height() == 20_000.

Suggested fix
Suggested change
// After the two wallets are at synced_height 40_000:
let wi1 = manager.get_wallet_info_mut(&wallet_id1).unwrap();
wi1.update_synced_height(50_000);
// wallet2 still at 40_000
assert_eq!(manager.synced_height(), 40_000, "min() should return the lower per-wallet height");
AI context
{
  "file": "key-wallet-manager/tests/integration_test.rs",
  "line": 237,
  "severity": "suggestion",
  "confidence": "high",
  "flaggedBy": [
    "Testing & Coverage"
  ],
  "title": "No test verifies synced_height() returns min() when wallets diverge",
  "fix": "// After the two wallets are at synced_height 40_000:\nlet wi1 = manager.get_wallet_info_mut(&wallet_id1).unwrap();\nwi1.update_synced_height(50_000);\n// wallet2 still at 40_000\nassert_eq!(manager.synce",
  "reachability": "reachable"
}

@xdustinface xdustinface merged commit 53b25c4 into v0.42-dev Apr 27, 2026
41 checks passed
@xdustinface xdustinface deleted the refactor/heights-per-wallet branch April 27, 2026 01:36
xdustinface added a commit that referenced this pull request Apr 27, 2026
The per-wallet semantics from #117 keep `synced_height` and `last_processed_height` independent. The rebase reintroduced a manager-level bump that mirrored the trait default, contradicting the test and per-wallet model.
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.

2 participants