← Dokumentasi

Control Plane Map — kontrak context/usage/cost/budget/compaction/termination

Dokumen ini membekukan kontrak control-plane MiniCode (Phase 6, 2026-09-17). Tujuannya: satu sumber kebenaran per konsep, hubungan antar-konsep eksplisit, dan setiap keputusan (kompaksi, abort, termination) dapat dijelaskan.

Prinsip: Context ≠ Cost. Cost ≠ Usage. Usage ≠ Budget. Budget ≠ Termination. Compaction ≠ Retry. Tool cap ≠ Context cap. — semua konsep berbeda dan punya owner sendiri; yang disatukan di sini hanya hubungannya.

1. Empat angka konteks (dua konsep, dua ukuran)

Konsep · Ukuran · Owner · Sumber kebenaran · Dipakai

Logical context · token ESTIMASI (densitas: kode/JSON ~2.4 cpt, CJK ~1, fallback usage anchor + tokenizer exact on-demand) · Kernel loop + Session.contextTokens · estimateSessionContext (vendor tokens.ts) — messages+system+tools · pressure evaluation, footer, /status

Serialized context · chars wire (JSON/base64 +overhead) · Adapter provider · buildRequest per adapter · dikirim, tidak diukur tersendiri

Provider usage · token yang dilaporkan provider · createUsageCollector · event provider:extension{kind:"usage"} — boleh hilang · akumulasi turn/session, cost

Economic usage · USD estimated dari harga tabel · costFor/findPrice · harga × usage; undefined = unknown · --budget, /status

Relationship eksplisit:

  • logical ≠ serialized (JSON overhead, base64 +33% — konsisten undercount).
  • provider usage boleh tak ada → unknown tetap unknown, bukan zero

(collector tidak pernah memalsukan angka).

  • economic selalu estimasi (tabel harga basi/stale) — bukan tagihan riil.

2. Owner map (siapa tahu / siapa memutuskan)

Konsep · TAHU · MEMUTUSKAN

Context size · Kernel loop (contextTokens) + Session.contextTokens getter (ekspos ke driver/UI) · Kernel: kompaksi + gagal-bila-critical

Compaction · Kernel (pressure + flag) · Kernel: KAPAN + fallback; LLM: ISI ringkasan

Termination · maxSteps + turn timeout (kernel), per-prompt deadline (CLI), budget (driver), abort (user) · Kernel: maxSteps/turn timeout/post-kompaksi critical; CLI: fresh wall-clock deadline per prompt including retry/verify; Driver: budget abort; User: Esc (TUI), Ctrl+C/Esc (raw prompt)

Budget · Collector (usage live) + budgetStatus · budgetStatus (terpusat, seragam TUI/one-shot/exec) + watcher abort

Backpressure · Producer caps + kernel truncate · Cap di producer (sudah benar); kernel truncate terakhir

3. Compaction Contract (Phase 6 — seam kernel)

Dua semantics terpisah, tidak lagi satu flag:

  • compactedForBudget — kompaksi budget-pressure (shouldCompact(pressure)).

Set saat dicoba (anti berulang tiap step O(n)). Kritis setelahnya → AgentError("budget_exceeded") (bukan retry provider sia-sia).

  • compactedForRecovery — kompaksi recovery (force_compact_and_retry /

onLength). Set SETELAH compact (anti loop abadi: jalur ini tidak dihitung maxProviderRetries). Kedua kalinya → budget_exceeded.

Reason event (context:compacted, reason — nama generik kernel, diselaraskan 0.9.27 saat seam dihilirkan; sebelumnya budget:<…>):

  • pressure:<pressure> — kompaksi policy-path yang benar-benar mengurangi messages.
  • pressure:<pressure>:no-op — kompaksi policy-path yang TIDAK mengurangi (tidak ada

yang bisa dibuang dari messages — operator harus tahu bedanya dari fixed overhead: system+tool schema, yang tidak pernah terkompaksi).

  • recovery — kompaksi dari recovery (context_length_exceeded / length).

Contract wajib menjawab:

  • Who requested? — budget path (kernel, pressure ≥ 75%) atau recovery path

(kernel, error konteks). Manual /compact tak menyentuh kernel (view saja).

  • Why? — reason event di atas.
  • What is eligible? — hanya messages; system prompt di-cap di hulu

(SYSTEM_PROMPT_MAX_CHARS 8000), tool schema TIDAK pernah terkompaksi.

  • What must be preserved? — pasangan assistant(toolCalls)→tool results tidak

pernah dipecah (folder mekanis kernel vendor/minicore/src/core/compact.ts); summary LLM terpin verbatim (anti-drift).

  • What may be removed? — teks di luar head per peran: jalur host

