Wait for OpenCode Go Zen balance in CLI usage reads - #2583
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b7f5e59748
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| /// than the subscription page is worth waiting for (bounded by the balance request timeout). | ||
| /// The menu-bar app keeps the short optional join grace so refreshes never stall behind it. | ||
| static func shouldWaitForZenBalance(context: ProviderFetchContext) -> Bool { | ||
| context.runtime == .cli |
There was a problem hiding this comment.
Exclude guard fetches from the Zen-balance wait
Using runtime == .cli also enables this policy for codexbar guard, whose CLIGuardCommand.guardFetchOutcome only consumes the subscription rate windows and wraps the whole operation in the user-specified guard deadline. If the subscription page succeeds but the optional Zen request is slow—especially when its workspace and billing requests run sequentially—a short --timeout can now produce an unavailable/timeout decision (or fail open) instead of evaluating the already-fetched quota; previously the 250 ms join returned that quota promptly. Restrict the wait to usage reads, or disable optional usage in the guard context.
Useful? React with 👍 / 👎.
| workspaceID: workspaceID, | ||
| cookieHeader: requestCookieHeader, | ||
| timeout: timeout, | ||
| timeout: waitForZenBalance ? min(timeout, self.optionalZenBalanceTimeout) : timeout, |
There was a problem hiding this comment.
Preserve the configured timeout for required Zen fallback
For a Zen-only account whose /go page has no subscription fields, requiredZenBalanceFallback reuses this task as the required source of the snapshot. With CLI waiting enabled, this line shortens that task from the caller's configured timeout (commonly 60 seconds) to 5 seconds, so a balance response arriving after 5 seconds now fails the entire CLI read even though it is within --web-timeout; the cap should apply only while the balance remains optional, or the fallback should retry with the original timeout.
Useful? React with 👍 / 👎.
|
Codex review: needs changes before merge. Reviewed August 4, 2026, 7:10 AM ET / 11:10 UTC. ClawSweeper reviewWhat this changesThe PR makes OpenCode Go CLI usage snapshots wait for Zen balance data within a five-second optional-request budget while preserving the short wait for app, guard, and diagnostic reads. Merge readinessKeep open: the PR has strong real-account proof, but the latest timeout calculation can still discard a Zen balance that completed before the five-second deadline when subscription parsing finishes later. Priority: P2 Review scores
Verification
How this fits togetherCodexBar fetches OpenCode Go subscription usage and a Zen prepaid balance concurrently, then returns a provider usage snapshot to the CLI and menu app. The changed policy determines how long each caller waits for the optional balance before producing that snapshot. flowchart LR
A[OpenCode Go pages] --> B[Concurrent subscription and Zen requests]
B --> C[Read policy]
C --> D[CLI completeness budget]
C --> E[App and guard short grace]
D --> F[Usage snapshot]
E --> F
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Copy recommended automerge instructionTechnical reviewBest possible solution: Retain the task result or arm its optional deadline when the Zen task is created, then add a regression where Zen completes before five seconds but subscription parsing completes afterward. Do we have a high-confidence way to reproduce the issue? Yes—source establishes a controlled path: let the balance finish before five seconds, delay subscription parsing beyond five seconds, and the zero-duration join can race away the completed result. The PR body also provides real-account evidence for the underlying current-main omission. Is this the best way to solve the issue? No—the elapsed-duration subtraction bounds the wait but does not retain a result that completed before the deadline. A race or completion record established at task creation is the narrower safe solution. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a82f509ea8e7. LabelsLabel justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (10 earlier review cycles; latest 8 shown)
|
|
Completed the maintainer follow-up in
Proof:
No merge performed. |
5564c2c to
d97edf5
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d97edf5fb1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - About: link the Website entry to codex.bar. | ||
|
|
||
| ### Fixed | ||
| <<<<<<< HEAD |
There was a problem hiding this comment.
Resolve the changelog conflict markers
The commit leaves an unresolved merge block in the 0.47.0 release notes; any rendered or published changelog will expose <<<<<<</=======/>>>>>>>, and the OpenCode Go fix is duplicated under the wrong historical release. Resolve the block by retaining the Alibaba entry and removing the duplicate OpenCode Go entry and markers (git diff --check also reports all three markers).
Useful? React with 👍 / 👎.
d97edf5 to
8f4efaf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f4efafc20
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| timeout: waitForZenBalance | ||
| ? .seconds(self.optionalZenBalanceTimeout) | ||
| : Self.optionalZenBalanceJoinGrace) |
There was a problem hiding this comment.
Start the optional Zen timeout when its task starts
When the subscription page is slow and the Zen request hangs, this five-second timer is not armed until after the subscription task has completed and been parsed, even though the Zen task started concurrently and still receives the caller's potentially 60-second timeout at line 157. In the current revision, a four-second subscription fetch can therefore be followed by another five-second join, making the CLI wait roughly nine seconds for a supposedly five-second-bounded optional request. Start the optional deadline with the Zen task, while restarting it with the configured timeout if it becomes the required Zen-only fallback, or subtract the task's elapsed time here.
Useful? React with 👍 / 👎.
|
@clawsweeper re-review Fixed the changelog conflict block from the last review: removed the conflict markers, retained the Alibaba 0.47.0 entry, removed the duplicate historical OpenCode Go line, and verified |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review Fixed the P1 from the last review: the optional Zen-balance deadline now starts when the balance task is created, so a slow subscription cannot stack a second full five-second wait on top of it. Added a regression covering a slow subscription plus a hung balance ( |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ff4df124ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let remaining = .seconds(Self.optionalZenBalanceTimeout) - (ContinuousClock.now - startedAt) | ||
| return max(Duration.zero, remaining) |
There was a problem hiding this comment.
Preserve balances completed before the deadline
When the subscription request or parsing takes more than five seconds but the Zen task has already completed successfully, this returns a zero timeout and then races an observer of the completed source task against Task.sleep(for: .zero). The timeout task can win and cancel/discard that already-available balance, so the new completeness path can still omit providerCost nondeterministically on slow subscription responses. Start and retain the timeout race when the Zen task is created, so completion before the deadline is recorded independently of when subscription parsing finishes.
Useful? React with 👍 / 👎.
Closes #2581
Summary
codexbar usage --provider opencodegocan silently drop the OpenCode Zen balance when the balance page responds more than 250 ms after the subscription page: the optional Zen join grace (optionalZenBalanceJoinGrace, 250 ms) resolves asniland cancels the in-flight balance request.This PR keeps the app's intentional fast refresh and changes the join contract for one-shot CLI reads:
OpenCodeGoUsageFetcher.fetchUsagegainswaitForZenBalance(defaultfalse). When enabled, the optional Zen balance is joined without the 250 ms grace, so a slower but successful balance response is included in the snapshot.OpenCodeGoUsageFetchStrategyenables the wait policy whencontext.runtime == .cli(codexbar usage,codexbar serve); the menu-bar app keeps the 250 ms bounded join.optionalZenBalanceTimeout), so a hung balance endpoint stalls a CLI read by at most ~5 s.nilbalance; the CLI read does not fail.This is the "Zen balance completeness is required for each CLI snapshot" contract from the issue review decision table. The alternative (retaining and asynchronously refreshing the last successful balance) remains open for the app/menu surface.
Tests
optional zen balance does not stall subscription usage(unchanged: app path still completes under 700 ms with a 1 s balance response)cli wait policy includes slow but successful zen balance(new: 1 s delayed valid balance is included)cli wait policy keeps subscription result when balance fetch fails(new)web strategy waits for zen balance only in cli runtime(new)Validation
swift test --filter 'OpenCodeGoUsageFetcherErrorTests|OpenCodeGoProviderStrategyTests'- 32/32 passedmake check- SwiftFormat 0 files need formatting, SwiftLint 0 violationsmake test- 758 selections / 64 groups, all passedCloses OpenCode Go provider silently drops Zen balance if balance fetch is >250ms slower than subscription fetch #2581
Summary
codexbar usage --provider opencodegocan silently drop the OpenCode Zen balance when the balance page responds more than 250 ms after the subscription page: the optional Zen join grace (optionalZenBalanceJoinGrace, 250 ms) resolves asniland cancels the in-flight balance request.This PR keeps the app's intentional fast refresh and changes the join contract for one-shot usage reads:
OpenCodeGoUsageFetcher.fetchUsagegainswaitForZenBalance(defaultfalse). When enabled, the optional Zen balance is joined with the optional-balance timeout (5 s) instead of the 250 ms grace, so a slower but successful balance response is included in the snapshot.ProviderFetchContextgainsrequiresOptionalUsageCompleteness(defaultfalse). Only usage-snapshot reads (codexbar usage,codexbar serve) set it, socodexbar guardand diagnostic commands keep the 250 ms bounded join and a slow balance cannot consume the guard deadline.--web-timeout; the required fallback is no longer capped at five seconds.nilbalance; the CLI read does not fail.Maintainer follow-up in
8fd66a4a6cbounds workspace discovery and the balance request at five seconds in the local-overlay helper and addsOpenCodeGoOptionalZenBalanceTimeoutTests.Tests
optional zen balance does not stall subscription usage(unchanged: app path still completes under 700 ms with a 1 s balance response)cli wait policy includes slow but successful zen balance(1 s delayed valid balance is included)cli wait policy keeps subscription result when balance fetch failscli wait policy keeps configured timeout when zen balance becomes required(Zen-only fallback keeps--web-timeout)web strategy waits for zen balance only on usage completeness reads(guard-style CLI contexts do not wait)Validation
swift test --filter 'OpenCodeGo...'- 34/34 passedmake check- SwiftFormat clean, SwiftLint 0 violationsmake test- 760 selections / 64 groups, all passedNote: the latest
swift-test-macos (1, 2)CI failure on this branch is an unrelated timing flake inKimiProviderTests(subscription grace is a total budget for existing usage windows, 0.25444 s vs a 250 ms budget); the PR does not touch Kimi code and the test passes locally.Real-behavior proof (redacted live
codexbar usage --provider opencodegotranscript) still needs an OpenCode Go account and is pending.Closes #2581
Summary
codexbar usage --provider opencodegocan silently drop the OpenCode Zen balance when the balance page responds more than 250 ms after the subscription page: the optional Zen join grace (optionalZenBalanceJoinGrace, 250 ms) resolves asniland cancels the in-flight balance request.This PR keeps the app's intentional fast refresh and changes the join contract for one-shot usage reads:
OpenCodeGoUsageFetcher.fetchUsagegainswaitForZenBalance(defaultfalse). When enabled, the optional Zen balance is joined with the optional-balance timeout (5 s) instead of the 250 ms grace, so a slower but successful balance response is included in the snapshot.ProviderFetchContextgainsrequiresOptionalUsageCompleteness(defaultfalse). Only usage-snapshot reads (codexbar usage,codexbar serve) set it, socodexbar guardand diagnostic commands keep the 250 ms bounded join and a slow balance cannot consume the guard deadline.--web-timeout; the required fallback is no longer capped at five seconds.nilbalance; the CLI read does not fail.Maintainer follow-up in
8fd66a4a6cbounds workspace discovery and the balance request at five seconds in the local-overlay helper and addsOpenCodeGoOptionalZenBalanceTimeoutTests.Real behavior proof
Live runs against a real OpenCode Go account, same command (
codexbar usage --provider opencodego --format json), same network, three runs each:main(e59539db, 0.47.0)providerCostmissingproviderCostmissingproviderCostmissing5564c2cf)providerCostpresentproviderCostpresentproviderCostpresentOn this network the Zen balance endpoint consistently finishes more than 250 ms after the subscription page, so
maindrops it on every run; the PR branch includes it on every run.Redacted PR-branch transcript (the output contains no cookies, account identifiers, or workspace IDs, so nothing further needed redacting):
[ { "provider" : "opencodego", "source" : "web", "usage" : { "primary" : { "resetsAt" : "2026-08-03T21:10:06Z", "usedPercent" : 2, "windowMinutes" : 300 }, "providerCost" : { "currencyCode" : "USD", "limit" : 0, "period" : "Zen balance", "updatedAt" : "2026-08-03T16:43:53Z", "used" : 0 }, "secondary" : { "resetsAt" : "2026-08-09T23:59:57Z", "usedPercent" : 9, "windowMinutes" : 10080 }, "tertiary" : { "resetsAt" : "2026-09-01T16:44:42Z", "usedPercent" : 51, "windowMinutes" : 43200 }, "updatedAt" : "2026-08-03T16:43:53Z" } } ]The same command on
mainreturns the identical shape withoutproviderCost:{ "provider" : "opencodego", "source" : "web", "usage" : { "primary" : { "usedPercent" : 2, "windowMinutes" : 300 }, "secondary" : { "usedPercent" : 9, "windowMinutes" : 10080 }, "tertiary" : { "usedPercent" : 51, "windowMinutes" : 43200 }, "updatedAt" : "2026-08-03T16:43:57Z" } }Tests
optional zen balance does not stall subscription usage(unchanged: app path still completes under 700 ms with a 1 s balance response)cli wait policy includes slow but successful zen balance(1 s delayed valid balance is included)cli wait policy keeps subscription result when balance fetch failscli wait policy keeps configured timeout when zen balance becomes required(Zen-only fallback keeps--web-timeout)web strategy waits for zen balance only on usage completeness reads(guard-style CLI contexts do not wait)Validation
swift test --filter 'OpenCodeGo...'- 34/34 passedmake check- SwiftFormat clean, SwiftLint 0 violationsmake test- 760 selections / 64 groups, all passedNote: the earlier
swift-test-macos (1, 2)CI failure on this branch was an unrelated timing flake inKimiProviderTests(subscription grace is a total budget for existing usage windows, 0.25444 s vs a 250 ms budget); the PR does not touch Kimi code and the test passes locally.