Repository navigation
fix(harness): stop telling a token-billed operator to wait for a subscription - #11
Merged
Merged
Conversation
A spent allowance was reported as a subscription usage limit whatever paid for the harness. DeepSeek and Muse Code are billed by the token, so an operator whose wallet ran dry was told to wait for an allowance that never resets, to raise a plan that does not exist, and that usage-based API billing is forbidden — which is what they are running. All three sentences reach the operator through the capability card. The refusal now takes the advice from HARNESS_BILLING: a subscription is waited out, a wallet is topped up. The module is named for what it detects rather than for the billing it used to assume. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The streaming fixture rejects its process promise when the watchdog aborts, and the run only awaits that promise after it has written the events before it to disk. In between, the rejection has nothing watching it, so Node reported it as unhandled and vitest failed the whole suite on a run whose every test passed — intermittently, under the load of the full workspace test, which is what the pre-push hook runs. The rejection is now marked as observed where it is created. The run awaits the same promise and still sees the same rejection. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…every harness A CLI that cannot answer for its own version is a missing installation, and the sentence saying so asked for "an active product subscription login" whatever the harness authenticates with. DeepSeek is handed a key and Muse Code logs in to Meta, so both were sent after something that does not exist — and the capability card shows the sentence verbatim. The refusal now names only what this gap is about, the CLI itself. Which credential is missing is already the authentication check's to say, and each harness says it in its own words. The README requirement is corrected the same way: it still named two of the five harnesses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…riptions The base class every harness extends, the preflight it runs, the environment it sanitizes and the gap it reports when a credential is missing were all named for a subscription. Three harnesses hold one; DeepSeek is handed an API key and Muse Code logs in to a Meta account, and both extended SubscriptionCliHarness and raised HarnessCapabilityGaps.SUBSCRIPTION to say they had no key. The readiness state that gap maps to has always been NOT_SIGNED_IN, so the surrounding code already disagreed with the name. SubscriptionCliHarness is CliAgentHarness, subscription-preflight is harness-preflight, subscription-environment is harness-environment, the gap is CREDENTIAL and the error code every capability error carries is CAPABILITY_REQUIRED rather than SUBSCRIPTION_AUTH_REQUIRED — it is set for a spent allowance too. Three more operator-facing sentences went with them. Dispatch asked for "a responsive Codex, Claude or GLM CLI with an active product subscription" and told the operator that "API billing is forbidden" — the second copy of a clause already removed from the spent-allowance refusal, and both are shown on the capability card. Hibernation reported "No subscription-authenticated agent CLI harness is available" for a roster of five. BREAKING CHANGE: @openlab/harness subpaths ./subscription-cli-harness, ./subscription-cli-harness.types, ./subscription-environment and ./subscription-usage-limit are now ./cli-agent-harness, ./cli-agent-harness.types, ./harness-environment and ./spent-allowance. The package is not published. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DeepSeek's remaining money and Muse Code's "Meta publishes no balance" were both reported in `plan`, the field that carries the tier a vendor sells. The page then ran them through the helper that title-cases a plan name and rendered them in the badge a bought subscription gets, so a dollar amount appeared as though it were a plan the operator holds. An allowance now carries `plan` and `balance` separately, the same split the preflight has always reported: a vendor that sells tiers names one and states no balance, a vendor that sells tokens states a balance and has no tier. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…subscriptions The domain that reads what each harness has left was called subscription-allowance across four packages, served at /api/subscriptions, and shown to the operator under a heading that said Subscriptions. It carries DeepSeek's wallet and Muse Code's metered account, neither of which is a subscription, so the page named two of its five cards wrong and the settings tab named itself wrong above them. The domain is harness-allowance, the route is /api/allowances, the section is Allowances, and the daemon plumbing that passed these readings around as `subscriptions` passes them as `allowances`. What a vendor answers is a HarnessAllowanceReading and what the lab publishes is a HarnessAllowance, which are two different shapes that were both called the same thing. The dashboard directory is allowance-panel rather than harness-allowance so its `#src/<dir>/<file>` paths cannot collide with the protocol's, which the dashboard tsconfig resolves against its own src. BREAKING CHANGE: GET /api/subscriptions is now GET /api/allowances. The daemon and dashboard ship together and no third party pins it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ating it The site kept its own copy of which harness costs money — a second HARNESS_BILLING table declared beside the roster, with the answer hand-written into each entry. Two tables for one fact, and this is the page an operator decides what to install from, so a drift between them would land in the worst possible place. The roster entries now name the harness they stand for and the page reads the billing out of @openlab/protocol, the same table the dashboard card and the spent-allowance refusal read. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… subscriptions The README listed the settings panel under its old heading, and the readiness schema said a ready harness names "the subscription it is signed in to" — which two of the five never do, and which the schema itself contradicts by carrying a balance beside the plan. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Exhaustion was read off the windows alone, and a wallet meters none — so a DeepSeek wallet DeepSeek had stopped serving came back as an account with everything still to spend. The panel showed it available beside a balance of nought while the preflight was already refusing every run on the same verdict, leaving an operator nothing on the page to explain why nothing dispatched. The vendor's own verdict is carried on the reading and taken at its word, so the panel and the dispatch decision agree and the harness is stopped a step earlier. A spent account is only called a plan where the vendor sold a tier: a wallet comes back when the operator pays for it, never on a renewal they could wait for.
1 task
This branch was successfully deployed
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.
The harness layer was built when every harness ran on a subscription, and it kept that vocabulary
after DeepSeek and Muse Code arrived on token billing. The names were the visible half —
SubscriptionCliHarnessis the base class all five extend, andHarnessCapabilityGaps.SUBSCRIPTIONis what DeepSeek raises to say it holds no API key — but the sentences underneath had gone wrong
with them, and three of those are shown to the operator.
A DeepSeek operator whose wallet ran dry was told to wait for an allowance that never resets, to
raise a plan that does not exist, and that "usage-based API billing is forbidden" — which is what
they are running. A failed preflight asked every harness for "an active product subscription login".
Blocked dispatch asked for "a responsive Codex, Claude or GLM CLI" against a roster of five. All
three reach the capability card verbatim.
What changed
Each of these is its own commit, in this reading order:
HARNESS_BILLING— a subscription is waited out, awallet is topped up. The forbidden-billing clause is gone from both places it appeared.
pnpm testfailed intermittently on a suite where every test passed. Pre-existing onmain;fixed here because it is what
pre-pushruns.missing is already each harness's own error to raise, in its own words.
CliAgentHarness,harness-preflight,harness-environment,HarnessCapabilityGaps.CREDENTIAL,HarnessErrorCodes.CAPABILITY_REQUIRED. The readiness statethat gap maps to has always been
NOT_SIGNED_IN, so the surrounding code already disagreed withthe old name.
publishes no balance" were both written into
plan, then run through the helper that title-casesa plan name and rendered in the badge a bought subscription gets.
/api/subscriptionsbecomes/api/allowances, and the settings panel is Allowances.@openlab/protocolinstead of keeping a secondHARNESS_BILLINGtable of its own.Allowances panel, before and after
Shot from a lab actually running on this machine,
OPENLAB_HOMEpointed at a disposable directory.Muse Code is the visible case: its sentence used to sit in the plan badge, title-cased into
"Metered — Meta Publishes No Balance" beside Codex's "Plus" and Claude's "Max".
The same lab answers
GET /api/allowanceswith the plan and the balance split apart:Breaking
GET /api/subscriptionsis nowGET /api/allowances. The daemon and dashboard ship together andno third party pins it.
@openlab/harnesssubpaths moved. The package isprivate: trueand is never published;only this repository imports it.
Not done here
windowed subscription can carry one),
AgentHarnessBilling.SUBSCRIPTIONitself, and the rosternotes about Codex, Claude and GLM. They are about actual subscriptions.
reproducing them on screen needs a spent wallet, which this machine has no key for.
Verified with
pnpm check(biome, typecheck, 733 tests, build) and against a running daemon.Written by Claude Opus 5 through the Claude Code harness.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmithwith what you need. Autofix is disabled.Note
Stop telling token-billed operators to wait for a subscription when their allowance is spent
SubscriptionCliHarness→CliAgentHarness,runSubscriptionPreflight→runHarnessPreflight, and all related types/constants throughout the harness and daemon packages, removing subscription-specific wording from user-facing messages.spentAllowanceErrorpath that distinguishes subscription-billed harnesses (advise waiting for reset/raising plan) from token-billed wallet harnesses (advise adding balance), usingHarnessCapabilityGaps.ALLOWANCEinstead of the oldSUBSCRIPTIONgap.readDeepseekAllowanceandreadMuseAllowancefor token-billed harnesses, and areadHarnessAllowancedispatcher covering all supported harness kinds; allowance readings now carry explicitbalanceandspentfields.HarnessCapabilityGaps.SUBSCRIPTION→CREDENTIALandHarnessErrorCodes.SUBSCRIPTION_AUTH_REQUIRED→CAPABILITY_REQUIRED; the/api/subscriptionsendpoint moves to/api/allowances./api/subscriptions→/api/allowances) and the renamed error codes/gap identifiers are breaking changes for any client consuming those values directly.Macroscope summarized 1a36458.