Provider surface: wire the session lease TTL (buzz#84) - #119
Merged
Conversation
Task: #84, part of the agent-fleet-money epic (toon-meta#262 decision 12). PR #101 shipped the freshness invariant (providerAvailability.ts) and #101/1a593344 shipped advertise/see-jobs/ quote, but both left providerAvailability.ts's sessionLeaseTtlMs unwireable — no published @toon-protocol/client exposed the connector's session_lease_ttl_ms on the path this app's channel bootstrap actually negotiates through (toon-client#509, re-checked and re-blocked twice more in this issue's thread). toon-client#509 shipped in @toon-protocol/client@0.28.0 via ToonClient.getLastConnectorRouteTerms(), populated by ordinary publishEvent()/openChannel() bootstrap with no extra probe — the one remaining blocker this ticket closes. Key decisions: - Bumped @toon-protocol/client to ^0.28.0 (pnpm-workspace.yaml's minimumReleaseAgeExclude updated accordingly, lockfile regenerated). - ToonPaidWriter.getSessionLease() reads session_lease_ttl_ms off getLastConnectorRouteTerms()?.extra after every successful write, not just the first — ToonClient caches the greeting negotiation per peer, but a repeat write still proves the SESSION (not just the cached negotiation) was live at that moment, which is what the freshness window needs to bound. Undefined stays undefined (never a substituted 120_000 default) until a connector with connector#722 answers. - useProviderAvailability.ts wires that into providerAvailability.ts's deriveProviderAvailability, replacing ProviderJobsPanel's former coarse "is the transport ready" gate. - Found and fixed a real chicken-and-egg bug while wiring this: the lease is learned FROM a successful write, so gating the quote button on canQuoteJobs (kind === "available") would permanently block a provider agent's first-ever quote, since nothing else would produce the write the freshness state is waiting on. The quote action now gates on `availability.kind !== "stale"` instead — pending (unknown) proceeds, only a confirmed-dead session blocks — matching the freshness invariant's own asymmetry (a wrongly-allowed quote costs one rejected 1 µUSDC write; a wrongly-blocked one costs a provider its first job). - The @toon-protocol/client bump surfaced 5 pre-existing SVG accessibility lint failures (harness-logos icons, agent-outline.svg) and one theme.css formatting issue, unrelated to this ticket's code but now enforced by desktop-check against the new dependency resolution. Fixed via aria-hidden="true" (these are all consumed as <img src> with external alt text, matching the existing public/sounds/*.svg convention) and biome's auto-format. Files changed: desktop/package.json, pnpm-lock.yaml, pnpm-workspace.yaml, desktop/src/shared/api/toonPaidWriter.ts (+test), desktop/src/features/providers/lib/useProviderAvailability.ts (new), desktop/src/features/providers/ui/{ProviderJobsPanel,InboundJobsList, QuoteForm}.tsx, desktop/public/harness-logos/{grok,omp,openclaw, opencode}.svg, desktop/src/features/agents/assets/agent-outline.svg, desktop/src/shared/styles/globals/theme.css. Verified: fmt-check, desktop-tauri-fmt-check, clippy (workspace, -D warnings), test-unit (864 tests), desktop-check, desktop-test (4350 passed, 3 pre-existing skips), desktop-build, web-check, web-build — all green. No blockers remaining for this ticket. The provider surface (advertise, see jobs, quote, availability) is now fully wired end to end: quoting gates on a real, connector-sourced freshness window once one is known, and degrades to the coarse-but-safe "session confirmed reachable" read before the first write establishes it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit 1bd97b2) Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com>
…lper The buy/provide body was a three-way nested ternary (availability -> mode -> buy content), which CODING_STANDARDS.md calls out to avoid. Pulled it into renderJobsScreenBody() with straight-line if/else returns — same output, easier to follow. Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com> (cherry picked from commit cc4c818) Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com>
… caller The module comment still claimed there was "no live caller yet" for the session lease TTL, but this branch's useProviderAvailability.ts is exactly that caller — reading the TTL from ToonPaidWriter.getSessionLease() rather than the still-unpublished connector#698 constant the comment described. Signed-off-by: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 4, 2026
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.
Summary
Rescues PR #117's work (branch
sandcastle/issue-84, which conflicts because its first half was already squash-merged as #115). This PR is a clean rebase off currentmain: cherry-picks the two commits fromsandcastle/issue-84that are not yet onmain—1bd97b28(session lease TTL wiring) andcc4c8184(FactoryJobsScreen ternary refactor) — onto a fresh branch.@toon-protocol/clientto^0.28.0(plusminimumReleaseAgeExcludeentry and regenerated lockfile) to pick upToonClient.getLastConnectorRouteTerms()(toon-client#509/feat(desktop): expand default agent toolsets with canvas, forums, dms, and member list block/buzz#510).ToonPaidWriter.getSessionLease()readssession_lease_ttl_msoffgetLastConnectorRouteTerms()?.extraafter every successful write, wiring it intoproviderAvailability.ts's freshness invariant viauseProviderAvailability.ts.availability.kind !== "stale"(not the strictercanQuoteJobs) — the lease is learned from a successful write, so gating on a confirmed-live session would permanently block a provider agent's first quote.aria-hiddenaccessibility lint failures surfaced by the client bump, and atheme.cssformatting nit.FactoryJobsScreen.tsxinto an if/else render helper.One cherry-pick conflict in
desktop/src/shared/api/toonPaidWriter.ts(thegetClaimStatereturn type had moved from a hand-rolledClaimStateReadResultto the realClaimStateResulttype in #113, which landed onmainafter the original branch point) — resolved by keepingmain'sClaimStateResulttype and adding the incominggetLastConnectorRouteTermsmethod alongside it.Confirmed
git diff origin/main HEAD --statonly adds/modifies the expected files (client bump, lease wiring, SVG fixes,FactoryJobsScreenrefactor) — nothing already onmainis removed or reverted.pnpm install --frozen-lockfilepasses cleanly against the regenerated lockfile.Part of #84. Closes #118. PR #117 / branch
sandcastle/issue-84left untouched — to be closed by hand.Test plan
just fmt-checkjust desktop-tauri-fmt-checkjust clippy(workspace,-D warnings)just test-unit(864 tests)just desktop-checkjust desktop-test(4378 passed, 3 pre-existing skips)just desktop-buildjust web-checkjust web-build🤖 Generated with Claude Code