Money tab: the Network spend block and the refill action - #106
Merged
Conversation
Task: buzz#80, part of the agent-fleet-money epic (toon-meta#261 decision 9 / toon-meta#262). #75 shipped the Money tab with Model usage; this adds the sibling Network spend block (balance, allowance, runway, burn rate) and the app's first working refill/top-up action. Key decisions: - Budget state is a discriminated union matching the huddle fee quote's shape exactly (`relay | pending | unavailable | quoted`, networkSpendState.ts), with `canRefillNetworkSpend(state)` as the separate "can I act" answer per the issue's explicit AC — never a `state.kind === "quoted"` check scattered at call sites. - `ToonPaidWriter.getNetworkFlowStatus()` (toonPaidWriter.ts) prefers the connector's claim-state endpoint and falls back to the client's own locally-tracked deposit/cumulative-claimed read when the connector is unreachable or the client build predates `getClaimState` — the block never goes blank, per decision 5's "always-available free floor". - `getClaimState` is wired against a hand-rolled `ClaimStateReadResult` type, not imported from `@toon-protocol/client`: the pin is still `^0.25.1` (see Blockers below), so no real client build supplies this method yet — `tryClaimState` treats its absence as "no verified answer" and falls back cleanly, same as an unreachable connector. - Burn rate is sourced from a new module-level store (networkSpendLiveStore.ts) fed by `ToonEventTransport.onPaidWrite`, per the epic's established module-level-store + `useSyncExternalStore` idiom — a 5-minute trailing window, reset on community switch (wired into `resetCommunityState()`, AGENTS.md updated). Reusing `agentNetworkFlow.ts`'s `deriveNetworkRunway` directly on a zero (unmeasured) rate would read as "self-funding" — a lie — so `networkSpendState.ts` gates that call on a real sample having landed first ("burn rate hasn't been measured yet this session" otherwise). - Real, per-agent claim-state reads are scoped to `isSelf` (the identity this desktop process itself pays as, account index 0) — not to every managed agent. This is a verified architectural gap, not a scoping shortcut: no toon-clientd spawn/lifecycle exists for managed agents (buzz#79's ADR 0006 says so explicitly), no account-index lookup is exposed to the frontend, and `ToonClient.getClaimState`/ `getChannel*` only ever answer for channels THIS client instance tracks locally — there is no channel id to ask about for another agent's identity. Viewing another agent's Money tab honestly reads `unavailable`, never a fabricated figure. - Top-up reuses `ToonPaidWriter.depositToChannel` (buzz#77's real, already-wired deposit path) and `paymentsOverview.ts`'s `parseUsdcAmount` — the same real on-chain deposit Settings -> Payments already executes, now reachable from the Money tab too. Files changed: desktop/src/features/profile/lib/{networkSpendState, networkSpendLiveStore,useNetworkSpend}.ts (+tests), desktop/src/features/profile/ui/{UserProfilePanelNetworkSpend.tsx (new), UserProfilePanelMoneyTab.tsx,UserProfilePanelSections.tsx}, desktop/src/shared/api/{toonPaidWriter.ts (+tests),transportSelection.ts}, desktop/src/features/communities/useCommunityInit.ts, AGENTS.md. Verified: fmt-check, desktop-tauri-fmt-check, clippy (workspace, -D warnings), test-unit (864 tests), desktop-check (incl. file-size ratchet — UserProfilePanelSections.tsx was already at the grandfathered 1000-line ceiling; offset the one-line `isSelf` prop wire with a content-preserving one-line collapse of PROFILE_HERO_SPACING), desktop-test (4278 passed), desktop-build, web-check, web-build — all green. Blockers/notes for next iteration: bumping `@toon-protocol/client` to 0.26.0 (needed for the real `getClaimState()`, per the issue's own comment) is blocked in THIS sandbox by pnpm's minimumReleaseAge supply-chain gate — 0.26.0 was published too recently and the lockfile verification fails even with a `minimumReleaseAgeExclude` entry present (reproduced directly: `pnpm install` fails ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION regardless). The `getClaimState` seam is fully wired and tested against a hand-rolled type so the bump is the only remaining step once it clears that gate (or enough real time passes). Per-managed-agent live reads (not just `isSelf`) need toon-clientd spawn/lifecycle (still absent per buzz#79) plus an account-index Tauri command exposed to the frontend — both real, separate follow-ups, not this ticket's scope. buzz#68 (mid-huddle top-up unwired) is addressed at its root cause — a working top-up action now exists and is reachable — but its huddle-specific low-collateral warning is not implemented here (deferred v1.1 per epic decision 8); left a comment on #68 rather than closing it. Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 4, 2026
ALLiDoizCode
pushed a commit
that referenced
this pull request
Aug 4, 2026
* RALPH: earning badge on AgentIdentityCard, close out net-flow Money tab (buzz#86) Task: #86, part of the agent-fleet-money epic (toon-meta#262 decision 9). Per the issue's own re-dispatch comment, AC1/AC2 (income beside spend, income-aware runway) landed in PR #97 (agentNetworkFlow.ts) and were wired to real data in #108/#106 (PR #113, #106). AC4 (suppress the low-funds alert for a self-funding agent) was already implemented and tested by buzz#76/PR #111 — `deriveAgentFleetRunwayBadge` returns no badge once `deriveNetworkRunway` concludes an agent is self-funding, which flows straight through `countLowFundsAgents`/`shouldShowSidebarLowFundsCard` — confirmed via the existing "self-funding agents show no badge" test, no code change needed. This lands the one true remaining gap: AC3, an earning indicator on `AgentIdentityCard` in the Agents grid. Key decisions: - New `isAgentFleetEarning(state: NetworkSpendState): boolean` (agentFleetRunway.ts) wraps `agentNetworkFlow.ts`'s `isEarning` behind the same `state.kind !== "quoted"` gate `deriveAgentFleetRunwayBadge` already uses, so the earning badge and the low-funds suppression share one trusted-income bar and can never disagree about whether an agent is self-funding. - New `useAgentFleetEarningBadges` hook mirrors `useAgentFleetRunwayBadges`'s `isSelf`-only gate exactly (same documented buzz#79 ADR 0006 gap — no per-agent channel read exists for any identity but the one this desktop process itself pays as). Kept as its own hook rather than folding into the existing runway hook: the runway hook's `Map<pubkey, AgentFleetRunwayBadge>` return type is consumed as-is by two call sites (`UnifiedAgentsSection.tsx`, `SidebarLowFundsCard.tsx`), and `SidebarLowFundsCard.tsx` has no need for earning state, so widening its shape would be churn for one consumer's benefit. - `AgentStatusBadge` (the card's single-warning slot, `UnifiedAgentsSection.tsx`) gets a third, lowest-priority branch: operational issues, then a low-funds runway warning, then "Earning" (success-variant badge, `TrendingUp` icon) — same slot, no layout change. The three are mutually exclusive in practice (self-funding agents never carry a runway badge), but priority order is defensive. Files changed: desktop/src/features/agents/lib/{agentFleetRunway.ts (+3 tests),useAgentFleetEarningBadges.ts (new)}, desktop/src/features/agents/ui/UnifiedAgentsSection.tsx. Verified: fmt-check, desktop-tauri-fmt-check, clippy (workspace, -D warnings), test-unit (864 tests), desktop-check, desktop-test (4334 passed), desktop-build, web-check, web-build — all green. Blockers/notes for next iteration: the earning badge is wired but inert against real data today — `networkSpendState.ts`'s `deriveNetworkSpendState` hardcodes `incomeRateBaseUnitsPerSec: 0`/`incomeSampleCount: 0` (no live inbound-payment event feed exists yet, only `networkSpendLiveStore.ts`'s outbound `onPaidWrite` — documented in agentNetworkFlow.ts's module doc since PR #113), so `isEarning`/`isAgentFleetEarning` cannot return true from a real read until that income-rate feed lands. This is the same documented, pre-existing gap AC1/AC2's runway already ships ahead of, not new scope this ticket introduces. Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: toon-backlog-bot[bot] <294337193+toon-backlog-bot[bot]@users.noreply.github.com> * Dedupe fleet-status hooks: one useNetworkSpend read for badges + earning UnifiedAgentsSection called useAgentFleetRunwayBadges and the new useAgentFleetEarningBadges together, each independently calling useNetworkSpend(true)/useIdentityQuery and duplicating the same isSelf-matching loop — doubling the connector fetch on every mount. Fold both into useAgentFleetStatus, which computes runway badges and the earning set from a single self-spend read; useAgentFleetRunwayBadges becomes a thin wrapper so SidebarLowFundsCard is unaffected. Signed-off-by: toon-backlog-bot[bot] <294337193+toon-backlog-bot[bot]@users.noreply.github.com> --------- Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: toon-backlog-bot[bot] <294337193+toon-backlog-bot[bot]@users.noreply.github.com> Co-authored-by: toon-backlog-bot[bot] <294337193+toon-backlog-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the Network spend block and the refill action to the desktop app's Money tab.
Part of #80
This PR was produced by the sandcastle
agent:implementrunner and is awaiting human review.🤖 Generated with Claude Code