Skip to content

Provider surface: wire the session lease TTL (buzz#84) - #119

Merged
ALLiDoizCode merged 3 commits into
mainfrom
sandcastle/issue-118
Aug 4, 2026
Merged

Provider surface: wire the session lease TTL (buzz#84)#119
ALLiDoizCode merged 3 commits into
mainfrom
sandcastle/issue-118

Conversation

@toon-backlog-bot

Copy link
Copy Markdown

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 current main: cherry-picks the two commits from sandcastle/issue-84 that are not yet on main1bd97b28 (session lease TTL wiring) and cc4c8184 (FactoryJobsScreen ternary refactor) — onto a fresh branch.

  • Bumps @toon-protocol/client to ^0.28.0 (plus minimumReleaseAgeExclude entry and regenerated lockfile) to pick up ToonClient.getLastConnectorRouteTerms() (toon-client#509/feat(desktop): expand default agent toolsets with canvas, forums, dms, and member list block/buzz#510).
  • ToonPaidWriter.getSessionLease() reads session_lease_ttl_ms off getLastConnectorRouteTerms()?.extra after every successful write, wiring it into providerAvailability.ts's freshness invariant via useProviderAvailability.ts.
  • Preserves the deliberate quote gate availability.kind !== "stale" (not the stricter canQuoteJobs) — the lease is learned from a successful write, so gating on a confirmed-live session would permanently block a provider agent's first quote.
  • Fixes SVG aria-hidden accessibility lint failures surfaced by the client bump, and a theme.css formatting nit.
  • Extracts the buy/provide nested ternary in FactoryJobsScreen.tsx into an if/else render helper.

One cherry-pick conflict in desktop/src/shared/api/toonPaidWriter.ts (the getClaimState return type had moved from a hand-rolled ClaimStateReadResult to the real ClaimStateResult type in #113, which landed on main after the original branch point) — resolved by keeping main's ClaimStateResult type and adding the incoming getLastConnectorRouteTerms method alongside it.

Confirmed git diff origin/main HEAD --stat only adds/modifies the expected files (client bump, lease wiring, SVG fixes, FactoryJobsScreen refactor) — nothing already on main is removed or reverted. pnpm install --frozen-lockfile passes cleanly against the regenerated lockfile.

Part of #84. Closes #118. PR #117 / branch sandcastle/issue-84 left untouched — to be closed by hand.

Test plan

  • just fmt-check
  • just desktop-tauri-fmt-check
  • just clippy (workspace, -D warnings)
  • just test-unit (864 tests)
  • just desktop-check
  • just desktop-test (4378 passed, 3 pre-existing skips)
  • just desktop-build
  • just web-check
  • just web-build

🤖 Generated with Claude Code

claude added 2 commits August 4, 2026 18:32
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>
@ALLiDoizCode
ALLiDoizCode merged commit 4563908 into main Aug 4, 2026
4 checks passed
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.

Rebase PR #117 onto main — sandcastle/issue-84 conflicts after #115 was squash-merged

2 participants