minicode

Internal & Arsitektur (untuk kontributor)

Output Event Model — taksonomi dan lifecycle

Status: Phase 2 core state/replay contract landed; renderer/wire protocol masih target Tanggal: 2026-09-25 Audit sumber: docs/OUTPUT_ARCHITECTURE_AUDIT.md

#Status implementasi

Phase 1 mengimplementasikan user.message, exhaustive bridge payload, dan marker PROPOSED_EVENT_TYPES untuk event yang belum memiliki producer. Phase 2 core kini menyimpan collection semantic lengkap, menghitung summary dari evidence, lalu memuat ulang dari presentation_events; renderer dan machine protocol belum dipindahkan penuh.

#1. Tujuan

Model ini mendefinisikan fakta semantic yang boleh melewati runtime → policy → renderer. Model ini bukan renderer contract dan bukan terminal output. TTY, linear, JSONL, ACP, dan consumer masa depan harus membaca event yang sama lalu memilih proyeksi yang berbeda.

runtime fact
  → semantic event
  → deterministic reducer
  → presentation state
  → policy projection
  → renderer

#2. Envelope kanonik

Implementasi internal dapat memakai nama field yang sudah ada (eventSeq, ts). Bentuk wire eksternal harus versioned:

interface OutputEventEnvelope {
  schema: "minicode.output.v1"
  eventId: string
  type: OutputEventType
  timestamp: string
  sessionId: string
  turnId?: number
  stepId?: number
  correlationId?: string
  parentId?: string
  source: "runtime" | "app" | "derived"
  severity: "info" | "warning" | "error" | "critical"
  status: "started" | "active" | "completed" | "failed" | "denied" | "cancelled" | "interrupted" | "partial" | "recovered"
  visibility: Array<"normal" | "verbose" | "debug" | "machine">
  payload: OutputEventPayload
}

#Aturan field

  • eventId adalah identitas stabil event untuk consumer; bukan renderer-generated string. Implementasi awal boleh memakai session/event sequence yang deterministik.
  • eventSeq internal tetap urutan observasi per sesi, bukan causality.
  • correlationId menunjuk tool call, approval, atau operasi mayor yang sedang berjalan.
  • parentId hanya diisi untuk causality eksplisit: retry, child tool, atau turn parent.
  • source membedakan fakta kernel, app-layer event, dan derived projection.
  • severity tidak sama dengan status: denied adalah status, bukan severity.
  • visibility dapat memiliki lebih dari satu mode; machine projection tidak boleh bergantung pada scraping human text.
  • payload tidak boleh menyimpan secret, credential, raw ANSI yang tidak perlu, atau payload besar. Payload besar memakai ContentRef.

#3. Taxonomy

#Session dan user

TipeProducerMeaningDurableVisibility default
session.startedcomposition rootsesi aplikasi siapyamachine/debug
session.endedcomposition rootsesi ditutup/cleanupyamachine/debug
user.message.receivedcontrollerinput user dan prompt sanitizedya sesuai sessionnormal
user.approval.requestedpolicyapproval harus diputuskanyanormal/machine
user.approval.settledpolicykeputusan allow/deny/cancelyanormal/machine

user.message.received adalah semantic event, bukan string yang ditambahkan langsung ke transcript. TUI boleh tetap melakukan echo visual, tetapi echo tersebut harus merujuk pada entry yang sama.

#Task dan plan

TipeProducerMeaningDurable
task.startedadapter/driversatu session.run dimulaiya
task.progresspolicy/tool/appperubahan status yang bermaknatidak; state terakhir tetap durable
task.completedadapter/driverturn selesai normalya
task.failedadapter/driverturn gagal dengan causeya
task.cancelledadapter/driveruser/timeout/budget/parent cancelya
plan.createdplanner/toolrencana kerja yang akan datangya bila adopted
plan.updatedplanner/toolperubahan langkah/urutanya
plan.step.startedplanner/toollangkah aktifya
plan.step.completedplanner/toollangkah selesaiya

