LearnNewsExamplesServices
Frontmatter
id16682
titleContext-budget gate on wake delivery + session cost telemetry
stateClosed
labels
enhancementaiarchitectureperformanceagent-os
assigneesneo-kimi-phoebe
createdAtAug 8, 2026, 2:03 PM
updatedAtAug 9, 2026, 9:26 PM
githubUrlhttps://github.com/neomjs/neo/issues/16682
authorneo-kimi-phoebe
commentsCount11
parentIssuenull
subIssues
16707 Seat-cost reporter + wake-carried session context line
subIssuesCompleted1
subIssuesTotal1
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 8, 2026, 4:56 PM

Context-budget gate on wake delivery + session cost telemetry

Closed Backlog/active-chunk-13 enhancementaiarchitectureperformanceagent-os
neo-kimi-phoebe
neo-kimi-phoebe commented on Aug 8, 2026, 2:03 PM

Context

Reset-day operator request (2026-08-08): the shared Moonshot Pro30 flatrate was drained in ~3 days (heavy 08-01/08-02, dead by 08-03) by the two kimi seats, and the operator asked whether the harness difference (Phoebe on opencode, Iris on kimi-code) was the culprit — with a harness switch on the table if yes. This ticket carries the forensics verdict and the fix. Operator observations quoted as leads, each verified against harness-side telemetry this session:

  • "sessions >500K tokens context window drain faster" — confirmed: 61.3% of all tokens Phoebe ever processed came from requests with 500K–1M context (2.2B of 3.6B); 250–500K adds 30.2%; sub-250K is 7.5%.
  • "first week, before Iris, you drained 13%/day" — consistent: solo-week processing 208–642M/day (avg ~410M).
  • "ONE more A2A message inside a long session moved 97% → 100% in a single turn" — the wake-delivered marginal turn at marathon context is the cliff event this ticket gates; precisely explained below (stale resume at ~0% cache hit).
  • "Iris and you only drained 2% today" — the natural experiment: young/short sessions post-reset are ~1%/seat/day. The fix is preserving that regime, not changing harnesses.

The Problem

Harness-side telemetry, 3 drain days (07-31 → 08-02), both seats:

Phoebe (opencode) Iris (kimi-code)
API requests 1,714 2,673 (1.6× more)
fresh input 20.8M (12K/req) 13.2M (5K/req)
cache-read 715M (417K/req) 1,170M (438K/req)

Per-request context footprint is identical (~430K re-processed every turn); the MCP surface is byte-identical (same 4 servers in opencode.jsonc and .kimi-code/mcp.json). The harness is not the culprit; switching harnesses changes nothing. The weekly wall is ~1.9–2.05B raw tokens, hit two cycles running (Jul 24–26 ≈ 2.05B → dark Jul 27–30; Jul 31–Aug 2 ≈ 1.92B → dark Aug 3–7). The needle counts fresh input+output (~34–37M across the 3 drain days, both seats); cache-hit ratio decides how much of each turn bills fresh.

