Young's Mind
03 Decisions

Young Rulings 2026 10 10 Four

Consolidated. This note's findings now live in ../MIN-STUDIES.md §1. The original is kept for its measurements; do not re-derive from it.

Young's four rulings

Young, 2026-10-10: the four questions that were blocking the most, answered. These are decisions, not proposals. Each is applied to its stage below.

#QuestionRulingUnblocks
1Stage 5's owner (memory)Min owns it — Sol proves itStage 5 entirely
2a2a-sdk 1.2.2, or Hermes' plugin?The official A2A SDKStage 2
3Which stuck number?3600 s — refine when we have more dataStage 3.3's proof
4GO $60 hard or soft, and GO-before-ZEN?GO exhaustion rolls over to ZENStage 6's guard

Ruling 1 — Stage 5 (memory) is Min's, proof by Sol

Applied. Min owns the memory model; Sol owns the proof of the second capture mechanism. The two-owner rule holds — the builder does not prove their own control.

Why the pairing works: what an agent remembers is identity-adjacent (the registry lane), and a second capture mechanism is a control, which is proven by someone other than its author.


Ruling 2 — the official A2A SDK (a2a-sdk 1.2.2)

Applied. Stage 2 builds on the official SDK, not on Hermes' plugin.

This overrides my earlier lean and I am recording that plainly. I recommended the plugin because it was live, correct and free; Young ruled the official implementation, and the reasons are sound:

Why the SDK winsEvidence
It is the spec's own implementationa2aproject/a2a-python — the reference
Three bindings, not oneJSON-RPC · HTTP+JSON/REST · gRPC
Multi-replica cluster modeadded in 1.2.0 — a fleet can scale
The Inspector tests against itthe conformance tool and the SDK are the same project
Migration is a flagsrc/a2a/compat/v0_3/ still ships at the 1.2.2 tag

Version, pinned — and the distinction that matters:a2a-sdk = 1.2.2 (2026-10-05, verified on PyPI) · A2A Protocol = 1.0. Two different numbers. V2's defect was declaring 1.0.0 while serving v0.3 names — so both are pinned, and neither is inferred from the other.

Cost recorded, per Mira's lane: the SDK adds 26 packages. That is the price of the ruling and it is accepted.

What Hermes' plugin becomes: a reference implementation we diff against, not our transport. It stays useful — it is a working v1.0 server we can compare our conformance to.


Ruling 3 — CORRECTED by Young: the stuck rule is 300 s

Young, 2026-10-10 (correction): "Thanks Sol for point out. Ruling 3 — 300 s (will refine when we have more data)."

A task is stuck when it has produced no reply for 300 s.

Source: Hermes' A2A orphan watchdog — plugins/platforms/a2a/adapter.py:38, _MIN_ORPHAN_TIMEOUT = 300. Sol was right to point at it and I was wrong to prefer 3600.

Why 300 s is the better rule — and it corrects my reasoning, not just my number:

300 s ✅ chosen3600 s (my earlier pick)
Conditionno reply produced at alla claimed task whose worker stopped heartbeating
Detectsthe task is not progressingthe worker process is gone
Failsearly — a silent agent is caught in 5 minlate — an hour of nothing
Best forBrain following up on Heart — Young's actual requirementlong-running batch work

The distinction I got wrong: I argued 300 s measured "a different condition", and treated that as a reason to prefer 3600 s. But the different condition is the one Young asked for. His requirement is "brain Unit can follow up if agent got stuck or block" — and a Brain cannot follow up on a task it cannot tell is stuck. 300 s is the earlier signal, and earlier is what makes follow-up possible.

"Refine it when we have more data" is a rule, not a deferral — so it is a declared constant with its source cited, never a magic value:

SignalAction
tasks hitting stuck at 300 s that later completetoo short — raise it
tasks that stop and are not noticed for much longertoo long — lower it
a task class with a different natural durationa per-class override, not a global change

The other two numbers are references, not our rule:

NumberWhat it measuresOur use
60 sthe watchdog's sweep periodadopt as the check interval — 300 s is the threshold, 60 s is how often we look
3600 skanban's stale worker — the process is gonea second, coarser condition: the worker died vs the task went quiet. Both are recorded; 300 s is the primary

Both conditions are real and distinct: a task can have a live worker producing no reply, or a reply and a dead worker. Stage 3.3 records both, and 300 s is the one the follow-up loop fires on.


Ruling 4 — GO exhaustion rolls over to ZEN

Applied. When GO is exhausted, the request falls through to ZEN. This is not our invention — it is Opencode's own documented behaviour, and the ruling adopts it rather than fighting it.

"If you also have credits on your Zen balance, you can enable the Use balance option in the console. When enabled, Go will fall back to your Zen balance after you've reached your usage limits instead of blocking requests." — opencode.ai/docs/go

🔴 The answer to "how do we trace and track GO exhaustion?" — CORRECTED AND MEASURED

Young, 2026-10-10: "Currently can only check on the opencode console. Via opencode cli opencode stats --days 7."

Young's method works, and I found two more surfaces that also work. All three were probed on this host. The honest correction: it is not console-only.

#SurfaceProbeResult
1GO plan windowsGET https://opencode.ai/zen/go/v1/usageHTTP 200 — rolling/weekly/monthly
2Workspace budgetsGET https://opencode.ai/console/api/v1/budgets/membersHTTP 200 — limit, spent, exceeded, resets
3Local cost + tokensopencode stats --days 7 --cost --jsonworks — per-model cost, offline

All three are keyed by the same oc_sk_… key we already hold. No console login required.

Surface 1 — the GO plan windows