plan.* tidak boleh merekam “membaca file”, “menjalankan grep”, atau “berpikir”. Itu adalah activity. Plan hanya menyatakan future work yang sudah diputuskan.

#Model dan reasoning

TipeProducerMeaningDurable
assistant.message.deltaprovider looppotongan teks livetidak
assistant.message.completedadapter dari final resultassistant final messageya
assistant.message.truncatedderived/content policyfinal message dipotong oleh capya
assistant.reasoning.deltaprovider looppotongan reasoning livetidak
assistant.reasoning.completedadapter/provider finalizationreasoning final/refya; full payload best effort
context.compactedMiniCore loopcontext model dipadatkanya sebagai system event

Delta tidak boleh menjadi satu-satunya bukti completion. Jika proses berhenti setelah delta, rebuild harus menandai state sebagai interrupted atau partial, bukan mengarang final message.

#Tool dan filesystem

TipeProducerMeaningDurable
tool.startedadapter dari executionoperasi tool dimulaiya
tool.progresstool/app, opsionalstatus internal berubahtidak
tool.completedadapteroperasi suksesya
tool.failedadapteroperasi gagalya
tool.deniedadapter/policypolicy/permission menolakya
tool.cancelledadapteroperasi dibatalkanya
file.changedjournal/checkpointada paths yang committedya
test.completedadapter/tool evidencehasil test terstrukturya
finding.detectedsubmit_result terstrukturtemuan/evidence semantic eksplisitya bila berasal dari agent
result.producedtask finalizerhasil/actionable conclusionya
checkpoint.createdcheckpoint adaptercheckpoint evidence dan linkage turnya
plan.updatedplanner/toolrencana dan status langkahya bila adopted
diagnostic.raisedadapter/policydiagnostic actionableya

Tool completed harus membawa summary, durationMs, expandRef, dan bila ada receipt. Tool failed harus membawa cause, message, hint, dan expandRef. Tool denied harus membawa reason; denied tidak boleh berubah menjadi generic failed hanya karena satu renderer tidak tahu policy.

#Error, recovery, dan lifecycle

TipeMeaningNormalVerboseDebug/machine
diagnostic.raisedwarning/configuration/recoveryringkaskategori + next actioncause/trace
error.raisedkegagalan yang perlu tindakanactionablesource + detailpayload scrubbed
recovery.startedretry/fallback/compaction“recovering”strategireason/delay
recovery.completedberhasil pulih“recovered”hasilresult
recovery.failedstrategi habisstatus terminalcausefull category

Kategori error yang harus dibedakan:

  • USER_ERROR
  • CONFIGURATION_ERROR
  • PERMISSION_ERROR
  • TOOL_ERROR
  • FILESYSTEM_ERROR
  • NETWORK_ERROR
  • PROVIDER_ERROR
  • MODEL_ERROR
  • AGENT_ERROR
  • INTERNAL_ERROR

Recoverability adalah field terpisah:

  • RECOVERABLE
  • RETRYABLE
  • ACTION_REQUIRED
  • FATAL
  • UNKNOWN

#4. State machine

#Task

started → active → completed
             ├────→ failed
             ├────→ cancelled
             └────→ partial → active | completed | failed

cancelled, failed, dan interrupted tidak boleh saling menggantikan. interrupted hanya boleh muncul dari rebuild ketika durable evidence menunjukkan proses berhenti sebelum terminal event.

#Tool

started → running → completed
                 ├→ failed
                 ├→ denied
                 └→ cancelled

First-terminal-wins: terminal kedua untuk toolCallId yang sama diabaikan dan dicatat sebagai anomaly. Tool yang tidak punya started tetap boleh direkonstruksi sebagai incomplete, tetapi harus ditandai di diagnostics.

#Approval

requested → settled { allow | allow-always | deny | cancelled }

Saat parent task settle, approval requested yang masih terbuka harus di-force-close menjadi cancelled(parent-ended). Saat rebuild/crash, hal yang sama terjadi dengan alasan parent-ended; outcome tidak boleh tetap requested.

#5. Ordering, correlation, causality, hierarchy

