Skip to content

fix(cli): agent-UX + billing-visibility follow-ups (RND-590/592/593/594/595)#166

Open
mpjunior92 wants to merge 7 commits into
release/v1.0.0from
matheuspereirajunior/cli-agent-ux-billing-followups
Open

fix(cli): agent-UX + billing-visibility follow-ups (RND-590/592/593/594/595)#166
mpjunior92 wants to merge 7 commits into
release/v1.0.0from
matheuspereirajunior/cli-agent-ux-billing-followups

Conversation

@mpjunior92

@mpjunior92 mpjunior92 commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Follow-up CLI/SDK fixes on top of #164, addressing five UX/DX tickets plus a billing-display bug. Each ticket is its own commit; live-verified against both deployed backends (compute-tee on sepolia/mainnet, ecloud-platform on sepolia-dev).

Changes

RND-590 — deploy guards against duplicate same-named billable apps (59c69d9)
deploy enumerated name collisions only against the local YAML registry, so a clean machine/CI (empty registry) silently provisioned a second billable app. Now enumerates the callers apps on-chain (getAllAppsByDeveloper), resolves profile names via /info, and errors (exit 2, pointing to app upgrade ) when a live app already uses the name. --force-new` bypasses. The check is fail-open: a read failure warns and proceeds.

RND-592 — app status --wait docs (c435144)
Align the deploy skill guidance and --wait help text with shipped behavior: --wait only blocks while the app is transitioning and returns immediately for settled statuses.

RND-593 — reconcile release digest after upgrade (b19e4ad)
After app upgrade, the release digest is served by a lagging Ponder indexer, so an agent could read the old digest and retry a successful upgrade. New reconcileReleaseDigest SDK helper polls until the reported digest matches the just-deployed one (or warns "propagation in progress", exit 0). The digest is surfaced out of the SDK so the exact target is known on both verifiable and non-verifiable paths. --fresh (from the ticket) was dropped after verifying in the server source that the digest comes from a GraphQL POST with no cache layer — re-reading, not cache-busting, is the fix.

RND-594 — surface TLS-off (DOMAIN unset) (3158617)
When DOMAIN is unset the app runs but nothing binds ports 80/443, with no signal. deploy/upgrade now warn pre-flight; app info shows a static TLS line (gated so it stays out of the denser app list). DOMAIN is encrypted, so the info line is informational.

RND-595 — billing status credit split (6785e88)
billing status printed one ambiguous "Credits" line. Now shows a grouped funds block: Promotional (+expiry) / Paid / Total from the billing-api 3-way split (new SDK getAccountCredits), plus Wallet ETH + USDC — with a note that Stripe credits are separate from on-chain funds. Each read is best-effort.

Billing display fix (1ed75f5) + reconcile doc (cfcd923)
Pre-existing line-item bug: the renderer took the last two words of the Stripe description as the SKU, yielding garbage like Compute (/ month)). Now parses the SKU correctly and uses structured price/quantity fields; preserves the (correct) hourly rate, verified against the published pricing table. Also shortens wallet ETH display to 4 dp.

New billing status output

Subscription Status:
  Wallet: 0x540d6701c396f77c3601FC34585107497ED71495
  Status: ✓ Active
  Product: compute
  Current Period: 20/05/2026 - 20/06/2026

  Line Items:
    • Compute (Pro 1): $0.00 (0 hours × $0.074/hour)
    • Compute (Starter 2): $0.00 (0 hours × $0.041/hour)
    • Compute (Starter 1): $0.00 (0 hours × $0.027/hour)
    • Compute (Pro 2): $0.00 (0 hours × $0.118/hour)
    • Compute (Enterprise 1): $0.00 (0 hours × $0.329/hour)
    • Compute (Enterprise 2): $0.00 (0 hours × $0.664/hour)

Credits (Stripe):
  Promotional: $9.98 (expires 19/07/2026)
  Paid:        $10.00
  Total:       $19.98
  (Stripe credits pay compute usage — separate from the on-chain wallet below)

Wallet (sepolia):
  ETH:  0.0989 ETH
  USDC: 10 USDC

Payment & Invoices:
  https://billing.stripe.com/p/session/...

The old format collapsed all of this into a single ambiguous Credits: $19.98 line, with line items rendered as Compute (/ month)).

Testing

  • SDK: 56 tests pass. CLI: 160 tests pass.
  • Live-verified billing status (both backends), app status --wait (both), and the credit split / line items with a real wallet.

🤖 Generated with Claude Code

mpjunior92 and others added 7 commits June 9, 2026 14:38
…tatuses

Align the deploy SKILL.md agent guidance and the --wait flag help text with
the shipped behavior: --wait only blocks while the app is transitioning
(Deploying/Upgrading/etc.) and returns immediately for already-settled
statuses (Running/Stopped/Terminated/Suspended/Failed).

Completes the agent-facing docs acceptance criterion; the command, --wait
timeout handling, and 502/503/504 retry already landed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enumerate the caller's apps on-chain (getAllAppsByDeveloper), filter out
terminated, resolve profile names via the coordinator-DB-backed /info, and
error (exit 2) when a live app already uses the requested name — pointing to
'app upgrade <addr>'. --force-new bypasses. The check is fail-open: any read
failure warns and proceeds rather than blocking a legitimate deploy.

Fixes the duplicate-billable-app leak where the name check only consulted the
local YAML registry, so a clean machine/CI (empty registry) never detected an
existing same-named app and silently provisioned a second one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
After `app upgrade`, poll the release digest until it matches the digest just
deployed (or warn "indexer propagation in progress"), so an agent never reads
the stale pre-upgrade digest and retries an already-successful upgrade.

The expected digest is surfaced out of the SDK (prepareRelease ->
PreparedUpgrade -> CLI) so an exact target is known on both the verifiable
(sha256:) and non-verifiable (0x bytes32) paths; reconcileReleaseDigest
normalizes either form. Adds the reconcileReleaseDigest SDK helper (polls
getApp, never throws on timeout) and exposes it on the app module.

Verified root cause in compute-tee: GET /apps/:id serves the digest from a
Ponder indexer via GraphQL POST with no cache layer (API code has no cache on
this path; the GCP HTTP LB has enable_cdn=false). So re-reading -- not
cache-busting -- is the fix; the ticket's --fresh/--no-cache criterion is
dropped as a no-op against this backend.

Closes RND-593.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…p info

When DOMAIN is unset the app runs but nothing binds ports 80/443, so HTTP(S)
requests are refused with no signal — a "Running" web app that is unreachable.

- deploy/upgrade now warn pre-flight (after the env file is finalized, so an
  inline --env DOMAIN=... still counts as on) when isTlsEnabledFromEnvFile is
  false, pointing to `ecloud compute app configure tls`.
- app info shows a static TLS line (gated behind a showTls option so it stays
  out of the denser app list). DOMAIN is encrypted (private env), so the line
  is informational rather than a live on/off read.

No behavior change when DOMAIN is set.

Closes RND-594.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llet

billing status previously printed one ambiguous "Credits" line (the Stripe
balance) and a lone wallet-ETH line, so an agent couldn't tell applied promo
credit from spendable funds. Now it shows a grouped funds block:

- Credits (Stripe): Promotional (+expiry), Paid, Total — pulled from the
  billing-api 3-way split (new SDK billing.getAccountCredits → the deployed
  GET /accounts/:eth/credits route), not recomputed in the CLI — with a note
  that Stripe credits are separate from the on-chain wallet.
- Wallet (<env>): ETH (gas) + USDC (via getTopUpInfo, 6 decimals).

Each read is best-effort: a failure warns and degrades (credits → single
Stripe line; wallet → omit), and core subscription status always prints.

Verified live against both deployed billing-API versions: compute-tee
(sepolia/mainnet prod, GCP) and ecloud-platform (sepolia-dev, AWS) — both
return the promotional/paid/total split on the unprefixed /accounts/:eth/credits
route.

Closes RND-595.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… ETH

Two display fixes in `billing status`, surfaced while testing RND-595:

1. Line items: the Stripe description format is '<qty> × <SKU> (at $price /
   month)', but the renderer took the last two words as the SKU, yielding
   garbage like 'Compute (/ month)): ...'. Now parse the SKU with a regex
   (verbatim fallback if it stops matching) and use the structured
   quantity/price/subtotal fields. Price is the hourly rate (verified against
   the published pricing table; the description's '/ month' text is a
   Stripe-side mislabel), so 'hours × $price/hour' is preserved. Dropped the
   dead sepolia/mainnet branch.

2. Wallet ETH: render at most 4 decimal places (e.g. 0.0989 ETH) instead of the
   full 18-decimal wei value — the leading digits are what matter for gas.

Both extracted as pure, unit-tested helpers in billingFormat.ts. Live-verified
on sepolia (compute-tee); line items are a no-op on sepolia-dev (ecloud-platform
returns none).
@mpjunior92 mpjunior92 self-assigned this Jun 11, 2026
@mpjunior92 mpjunior92 requested a review from mmurrs June 11, 2026 17:01
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.

1 participant