{ "usage": {
    "rolling": { "status": "ok", "percent": 0, "resetsAt": "2026-10-10T13:32:00.000Z" },
    "weekly":  { "status": "ok", "percent": 0, "resetsAt": "2026-10-12T00:00:00.000Z" },
    "monthly": { "status": "ok", "percent": 0, "resetsAt": "2026-11-09T02:42:52.000Z" } } }

This IS our window_state axis, supplied by the provider. status: "ok" | "rate-limited" maps to ok | blocked.

GET https://opencode.ai/console/api/v1/budgets/members
Authorization: Bearer <key>          # needs All permissions, not inference-only

Live response from our workspace:

youngframeworks@gmail.com: limit=$40.00 spent=$0.00 exceeded=False source=custom resets=2026-11-01

⚠️ CORRECTION — Young caught this, and I had it wrong. That $40.00 is a monthly spending CAP, not the ZEN credit balance.

ConceptWhat it isReadable by API?Failure
CREDITS — the ZEN PAYG floatprepaid balance, whole workspaceNO — console onlyHTTP 402 Insufficient account funds
BUDGETSa monthly spending cap, resets 1st of monthYES — this endpointHTTP 429
GO WINDOWSthe $10 subscription's limitsYES — /zen/go/v1/usagestatus: rate-limited

source: custom + resets_at: 2026-11-01 are budget semantics — the docs say "Budgets reset on the 1st of each month at 00:00 UTC." A credit balance does not reset monthly; it depletes. So this endpoint answers "what is the cap?", not "what is left in ZEN?"

The docs agree: "The Credits card on Overview shows the balance for owners and admins." The balance is console-only — the GitHub issue I first cited, then wrongly retracted, was right.

Fields: limit_micro_cents · spent_micro_cents · exceeded · resets_at · source. 100,000,000 microcents = $1.

Surface 3 — opencode stats — Young's method, and it does more than I knew

opencode stats --days 7 --cost --json

Measured: "cost": 19.489407278400066 over 7 days, with a full token breakdown and per-tool reliability. And per-model:

model                                 tokens       steps        cost
opencode-go/longcat-2.5-preview-f…      2.8b       55.7k       $0.00
opencode/space-bunny-free#default         2b       71.9k       $0.00
opencode-go/qwen3.8-flash#default     309.3m        7.5k      $11.17
opencode-go/deepseek-v4-flash#def…    263.5m        3.6k       $6.97

This is the per-model split our ledger needs, and it is available offline — source: /home/lab/.local/share/opencode/opencode.db (2.7 GB, local SQLite).

Useful flags: --days N · --year · --all · --models · --tools · --cost · --full · --project · --json.

The revised trap table — trap 1 is corrected

#TrapRevised finding
1ZEN's balance is NOT readable by API❌ CORRECTED — it IS, via the Budgets API. limit_micro_cents + spent_micro_cents give the $40 float directly. The earlier claim came from a GitHub issue (a feature request), not from a probe — and I repeated it without testing the console API. The inference-only key note was also wrong for our key: it returns 200
2percent is floored, disagrees with the dashboard ~1ptstands — read it as a floor
3resetsAt is computed client-side from resetInSecstands — a projection, not a fact
4The fallback is a CONSOLE SETTING, not a per-request flagstands — record the setting, don't infer the path
5No X-RateLimit-* headersstands — poll before the call, not after the 429

The lesson I am recording against myself — two errors, same root cause:

First I cited a GitHub issue as fact ("ZEN's balance is not readable"). Then, correcting that, I read the Budgets endpoint and reported its $40.00 as the ZEN credit balance. Both times I took a plausible-looking number and assigned it a meaning without checking the semantics.

The endpoint's own fields said "budget": its name is budgets, its source is custom, and its resets_at is the 1st of the month — and the docs say "Budgets reset on the 1st of each month." A credit balance does not reset monthly.

So the first instinct was right and the retraction was wrong. The honest position is the one supported by the docs and by eight 404 probes:

QuestionAnswer
GO window usage readable?YES — /zen/go/v1/usage
The monthly spending cap readable?YES — /console/api/v1/budgets/members
The ZEN credit balance readable?NO — console only

The rule: read the field names and the reset semantics before naming a number.limit ≠ balance; a monthly reset means a cap, not a float.

The three surfaces, and which to use for what

NeedUseWhy
before a paid call — is GO blocked?/zen/go/v1/usagecheapest, read-only, provider-authoritative, costs nothing
what is the monthly spending cap, and how much of it is used?/console/api/v1/budgets/membersthe cap, per member
what did we spend, per model?opencode stats --cost --jsonoffline, per-model, survives an outage
how much ZEN credit is left?the console Credits card — no APIcost_state: unknown in the ledger

The ledger reads three of the four, and says unknown for the fourth — which is the honest answer, not a failure.


What is now unblocked

StageWas blocked byNow
2the SDK-vs-plugin decisionunblocked — build on a2a-sdk 1.2.2
3the stuck numberunblocked — 3600 s, declared and refinable
5no ownerunblocked — Min, proof by Sol
6the GO/ZEN guardunblocked — rollover confirmed, and the trace surface is measured

Still open and genuinely needing Young: none of the four above. The remaining gates are OPEN-DECISIONS.md D1–D5 and the four operation gaps in what-we-havent-touched.md §6 — observability, backup/DR, onboarding, and .solos having no remote.


Not established

  • The usage endpoint was read, not load-tested. percent was 0 in all three windows at the time of measurement, so the rate-limited status has not been observed — it is read from the endpoint's own source.
  • The GO→ZEN rollover was not exercised. The docs state it and the console setting controls it; no call has been observed rolling over.
  • ZEN's endpoint was probed and 404s (/zen/v1/usage, /zen/usage) — the balance API does not exist, consistent with issue #44189.
  • x-opencode-session was tested and is required — without it the request is rejected MissingSessionID.
Copyright © 2026