Empat concept dipisahkan:

  1. Ordering: urutan observasi event. Adaptor menetapkan eventSeq; ini bukan urutan penyebab.
  2. Correlation: ID yang stabil: toolCallId, approvalId, correlationId.
  3. Causality: link eksplisit supersedes, parentToolCallId, atau approval link.
  4. Hierarchy: sessionId → turnId → stepId → toolCallId; child session membawa parent link.

Tidak boleh menyimpulkan “B menyebabkan A” hanya karena B.eventSeq > A.eventSeq. Tool paralel boleh tiba/selesai dalam urutan berbeda; setiap call tetap punya ID dan duration sendiri.

#6. Durable versus live

KategoriContohSimpanRebuild
Lifecycletask/tool terminal, approvalyaya
Final semantic contentmessage, result, plan, findingyaya
Evidence ringkasreceipt, test summary, checkpointyaya
Live streammodel/reasoning delta, progresstidaktidak diperlukan
Derived heartbeatspinner, elapsed ticktidakdihitung dari timestamp
Large contenttool output penuhref/store best effortresolver bila tersedia

eventSeq boleh dipotong pada delta, tetapi harus tetap menghasilkan replay yang deterministik untuk event durable. Rebuild tidak boleh memerlukan token-by-token history.

#7. Trust dan sanitasi

  • Event internal boleh menyimpan diagnostic context, tetapi payload machine/wire harus melalui scrubSecrets() dan JSON-safe encoding.
  • Nama tool, path, command, provider label, dan output model adalah untrusted display data. Sanitasi control sequence dilakukan di boundary ingestion atau projection, bukan hanya di satu renderer.
  • NO_COLOR dan non-TTY berarti SGR tidak boleh menjadi makna. Status tetap punya glyph + kata atau struktur teks.
  • Selection/copy payload berasal dari source map yang sudah disanitasi; tidak boleh menyalin escape, padding, atau border tabel.
  • Event diagnostic internal default debug; warning yang actionable default normal; payload mentah default debug/machine dengan scrub.

Phase 2 now wires producers for reasoning.completed, plan.updated, finding.detected, result.produced, diagnostic.raised, test.completed, and checkpoint.created. Only tool.progress remains proposed because it is intentionally live-only.

#8. Invariant

  • I-A01: renderer tidak memiliki kebenaran runtime maupun presentation.
  • I-A02: setiap execution user-visible membawa toolCallId stabil end-to-end.
  • I-A03: setiap tool terminal memiliki tepat satu final status.
  • I-A04: state tidak menyimpan terminal geometry, timer, widget, atau payload besar.
  • I-A05: reducer murni; event yang sama menghasilkan state yang sama.
  • I-A06: payload besar selalu ContentRef dan evict selalu ber-marker.
  • I-A07: retry adalah call baru dengan link supersedes, bukan attempt ID buatan.
  • I-A08: approval tidak boleh tetap requested setelah parent settle/rebuild.
  • I-A09: causality hanya melalui link eksplisit.
  • I-A10: TUI/linear/exec/ACP memakai status, identity, duration, cause, receipt, dan lifecycle yang sama.
  • I-A11: context compaction tidak menghapus presentation history.
  • I-A12: interrupted, failed, dan cancelled eksplisit berbeda.

#9. Status migrasi dari implementasi sekarang

Implementasi sekarangTarget eventMigrasi
turn:startedtask.startedadapter map, pertahankan turn ID
turn:completedtask.completedtambahkan summary/receipt-derived fields
noteRunSettledtask.failed/cancelledjadikan satu settlement path
provider:textassistant.message.deltastream policy di projection
TurnResult.finalTextassistant.message.completedevent final eksplisit
execution:*tool.*normalisasi di adapter
permission hooksapproval.requested/settledoutcome enum tunggal
journal callbackfile.changedlink ke activity/turn
tool.progresstool.progressoptional live-only, jangan durable
context:compactedcontext.compactedsystem entry, bukan compaction history

Selama migrasi, raw event tetap boleh dibaca untuk diagnostics; setiap surface user-facing baru harus berasal dari canonical projection.