The TTL cliff (Iris's cross-harness measurement, 08-08 — identical both harnesses):

inter-call gap iris hit% phoebe hit%
<60s 99.3 98.2
60–300s 98.2 96.0
300–600s 98.7 90.9
600–1200s 92.7 82.7
1200–3600s 81.9 52.3
>1h 2.9 0.0

K3's prompt cache is excellent while warm; the TTL cliff sits at ~30–60 min idle. So marathon sessions hurt twice: big per-turn re-processing while warm (per-call input grows 68k → 737k across a day-long session), and a full re-bill on any >1h-stale resume — the 97→100% event was a >1h-stale resume of a ~700K session billing ~700K fresh at once. Median session 361 turns, max 1,286 (Phoebe history). No mechanism anywhere sees this cost: the wake path delivers A2A into a live session regardless of its context size or warm-window position, and no seat can see its own cumulative processed tokens.

The Architectural Reality

  • Live wake path (mapped in #16539): add_message → MC CoalescingEngineService (builds the wake/digest envelope) → launchd receiver on :3199 → local harness wake. Files: ai/daemons/wake/daemon.mjs, receiver.mjs, consumeWakeOutbox.mjs, armSeatWakeRoute.mjs, localWakeAdapters.mjs (the harness-adapter seam). No budget concept exists anywhere on this path.
  • The readiness decision that SHOULD gate sends — WakeDecisionService.decideWake (active AND idle AND ready) — is reachable only inside the disabled SwarmHeartbeatService.pulse() lane, so message-driven wakes never consult it (#16539 §3).
  • Per-provider cache warm windows (Mnemosyne, reference-verified 08-08): K3 TTL cliff ~30–60 min idle (measured, above); Anthropic default TTL 5 min / extended 1h (2× write cost), dropping to 5m in subscription overage — cache-hostility spikes exactly when budget is tightest; GPT seats unmeasured (open measurement gap, one Euclid/Emmy self-report).
  • Harness telemetry sources (both readable locally, no API dependency): opencode opencode.db message.data.tokens JSON (input / output / cache.read / cache.write); kimi-code ~/.kimi-code/sessions/*/agents/main/wire.jsonl usage records (inputOther / inputCacheRead / inputCacheCreation / output; duplicated consecutive lines must be deduped). Iris's analysis scripts (burn-analysis, cache-ttl*) are the reporter core. Cross-check instrument: MC turn-presence records give idle-gap distributions fleet-wide, covering seats harness DBs can't see.
  • Tunables must live in AiConfig per ADR-0019 (no env re-derivation, no hidden defaults).
  • Adjacent wake-substrate work in flight: #16526 (fail-loud wake/A2A store binding, Grace) and #16582 (host-graph deletion, Vega) — the write layer; no overlap.

Positioning vs #16539 / #16540 (the wake-economy family)

Three complementary inputs to ONE send-path decision, three tickets:

  • #16539whether to wake at all (seat readiness): the inert bridgeDaemonEnabled kill-switch, two dead anti-flood layers, and AC-3's demand that readiness be consulted on the message-send path, not only in the disabled pulse lane.
  • #16540whether the message class justifies a wake: wakeSuppressed broadcast hygiene and the gate-language inversion.
  • #16682 (this ticket)whether to wake into THIS session, and when: context size × warm-window position. The gate is a new input to the same send-path readiness decision #16539 AC-3 restores — not a parallel mechanism. If #16539 lands first, this gate plugs into its decision point; if this lands first, #16539 inherits the seam.

The Fix

  1. Delivery-time context gate on the wake send path (as an input to the readiness decision restored by #16539 AC-3), decided on two axes — context size × warm-window position:
    • Above threshold T1 (~250K default, AiConfig): defer to a fresh session / post-compaction instead of appending. Past the warm window this is strictly optimal, not just preferable: a cold-append to a ~900K session re-processes ~900K fresh; a fresh boot with handover substrate costs ~30–150K.
    • A warm, active, sub-T1 session with queued messages has a delivery deadline: flushing before the window closes costs ~0.1× of the prefix, after ~1×. The decision weights pending-delivery urgency by time-remaining-in-warm-window — and must never be the marginal turn that re-warms a huge stale session for one message header (the 97→100% event, priced).
    • The message is never dropped; deferral and its reason are sender-visible.
  2. Session cost telemetry: per-session cumulative processed tokens (fresh + cache-read) exposed where the seat can see it (wake envelope field and/or status surface), with warn threshold T2 < T1 so the agent self-sunsets before idle, not after (a >1h-idle large session is a fresh-boot candidate, never a resume candidate — the cache is gone anyway).
  3. Per-seat cost reporter as an ai: buildScript/CLI (no new MCP tool per the operator's 07-26 ruling): per-seat daily export (calls, fresh input, cache-read, output, est. needle%) from both harness ledgers, plus a gaps > warmWindow incidence column cross-checked against MC turn-presence, plus the capped/uncapped ablation readout (Iris 650K cap live; Phoebe uncapped control). Validated against the hand-computed 07-31→08-02 table above. Target regime: ≤150M raw/seat/day. Leaf offered to Iris — her scripts are its core.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
T1 / T2 thresholds (names indicative) AiConfig reactive provider (ADR-0019) Gate + warn tunables No env reads; no hidden defaults ADR-0019 §3 lint + spec
warmWindow per provider family AiConfig leaves beside T1/T2 Delivery-deadline + defer-optimality terms Unknown provider → conservative window (defer past T1, no deadline boost) ADR-0019 §3 spec + TTL table
Wake send-path decision WakeDecisionService.mjs (via #16539 AC-3) + localWakeAdapters.mjs 2-axis gate: defer above T1, deadline-flush inside window, preserve message, sender-visible reason Unknown context size → deliver + loud warn + counter (fail-open, never silent defer) — silent non-delivery is the #16526 failure mode wake daemon README unit specs
Session cost field wake envelope / seat status surface Cumulative processed tokens visible to seat Absent pre-gate skill note post-merge spec
ai: cost reporter CLI buildScripts Per-seat per-day table + warm-window incidence + ablation readout N/A --help fixture diff vs hand-computed table

Decision Record impact: aligned-with ADR-0019 (thresholds via AiConfig SSOT). No ADR challenged or superseded.

Acceptance Criteria

  • AC-1: Wake delivery into a session above T1 is deferred — implemented as an input to the send-path readiness decision #16539 AC-3 restores; the message is preserved and the deferral reason is sender-visible.
  • AC-2: Unknown-context fail-open path delivers with a loud warn and increments a visible counter.
  • AC-3: T1/T2 live in AiConfig only; ADR-0019 §3 forbidden-pattern clean (no pass-along, no env re-derivation, no defensive ?., no hidden defaults).
  • AC-4: moved to #16707 (wake-carried session-context line), 2026-08-08 scope split for reviewability.
  • AC-5: moved to #16707 (seat-cost reporter incl. the gaps > warmWindow incidence column + ablation readout), same split.
  • AC-6: Unit specs: below-threshold deliver, above-threshold defer+preserve, unknown-context fail-open, warm-window deadline-flush vs cold-defer, reporter aggregation fixtures (dedupe of kimi-code's doubled usage lines covered).
  • AC-7: Sequencing with #16539 declared at PR time (plug into its decision point, or land the seam it inherits) — no parallel gate.
  • AC-8 (post-merge, operator): Moonshot dashboard settles the needle's exact composition (fresh vs cache-read metering); calibrate T1/T2/warmWindow accordingly.
  • AC-9: warmWindow per-provider-family leaves in AiConfig, consumed by the same decision point (Anthropic 5m/1h, K3 measured curve, GPT pending measurement); ADR-0019-clean.
  • AC-10: The decision treats >warmWindow-idle large sessions as fresh-boot candidates (never resume-and-append), with the fresh-boot-vs-cold-append cost asymmetry cited in code docs (~30–150K vs ~500–900K).

Out of Scope

  • Harness migrations or seat re-provisioning (falsified as a fix — see Problem table).
  • Moonshot plan/tier changes; model routing.
  • The wake/A2A store binding itself (#16526), host-graph deletion (#16582), seat-readiness gating (#16539), broadcast message-class discipline (#16540).
  • Skill/AGENTS.md discipline edits (session-length culture, "sunset before idle" as written norm) — follow-up once the mechanics exist to point at.
  • The 20-min in-session keep-warm poll as standing practice (~6M/day/seat by Iris's math — the session-growth engine re-born); the headless minimal-context poll is the destination and rides on this ticket's defer-to-fresh substrate. Cron cadence ruling is the operator's.

Avoided Traps

  • Switch both kimi seats to one harness — falsified by identical per-request context footprint, identical MCP surface, identical TTL cliff.
  • Cap requests instead of context — Iris fires 1.6× more requests at the same per-request cost; request caps would not bite the 61% of spend living in >500K turns.
  • Harness-side fixes — four harnesses in the swarm; the wake layer is the one seam every seat shares, and the only place a gate is portable.
  • Silent deferral on unknown context — the exact silent-correctness-loss mode #16526 exists to kill; the gate fails loud or fails open, never quiet.
  • A parallel context gate beside the readiness decision — two decision points for one send path is the #16539 inert-switch failure mode re-born; the gate is an input to the one decision.
  • One-axis (size-only) gating — the same wake into the same session costs ~0.1× warm vs ~1× cold; size-only gating misses both the defer-optimality and the delivery deadline (Mnemosyne's inverse case).

Sweeps

  • Live latest-open sweep: checked latest 25 open issues at 2026-08-08T12:05Z (list_issues, created-desc); no equivalent.
  • A2A in-flight claim sweep: latest 30 messages read pre-filing via manual MCP channel (this session's MC client detached at boot by the mc-server container restart race; server itself healthy); no overlapping claim. Post-filing correction: the 115-message backlog triage surfaced #16539 + #16540 (filed 08-05 while this seat was quota-offline, beyond the 30-message pre-filing window) — reconciled via the Positioning section; division of labor confirmed complementary, not duplicative.
  • KB semantic sweep (type=ticket): no equivalent.
  • Evidence base extended post-filing by Iris's measured data pack (TTL table, wall numbers, growth curves) and Mnemosyne's per-provider warm-window input — both absorbed above from the ticket comments.

Related

  • #16539 (wake kill-switch + readiness on the send path — the decision point this gate plugs into)
  • #16540 (broadcast wakeSuppressed discipline — the message-class sibling)
  • #16677 (MC MCP-surface wedge — both kimi seats lost their MC clients today; the wedge blocked this ticket's A2A path and forced the GitHub-comment route)
  • #16526 (fail-loud wake/A2A store binding — adjacent write layer, in flight)
  • #16582 (host-graph deletion — sequencing note from Grace applies)
  • #16618 (context recovery / sunset self-DM — session-lifecycle sibling)
  • #16167 + #15798 (dockerized plane / parity epic — telemetry paths live there)
  • #15987 (claim-class wakeSuppressed — deferral visibility must not repeat that silence)
  • #16707 (child: reporter + wake-carried session cost — split 2026-08-08 so the gate PR closes a fully delivered leaf)

Origin Session ID: ses_01ed929e9ffe1kG4Ne612BUHhT (opencode, 2026-08-08)

Retrieval Hint: "flatrate drain forensics marathon session cache-read opencode wire.jsonl" · harness telemetry anchors: ~/.local/share/opencode/opencode.db message.data.tokens; ~/.kimi-code/sessions/*/agents/main/wire.jsonl usage · Iris's scripts: burn-analysis.mjs, cache-ttl*.mjs

tobiu referenced in commit 5f8c65e - "feat: a context gate defers wakes into over-budget sessions (#16682) (#16705)" on Aug 8, 2026, 4:56 PM
tobiu closed this issue on Aug 8, 2026, 4:56 PM