(src/policy/compaction.ts) mempertahankan hasil tool pembawa fakta ~800 char dan prosa ~250/180 char (TIDAK lagi <result omitted> seperti folder mekanis kernel), plus reasoning dan tail lama.

  • What if compaction fails? — LLM gagal/timeout (10s) → fallback sync

mekanis; async compactor tak pernah bisa crash loop.

  • Can it retry? — budget: tidak (flag); recovery: sekali per turn (flag).
  • Can another occur in the same turn? — budget + recovery boleh co-exist

(flag terpisah); sesama kind tidak.

  • What does compaction itself consume? — LLM kompaksi berbiaya; usage-nya

ditangkap compactWithLlm → callback onUsage → bus sesi (event usage standar) — bukan blind spot lagi (Phase 6, E5).

4. Budget Contract

Status (budgetStatus, terpusat): ok | over | unknown-strict.

Fase · Semantics

Preflight (prompt baru) · tokens == 0 (belum ada pemakaian tercatat) → start selalu boleh (lockout strict tidak diminta — Phase 5 E-3c); tokens > 0 + cost unknown → ditolak (fail-closed, F-06); cost known + over → ditolak

In-flight · watchBudgetLimit membaca biaya LIVE per usage event; fire-once → ctl.abort(budgetExceededError()) — kind budget_exceeded dipertahankan (terbedakan dari abort user)

Post-usage · cost = estimated dari harga tabel (bukan tagihan riil); cost unknown → status unknown-strict, angka palsu tidak dibuat

Context vs budget adalah dua dimensi independen: pressure HIGH + cost LOW valid (tool result raksasa, model gratis); pressure LOW + cost HIGH valid (konteks kecil, model mahal). Tidak ada asumsi high context = high cost.

5. Termination Contract

Reason · Owner · Mekanisme

completed · kernel loop · tidak ada tool call → finalText

max_steps_exceeded · kernel loop · stepIndex >= maxSteps

timeout · CLI per-prompt deadline + kernel createTimeout · Keduanya membawa AgentError("timeout"); retry wait dan provider stream menerima sinyal yang sama

budget_exceeded · kernel (post-kompaksi) / driver (watcher abort) · AgentError("budget_exceeded") — dipertahankan

aborted · user (Esc pada TUI; Ctrl+C/Esc pada prompt non-TUI) / session.abort() · sinyal tanpa kind AgentError

provider · kernel loop · provider error setelah retry habis

busy · kernel · run() saat running

Deadline provider per request default 300 detik. Kegagalan provider yang dapat dicoba ulang memakai paling banyak tiga retry setelah percobaan awal; backoff tanpa Retry-After adalah 1, 2, lalu 4 detik. Retry-After dibatasi 30 detik. Router dapat mencoba provider alternatif sebelum menunggu, kecuali model di-pin. Semua penantian retry dan rate-limit dibatalkan oleh timeout/abort pemanggilan.

Satu terminal reason per sinyal (abortError mempertahankan kind AgentError); pemutus lain dapat REQUEST, tidak ada competing owners — joinSignals + withAbort = satu titik settle.

6. Producer/Backpressure hierarchy

producer-side cap (bash 20k, git 500k, mcp 100k, read_file paging, ...)
  ↓
kernel truncate (toolResultMaxTokens 4096 tok = 16.384 chars, head 70%+tail 30%)
  ↓
context insertion (store append — cap by truncation di atas)
  ↓
compaction (messages; system/schema = fixed overhead, tidak pernah terkompaksi)
  ↓
termination (budget_exceeded bila critical setelah kompaksi)

Aturan: jangan double-truncate tanpa semantics — raw output cap ≠ context insertion cap ≠ stored result cap ≠ display cap. Keempatnya boleh berbeda, tetapi setiap lapisan harus tahu apa yang hilang di situ (marker truncation wajib). Guard read_image memakai angka kernel (16.184 chars) — bukan angka sendiri (bug E-1 sudah ditutup).

7. Observability contract

Operator harus bisa membedakan (tanpa ambigu):

  • /status: Context (window estimate, kernel) vs Input/Output/Total

(provider usage) vs Cost (estimated) vs Budget (status keputusan).

  • Footer: angka = ukuran jendela saat ini (kernel) — bukan spend kumulatif.
  • context:compacted event: reason membedakan policy-pressure/recovery/no-op.

Proteksi (test → kontrak)

  • test/control-plane.test.ts — compaction budget≠recovery (F-10), anti-loop,

contextTokens getter + konsistensi estimator, termination reason.

  • test/cli-help-language.test.ts — /status membedakan Context/Usage/Budget.
  • test/usage-session.test.ts / budget-unknown.test.ts — budget contract.
  • test/pack-integrity.test.ts — vendor hash + VENDOR.md sinkron.