@vincemakes/kiso-core 0.1.29 → 0.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Producers are declared on tools (`delivers`, tools/tool.ts); the verdict
12
12
  * counts producer calls that completed (non-error results), against a
13
- * delivery claim in the text. The canonical lie — "已生成文档" with zero
13
+ * delivery claim in the text. The canonical lie — "generated-document" with zero
14
14
  * producer calls and a clean completed terminal — fails here.
15
15
  *
16
16
  * In M3.5 the emission side (artifact URLs extracted from results) joins;
@@ -10,13 +10,13 @@
10
10
  *
11
11
  * Producers are declared on tools (`delivers`, tools/tool.ts); the verdict
12
12
  * counts producer calls that completed (non-error results), against a
13
- * delivery claim in the text. The canonical lie — "已生成文档" with zero
13
+ * delivery claim in the text. The canonical lie — "generated-document" with zero
14
14
  * producer calls and a clean completed terminal — fails here.
15
15
  *
16
16
  * In M3.5 the emission side (artifact URLs extracted from results) joins;
17
17
  * today a completed producer IS the emission.
18
18
  */
19
- const CLAIM_PATTERN = /交付|已生成|已创建|已完成|completed|delivered|done/i;
19
+ const CLAIM_PATTERN = /created|completed|delivered|done/i;
20
20
  export function analyzeDelivery(events, config) {
21
21
  const producerCalls = [];
22
22
  const completedProducers = [];
@@ -18,7 +18,7 @@
18
18
  * started, no terminal event yet → "uncertain" (interrupted: human)
19
19
  * succeeded → "succeeded" (confirmed, never re-run)
20
20
  * failed (any) → "failed" (a complete receipt IS
21
- * the outcome — 裁决 #12 / ADR-0038;
21
+ * the outcome — ruling #12 / ADR-0038;
22
22
  * safeToRetry stays on the event for
23
23
  * history, it no longer feeds status)
24
24
  * resolved "rerun" → "rerun" (human cleared it)
@@ -18,7 +18,7 @@
18
18
  * started, no terminal event yet → "uncertain" (interrupted: human)
19
19
  * succeeded → "succeeded" (confirmed, never re-run)
20
20
  * failed (any) → "failed" (a complete receipt IS
21
- * the outcome — 裁决 #12 / ADR-0038;
21
+ * the outcome — ruling #12 / ADR-0038;
22
22
  * safeToRetry stays on the event for
23
23
  * history, it no longer feeds status)
24
24
  * resolved "rerun" → "rerun" (human cleared it)
@@ -50,7 +50,7 @@ export function executionLedger(events) {
50
50
  if (prior) {
51
51
  ledger.set(ev.executionId, {
52
52
  ...prior,
53
- // 裁决 #12 (ADR-0038): a complete receipt IS the outcome —
53
+ // ruling #12 (ADR-0038): a complete receipt IS the outcome —
54
54
  // failed is "failed", never "uncertain"; uncertainty
55
55
  // belongs to the crash window alone (started, no receipt).
56
56
  status: "failed",
@@ -17,13 +17,13 @@
17
17
  * assemble (onUserMessage / onPreLlm)
18
18
  * → adapter.stream(): events yielded straight through; every validated
19
19
  * and policy-allowed tool call LAUNCHES its execution immediately
20
- * (流中执行) — the executions run concurrently under a window of 4
20
+ * (streaming execution) — the executions run concurrently under a window of 4
21
21
  * (0.1.26, ADR-0024 Amd), their events queued and drained between
22
22
  * stream events (completion order; the projection re-orders the
23
- * results by call order — 字节纪律)
23
+ * results by call order — the byte discipline)
24
24
  * → the turn settles: the launched executions finish (receipts land
25
25
  * before any terminal), the ask-gated successors follow the human's
26
- * verdict (保守序)
26
+ * verdict (the conservative order)
27
27
  * no tool calls / maxTurns / abort / max_tokens → terminal event, return
28
28
  *
29
29
  * Retry lives HERE and only here (ADR-0005): a retryable StructuredError
@@ -71,7 +71,7 @@ export interface LoopConfig {
71
71
  readonly thresholdTokens: number;
72
72
  };
73
73
  /**
74
- * C 区: MICROCOMPACT — when the projected context exceeds the threshold,
74
+ * C area: MICROCOMPACT — when the projected context exceeds the threshold,
75
75
  * append ONE durable `microcompacted` boundary (clearing compactable tool
76
76
  * results older than the recent turns). The decision is a persisted fact:
77
77
  * the projection derives the same cleared view from the same events,
@@ -93,20 +93,20 @@ export interface LoopConfig {
93
93
  */
94
94
  readonly resolveApproval?: (decisionId: string) => Promise<PermissionDecision>;
95
95
  /**
96
- * 第四轮(对抗): a verdict the human ALREADY gave before an abort landed.
96
+ * round 4 (adversarial): a verdict the human ALREADY gave before an abort landed.
97
97
  * The abort path consults this BEFORE yielding the aborted terminal: a
98
98
  * consumed verdict must be recorded (exactly once), never lost — the
99
99
  * human's decision outranks the abort.
100
100
  */
101
101
  readonly approvalVerdict?: (decisionId: string) => boolean | undefined;
102
102
  /**
103
- * C 组: the channel that resolves a failed NON-idempotent execution.
103
+ * C group: the channel that resolves a failed NON-idempotent execution.
104
104
  * The loop persists `uncertain_pending`, yields it, and AWAITS the
105
105
  * human verdict — no next model turn, no sibling tool, no auto-retry.
106
106
  * Absent, the failure is recorded `abandoned` (never retried).
107
107
  */
108
108
  readonly resolveUncertainty?: (executionId: string) => Promise<"rerun" | "abandoned">;
109
- /** 第四轮(对抗): the uncertainty twin of `approvalVerdict`. */
109
+ /** round 4 (adversarial): the uncertainty twin of `approvalVerdict`. */
110
110
  readonly uncertaintyVerdict?: (executionId: string) => "rerun" | "abandoned" | undefined;
111
111
  /**
112
112
  * E1: extension approval policies, tagged by their owning extension —
@@ -17,13 +17,13 @@
17
17
  * assemble (onUserMessage / onPreLlm)
18
18
  * → adapter.stream(): events yielded straight through; every validated
19
19
  * and policy-allowed tool call LAUNCHES its execution immediately
20
- * (流中执行) — the executions run concurrently under a window of 4
20
+ * (streaming execution) — the executions run concurrently under a window of 4
21
21
  * (0.1.26, ADR-0024 Amd), their events queued and drained between
22
22
  * stream events (completion order; the projection re-orders the
23
- * results by call order — 字节纪律)
23
+ * results by call order — the byte discipline)
24
24
  * → the turn settles: the launched executions finish (receipts land
25
25
  * before any terminal), the ask-gated successors follow the human's
26
- * verdict (保守序)
26
+ * verdict (the conservative order)
27
27
  * no tool calls / maxTurns / abort / max_tokens → terminal event, return
28
28
  *
29
29
  * Retry lives HERE and only here (ADR-0005): a retryable StructuredError
@@ -72,7 +72,7 @@ export async function* loop(config) {
72
72
  };
73
73
  const aborted = () => signal?.aborted === true;
74
74
  // Assemble: the incoming user message may be rewritten or vetoed.
75
- // C 组: the outcome is PERSISTED as a user_input_replaced event — the
75
+ // C group: the outcome is PERSISTED as a user_input_replaced event — the
76
76
  // projection renders the final replacement AT THE INPUT'S POSITION (or
77
77
  // nothing, for a true veto), so the rewritten fact is the ONLY fact
78
78
  // every later turn of the run sees.
@@ -82,13 +82,13 @@ export async function* loop(config) {
82
82
  const last = messages.at(-1);
83
83
  if (last?.role === "user") {
84
84
  const inputEvent = [...log.all].reverse().find((e) => e.type === "user_input");
85
- // 六: the hook runs AT MOST ONCE per input. A replacement that
85
+ // round 6: the hook runs AT MOST ONCE per input. A replacement that
86
86
  // ALREADY exists (persisted before a crash, or before a resume)
87
87
  // means the hook already spoke for this input — it must never
88
88
  // run again, and the run continues from the durable fact.
89
89
  const replacement = log.all.find((e) => e.type === "user_input_replaced" && e.replaces === inputEvent?.seq);
90
90
  if (replacement !== undefined) {
91
- // 六/第五轮(P1-7): the hook ALREADY spoke for this input — a
91
+ // round 6/round 5 (P1-7): the hook ALREADY spoke for this input — a
92
92
  // durable null content is a TRUE veto: restore the vetoed
93
93
  // flag so the provider is NEVER called, even when earlier
94
94
  // history exists (previously only an empty history happened
@@ -98,7 +98,7 @@ export async function* loop(config) {
98
98
  }
99
99
  if (replacement === undefined && inputEvent) {
100
100
  const rewritten = await hooks.onUserMessage(last, {});
101
- // 一: the rewrite/veto is a NORMAL stream event — persisted by
101
+ // round 1: the rewrite/veto is a NORMAL stream event — persisted by
102
102
  // the harness and visible to consumers, never a hidden append.
103
103
  const replaced = log.append({
104
104
  type: "user_input_replaced",
@@ -109,11 +109,11 @@ export async function* loop(config) {
109
109
  messages = derive();
110
110
  yield replaced;
111
111
  if (rewritten === null)
112
- vetoed = true; // 三: a true veto ends the run
112
+ vetoed = true; // round 3: a true veto ends the run
113
113
  }
114
114
  }
115
115
  }
116
- // 三: a true veto ends the run — the provider is NEVER called, even
116
+ // round 3: a true veto ends the run — the provider is NEVER called, even
117
117
  // when earlier history exists.
118
118
  if (vetoed || messages.length === 0) {
119
119
  yield await terminal({ kind: "completed" });
@@ -123,7 +123,7 @@ export async function* loop(config) {
123
123
  // showed the sequential ledger is the bottleneck): the windowed parallel
124
124
  // batching returns, this time with the ledger events emitted per call in
125
125
  // deterministic order. The model stream and the tool executions run
126
- // CONCURRENTLY (流中执行): a tool_call_end validated and allowed by the
126
+ // CONCURRENTLY (streaming execution): a tool_call_end validated and allowed by the
127
127
  // policy chain launches its execution immediately; the events land
128
128
  // through a queue the stream loop drains on every stream event — their
129
129
  // seq order is the COMPLETION order (started/receipt/result land when
@@ -132,13 +132,13 @@ export async function* loop(config) {
132
132
  // turn's results by CALL order (project.ts flushResults) — the
133
133
  // completion order only affects the landing moment, never the derived
134
134
  // messages. The window caps concurrent executions; the ask gate holds
135
- // an ask AND the calls after it until the human decides (保守序 — the
135
+ // an ask AND the calls after it until the human decides (the conservative order — the
136
136
  // context may have changed when the human approves); the STARTED event
137
137
  // is acked by the drain so the handler never runs before its receipt is
138
138
  // persisted (write-ahead preserved). A voided turn (forged event,
139
139
  // post-stop violation, a non-compatible stop reason) fires the violated
140
- // signal: started executions finish and their receipts land (已开跑照落
141
- // receipt), not-started ones bail without a started event (abort 语义
140
+ // signal: started executions finish and their receipts land (already-started executions still land their
141
+ // receipt), not-started ones bail without a started event (abort semantics
142
142
  // clean, never uncertain).
143
143
  const WINDOW_SIZE = 4;
144
144
  // The execution event queue. The drain (below) appends + yields each
@@ -195,7 +195,7 @@ export async function* loop(config) {
195
195
  let launchError = null;
196
196
  let violated = false;
197
197
  // The violated signal: rejects when the turn is voided — the paused
198
- // ask-branches bail (abort 语义 for not-started executions). Typed
198
+ // ask-branches bail (abort semantics for not-started executions). Typed
199
199
  // `never` so the ask race resolves to the human decision alone.
200
200
  let violatedReject = () => { };
201
201
  const violatedP = new Promise((_, reject) => {
@@ -261,7 +261,7 @@ export async function* loop(config) {
261
261
  return;
262
262
  }
263
263
  }
264
- // 保守序: the calls AFTER an ask wait for its human
264
+ // the conservative order: the calls AFTER an ask wait for its human
265
265
  // resolution (the askGate is the ask's pause promise —
266
266
  // resolved by default, released by the ask branch above).
267
267
  // The context may have changed when the human approves.
@@ -293,7 +293,7 @@ export async function* loop(config) {
293
293
  return;
294
294
  }
295
295
  turns += 1;
296
- // ── C 区: one-shot microcompact boundary when over the threshold ──
296
+ // ── C area: one-shot microcompact boundary when over the threshold ──
297
297
  if (config.microcompact !== undefined && estimateTokens(messages) > config.microcompact.thresholdTokens) {
298
298
  const beforeSeq = microcompactBoundarySeq(log.all, config.microcompact.keepResults ?? KEEP_COMPACTABLE_RESULTS);
299
299
  if (beforeSeq !== undefined) {
@@ -316,11 +316,11 @@ export async function* loop(config) {
316
316
  let stopCount = 0;
317
317
  let streamed = false;
318
318
  let attempts = 0;
319
- // 五: the turn is a strict protocol — once the provider stops, ANY
319
+ // round 5: the turn is a strict protocol — once the provider stops, ANY
320
320
  // further event (delta, tool call, usage, thinking) is a violation.
321
321
  let sawStop = false;
322
322
  let postStopViolation = false;
323
- // 五: the adapter may only produce its OWN event kinds — a
323
+ // round 5: the adapter may only produce its OWN event kinds — a
324
324
  // kernel-owned event (terminal, tool_execution_*, permission_*,
325
325
  // user_input, …) from the stream is a FORGERY and must never reach
326
326
  // the log.
@@ -346,10 +346,10 @@ export async function* loop(config) {
346
346
  streamed = true;
347
347
  // 0.1.26: the launched executions' events land first —
348
348
  // the completion order; the projection re-orders the
349
- // results by call order (字节纪律).
349
+ // results by call order (the byte discipline).
350
350
  for await (const q of drainExec())
351
351
  yield q;
352
- // 五: the trust gate — a kernel-owned event from the
352
+ // round 5: the trust gate — a kernel-owned event from the
353
353
  // adapter is a forgery: it is never appended (never
354
354
  // persisted), and the turn ends with a unique
355
355
  // invalid_request terminal below.
@@ -359,7 +359,7 @@ export async function* loop(config) {
359
359
  violatedReject();
360
360
  break;
361
361
  }
362
- // 五: a delta/tool call/usage arriving AFTER the provider's
362
+ // round 5: a delta/tool call/usage arriving AFTER the provider's
363
363
  // stop is a protocol error — the violating event is never
364
364
  // appended, and the turn ends with an error terminal (the
365
365
  // pending tools must NOT execute).
@@ -376,7 +376,7 @@ export async function* loop(config) {
376
376
  }
377
377
  if (ev.type === "tool_call_end") {
378
378
  pending.push(ev);
379
- // 流中执行: the call launches immediately — the decide
379
+ // streaming execution: the call launches immediately — the decide
380
380
  // and the ledgered run proceed in parallel with the
381
381
  // model stream.
382
382
  launch(ev);
@@ -408,12 +408,12 @@ export async function* loop(config) {
408
408
  return;
409
409
  }
410
410
  }
411
- // ── The voided-terminal computation ( / C ) ────────────────────
411
+ // ── The voided-terminal computation (round 5 / C group) ────────────────────
412
412
  // A forged kernel-owned event, a post-stop event, or a
413
413
  // non-compatible stop reason voids the turn: the launched
414
- // executions still finish and their receipts land (已开跑照落
414
+ // executions still finish and their receipts land (already-started executions still land their
415
415
  // receipt — the side effects happened), the not-started bail
416
- // (abort 语义), then the terminal.
416
+ // (abort semantics), then the terminal.
417
417
  let voided = null;
418
418
  if (forgedEvent) {
419
419
  voided = {
@@ -454,7 +454,7 @@ export async function* loop(config) {
454
454
  yield await terminal({ kind: "aborted", by: "user" });
455
455
  return;
456
456
  }
457
- // ── C 组: the turn is verified. 0.1.26 (流中执行): the calls were
457
+ // ── C group: the turn is verified. 0.1.26 (streaming execution): the calls were
458
458
  // ALREADY launched at tool_call_end, so a non-compatible stop reason
459
459
  // VOIDS the turn instead of preventing the execution.
460
460
  if (voided === null && pending.length > 0) {
@@ -501,9 +501,9 @@ export async function* loop(config) {
501
501
  }
502
502
  }
503
503
  // ── The turn settles: a void fires the violated signal — the
504
- // not-started executions bail (abort 语义 — no started, no
504
+ // not-started executions bail (abort semantics — no started, no
505
505
  // receipt, never uncertain); the started ones finish and their
506
- // receipts land BEFORE the terminal or the next turn (已开跑照落
506
+ // receipts land BEFORE the terminal or the next turn (already-started executions still land their
507
507
  // receipt). The drain yields every queued event; the STARTED
508
508
  // ack resolves as the consumer persists (write-ahead), so the
509
509
  // launches advance DURING the drain — a 10ms settle poll covers
@@ -578,7 +578,7 @@ function terminalForStop(reason) {
578
578
  }
579
579
  }
580
580
  /** The tool_result event for a call — the shared shape (executionId rides
581
- * it as the durable correlation, ). */
581
+ * it as the durable correlation, round 5). */
582
582
  function resultEvent(call, result, executionId) {
583
583
  return {
584
584
  type: "tool_result",
@@ -589,7 +589,7 @@ function resultEvent(call, result, executionId) {
589
589
  // the runtime guard keeps a JS tool's illegal combination out of
590
590
  // the persisted event too).
591
591
  ...(result.isError && result.errorKind ? { errorKind: result.errorKind } : {}),
592
- // 五: a live tool's tags are preserved losslessly (do-not-compact,
592
+ // round 5: a live tool's tags are preserved losslessly (do-not-compact,
593
593
  // billing receipts, trace anchors) — never dropped at the loop.
594
594
  ...(result.tags !== undefined ? { tags: result.tags } : {}),
595
595
  ...(executionId !== undefined ? { executionId } : {}),
@@ -634,7 +634,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
634
634
  throw ABORTED;
635
635
  // ── E1: the extension policy chain, decided BEFORE the human flow ─────
636
636
  // A durable POLICY decision for THIS call takes effect on resume — the
637
- // chain never re-runs when its verdict is already in the log (同构
637
+ // chain never re-runs when its verdict is already in the log (isomorphic
638
638
  // alreadyReplaced: the persisted fact speaks for the call). The match is
639
639
  // the same logical call: same callId, decidedBy set (a policy verdict,
640
640
  // never a human's), and input identical to the original tool_call_end —
@@ -660,7 +660,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
660
660
  v = await raceAbort(Promise.resolve(policy.decide(payload, ctx)), signal);
661
661
  }
662
662
  catch {
663
- v = { action: "ask" }; // 抛错 = 该扩展计为 ask —— 发声,绝不静默
663
+ v = { action: "ask" }; // a throwing policy counts as ask it speaks, never silently
664
664
  }
665
665
  if (v.action === "abstain")
666
666
  continue; // no opinion — not a verdict
@@ -678,10 +678,10 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
678
678
  chainVerdict = { action: "deny", reason: deniedReason ?? "denied" };
679
679
  }
680
680
  else if (chainVerdict === undefined && anySpoke) {
681
- chainVerdict = { action: "allow" }; // 全发声者皆 allow
681
+ chainVerdict = { action: "allow" }; // every speaker allows
682
682
  }
683
683
  else if (chainVerdict === undefined) {
684
- // 全员 abstain (ADR-0042): NO policy speaks — the call falls to
684
+ // an all-abstain (ADR-0042): NO policy speaks — the call falls to
685
685
  // the ask flow below, never to a silent auto-approve. The human
686
686
  // decides; absent a channel, humanPause's honest denial.
687
687
  chainVerdict = { action: "ask" };
@@ -707,7 +707,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
707
707
  return { action: "deny", result: resultEvent(call, denialResult(durable.reason ?? "denied")) };
708
708
  }
709
709
  if (chainVerdict?.action === "ask") {
710
- // 裁决 A (E1 ask 语义修正): an ask means "a HUMAN must decide" — it
710
+ // ruling A (the E1 ask semantics fix): an ask means "a HUMAN must decide" — it
711
711
  // routes DIRECTLY to the human approval pause, never through
712
712
  // onPreTool: a static automated policy (e.g. the CLI's default deny
713
713
  // for unknown tools) must not answer for the human. No approval
@@ -718,10 +718,10 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
718
718
  }
719
719
  return { action: "ask", decisionId: nextDecisionId() };
720
720
  }
721
- // Permission negotiation — defer is a REAL pause (Phase D). C 组: the
721
+ // Permission negotiation — defer is a REAL pause (Phase D). C group: the
722
722
  // hook itself is cancelable (a slow policy query must not outlive an
723
723
  // abort), and the signal is re-checked after it returns. Runs only when
724
- // the policy chain did not run at all (裁决 A: an ask was already
724
+ // the policy chain did not run at all (ruling A: an ask was already
725
725
  // resolved by the human pause above — the static hook never speaks for
726
726
  // it, and a durable decision already spoke for the call).
727
727
  if (durable === undefined && chainVerdict === undefined && hooks.onPreTool) {
@@ -738,7 +738,7 @@ async function decideCall(call, registry, hooks, ctx, log, resolveApproval, reso
738
738
  return { action: "allow" };
739
739
  }
740
740
  /**
741
- * The human approval pause (Phase D / 裁决 A): register the resolver
741
+ * The human approval pause (Phase D / ruling A): register the resolver
742
742
  * BEFORE announcing the request (a consumer that answers the moment it
743
743
  * sees the event must find the resolver already waiting — no deadlock
744
744
  * between push and await), persist the request (via push), await the
@@ -767,7 +767,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
767
767
  }
768
768
  catch (err) {
769
769
  if (err === ABORTED) {
770
- // 第四轮(对抗): the human may have answered in the same instant
770
+ // round 4 (adversarial): the human may have answered in the same instant
771
771
  // the abort landed — a CONSUMED verdict must be recorded
772
772
  // (exactly once), never lost; the abort then ends the run with
773
773
  // its honest aborted terminal.
@@ -791,7 +791,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
791
791
  push({
792
792
  type: "permission_decided",
793
793
  decisionId,
794
- callId: call.callId, // binds the decision to the invocation (B )
794
+ callId: call.callId, // binds the decision to the invocation (B group)
795
795
  decision: finalDecision.action === "allow" ? "approved" : "denied",
796
796
  ...(finalDecision.action === "deny" && finalDecision.reason !== undefined
797
797
  ? { reason: finalDecision.reason }
@@ -808,7 +808,7 @@ async function humanPause(call, decisionId, hooks, log, resolveApproval, resolve
808
808
  */
809
809
  async function runLedgered(call, registry, hooks, ctx, signal, push) {
810
810
  const tool = registry.get(call.name); // validated + decided by decideCall
811
- // C 组: the signal is re-checked immediately before the started event —
811
+ // C group: the signal is re-checked immediately before the started event —
812
812
  // an abort that landed in any permission path must not let the side
813
813
  // effect begin.
814
814
  if (signal?.aborted)
@@ -830,7 +830,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
830
830
  });
831
831
  let result;
832
832
  try {
833
- // C 组: re-checked again right before the handler — the handler also
833
+ // C group: re-checked again right before the handler — the handler also
834
834
  // observes ctx.signal, but the gate itself must not invoke it after
835
835
  // a cancel.
836
836
  result = signal?.aborted
@@ -847,7 +847,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
847
847
  if (hooks.onPostTool) {
848
848
  result = await hooks.onPostTool({ callId: call.callId, name: call.name, input: call.input ?? {} }, result, ctx);
849
849
  }
850
- // 裁决 #12 修正一: a non-idempotent failure's side effects may have
850
+ // ruling #12 correction one: a non-idempotent failure's side effects may have
851
851
  // partially applied — an honest note rides the RESULT (and the failed
852
852
  // receipt below, losslessly — a crash-window repair of the tool_result
853
853
  // reproduces the normal path). Idempotent failures carry no note; the
@@ -863,7 +863,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
863
863
  // Area 3: only a tool that PROVED safe-to-retry (idempotent) gets a
864
864
  // clean failure; a non-idempotent failure may have produced a side
865
865
  // effect and is uncertain until a human decides.
866
- // 八: the tags ride on the RECEIPT too — a crash-window repair of the
866
+ // round 8: the tags ride on the RECEIPT too — a crash-window repair of the
867
867
  // tool_result reproduces the normal path losslessly.
868
868
  push({
869
869
  type: "tool_execution_failed",
@@ -893,7 +893,7 @@ async function runLedgered(call, registry, hooks, ctx, signal, push) {
893
893
  const ABORTED = Symbol("kiso-aborted-during-approval");
894
894
  /**
895
895
  * Wait for a human decision (approval or uncertain verdict), but WAKE on
896
- * abort (Area 4 / C ): a cancel during the wait must end the run, not
896
+ * abort (Area 4 / C group): a cancel during the wait must end the run, not
897
897
  * leave the iterator hung. Throws ABORTED; the loop converts it to an
898
898
  * `aborted` terminal.
899
899
  */
@@ -956,14 +956,14 @@ function sleep(ms, signal) {
956
956
  });
957
957
  }
958
958
  /**
959
- * C (自举 #3): the DEFAULT for how many of the NEWEST compactable tool
959
+ * C area (bootstrap #3): the DEFAULT for how many of the NEWEST compactable tool
960
960
  * results survive a microcompact boundary (overridable per config via
961
961
  * microcompact.keepResults) — the model must keep reasoning over the
962
962
  * recent results, whatever turn they belong to.
963
963
  */
964
964
  const KEEP_COMPACTABLE_RESULTS = 4;
965
965
  /**
966
- * C 区: the boundary seq for a microcompact — drawn by COMPACTABLE-RESULT
966
+ * C area: the boundary seq for a microcompact — drawn by COMPACTABLE-RESULT
967
967
  * recentness, never user turns: a SINGLE user turn that reads several big
968
968
  * files (the coding agent's main overflow shape) crosses the threshold and
969
969
  * must trigger. The newest `keepResults` still-visible compactable tool
@@ -987,11 +987,11 @@ function microcompactBoundarySeq(events, keepResults) {
987
987
  if (ev.type !== "tool_result" || ev.seq <= lastCleared)
988
988
  continue;
989
989
  const name = callName.get(ev.callId);
990
- // 手感批 C6 (P4): the do-not-compact tag makes a result UN-CLEARABLE
990
+ // the ergonomics batch C6 (P4): the do-not-compact tag makes a result UN-CLEARABLE
991
991
  // (the projection keeps it) — the count must EXCLUDE it, exactly like
992
992
  // the clearing side. A tagged result counted here would steal a keep
993
993
  // window slot forever and could anchor the boundary at a result the
994
- // projection refuses to clear (计数与清除口径一致).
994
+ // projection refuses to clear (the count and the clearing share one rule).
995
995
  if (name !== undefined && MICROCOMPACTABLE.has(name) && !(ev.tags ?? []).includes(DO_NOT_COMPACT))
996
996
  visible.push(ev.seq);
997
997
  }
@@ -16,8 +16,8 @@
16
16
  * Events with no message shape (usage, stop, thinking, terminal, the
17
17
  * compaction events' own records) are skipped by the projection;
18
18
  * `compacted` applies the EXACT persisted replacements verbatim — it never
19
- * re-runs the compaction algorithm (a future version could differ, A 组/D
20
- * ); `microcompacted` boundaries re-derive the cleared view from the
19
+ * re-runs the compaction algorithm (a future version could differ, A group/D
20
+ * group); `microcompacted` boundaries re-derive the cleared view from the
21
21
  * stream itself (deterministic and idempotent); `summarized` (ADR-0044)
22
22
  * replaces its covered range with one assistant summary message. All
23
23
  * three are persisted facts — the replay equals the live run. See ADR-0002.
@@ -26,18 +26,18 @@ import type { Event } from "../protocol/events.js";
26
26
  import type { EventInput } from "./event-log.js";
27
27
  import type { AssistantBlock, Message, MessageSource } from "../protocol/messages.js";
28
28
  /**
29
- * C 区: tools whose output is eligible for microcompact clearing — reads,
29
+ * C area: tools whose output is eligible for microcompact clearing — reads,
30
30
  * listings, searches, and shell output. write/edit outputs are short and
31
- * never cleared. Exported so the loop's boundary computation (自举 #3)
31
+ * never cleared. Exported so the loop's boundary computation (bootstrap #3)
32
32
  * counts exactly the results the projection can clear.
33
33
  */
34
34
  export declare const MICROCOMPACTABLE: Set<string>;
35
- /** The tag that makes a tool result un-clearable (C ). */
35
+ /** The tag that makes a tool result un-clearable (C area). */
36
36
  export declare const DO_NOT_COMPACT = "do-not-compact";
37
37
  /**
38
38
  * Rebuild the message array from events. Deterministic and order-sensitive:
39
39
  * replaying the same log always produces the same messages — BYTE FOR BYTE
40
- * (D ): the same event prefix derives the same message prefix; the only
40
+ * (D area): the same event prefix derives the same message prefix; the only
41
41
  * events that change already-derived messages are `microcompacted`
42
42
  * boundaries and `summarized` facts, which are themselves persisted facts
43
43
  * (their replay derives the same projection every time).
@@ -16,23 +16,23 @@
16
16
  * Events with no message shape (usage, stop, thinking, terminal, the
17
17
  * compaction events' own records) are skipped by the projection;
18
18
  * `compacted` applies the EXACT persisted replacements verbatim — it never
19
- * re-runs the compaction algorithm (a future version could differ, A 组/D
20
- * ); `microcompacted` boundaries re-derive the cleared view from the
19
+ * re-runs the compaction algorithm (a future version could differ, A group/D
20
+ * group); `microcompacted` boundaries re-derive the cleared view from the
21
21
  * stream itself (deterministic and idempotent); `summarized` (ADR-0044)
22
22
  * replaces its covered range with one assistant summary message. All
23
23
  * three are persisted facts — the replay equals the live run. See ADR-0002.
24
24
  */
25
25
  /**
26
- * C 区: tools whose output is eligible for microcompact clearing — reads,
26
+ * C area: tools whose output is eligible for microcompact clearing — reads,
27
27
  * listings, searches, and shell output. write/edit outputs are short and
28
- * never cleared. Exported so the loop's boundary computation (自举 #3)
28
+ * never cleared. Exported so the loop's boundary computation (bootstrap #3)
29
29
  * counts exactly the results the projection can clear.
30
30
  */
31
31
  export const MICROCOMPACTABLE = new Set(["read_file", "list_dir", "search_text", "shell"]);
32
- /** The tag that makes a tool result un-clearable (C ). */
32
+ /** The tag that makes a tool result un-clearable (C area). */
33
33
  export const DO_NOT_COMPACT = "do-not-compact";
34
34
  /**
35
- * C 区: the fixed placeholder for a cleared tool output, derived ONLY from
35
+ * C area: the fixed placeholder for a cleared tool output, derived ONLY from
36
36
  * the event stream (deterministic across replay): the tool's name and its
37
37
  * primary argument (the first string-valued field of its input).
38
38
  */
@@ -54,7 +54,7 @@ function primaryArg(input) {
54
54
  /**
55
55
  * Rebuild the message array from events. Deterministic and order-sensitive:
56
56
  * replaying the same log always produces the same messages — BYTE FOR BYTE
57
- * (D ): the same event prefix derives the same message prefix; the only
57
+ * (D area): the same event prefix derives the same message prefix; the only
58
58
  * events that change already-derived messages are `microcompacted`
59
59
  * boundaries and `summarized` facts, which are themselves persisted facts
60
60
  * (their replay derives the same projection every time).
@@ -75,9 +75,9 @@ export function projectMessages(events) {
75
75
  text = null;
76
76
  }
77
77
  };
78
- // 自举 P1: the reasoning of the turn being built, accumulated from its
78
+ // bootstrap P1: the reasoning of the turn being built, accumulated from its
79
79
  // `thinking` events and attached to the assistant message at flush —
80
- // deterministic (same events → same messages → same request body, D ).
80
+ // deterministic (same events → same messages → same request body, D area).
81
81
  let pendingReasoning = null;
82
82
  const flushAssistant = () => {
83
83
  pushText();
@@ -96,7 +96,7 @@ export function projectMessages(events) {
96
96
  blocks = [];
97
97
  assistantSource = undefined;
98
98
  };
99
- // C 组/六: vetoed/rewritten user inputs. Collect the replacement map
99
+ // C group/round 6: vetoed/rewritten user inputs. Collect the replacement map
100
100
  // first — the FINAL replacement for each input wins (later replacements
101
101
  // never produce extra messages), and the replacement renders AT THE
102
102
  // INPUT'S OWN POSITION: the original is skipped, the final non-null
@@ -111,7 +111,7 @@ export function projectMessages(events) {
111
111
  });
112
112
  }
113
113
  }
114
- // C 区: callId → {name, input} for the microcompact placeholder.
114
+ // C area: callId → {name, input} for the microcompact placeholder.
115
115
  const callMeta = new Map();
116
116
  for (const ev of events) {
117
117
  if (ev.type === "tool_call_end")
@@ -144,8 +144,8 @@ export function projectMessages(events) {
144
144
  // physical seq order is the COMPLETION order (started/receipt/result land
145
145
  // when each execution finishes — parallel), which must never enter the
146
146
  // projection: the same logical turn projects byte-identically whatever
147
- // the completion interleaving (字节纪律call 序为准,完成序只影响
148
- // 落盘时刻). `callOrder` is rebuilt per turn from the tool_call_end
147
+ // the completion interleaving (the byte discipline — call order is the truth; completion order only affects
148
+ // the moment of writing). `callOrder` is rebuilt per turn from the tool_call_end
149
149
  // events (their seq order IS the call order — the stream order).
150
150
  let resultBuf = [];
151
151
  const callOrder = new Map();
@@ -188,7 +188,7 @@ export function projectMessages(events) {
188
188
  // first, then its results in call order (the turn boundary).
189
189
  flushAssistant();
190
190
  flushResults();
191
- // 六: the final replacement renders HERE, at the input's own
191
+ // round 6: the final replacement renders HERE, at the input's own
192
192
  // position — the original is skipped, the replacement event
193
193
  // itself produces nothing (a later replacement for the same
194
194
  // input never becomes a second message).
@@ -214,10 +214,10 @@ export function projectMessages(events) {
214
214
  }
215
215
  case "user_input_replaced":
216
216
  // The replacement already rendered at its input's position —
217
- // this event carries no message of its own ().
217
+ // this event carries no message of its own (round 6).
218
218
  break;
219
219
  case "assistant_start":
220
- // D 组: an explicit message boundary — close any open message
220
+ // D group: an explicit message boundary — close any open message
221
221
  // and begin a new one (adjacent assistants stay separate).
222
222
  flushAssistant();
223
223
  flushResults();
@@ -304,7 +304,7 @@ export function projectMessages(events) {
304
304
  ...(ev.source !== undefined ? { source: ev.source } : {}),
305
305
  ...(ev.tags !== undefined ? { tags: ev.tags } : {}),
306
306
  };
307
- // 五: the originating event's seq rides on the message as a
307
+ // round 5: the originating event's seq rides on the message as a
308
308
  // NON-ENUMERABLE correlation field — the stable identity
309
309
  // compaction uses to name WHICH result it replaced. Deep
310
310
  // equality with seed messages (which carry no such field)
@@ -322,7 +322,7 @@ export function projectMessages(events) {
322
322
  flushAssistant();
323
323
  flushResults(); // the results must be in `out` before the replacement pass
324
324
  flushAssistant();
325
- // C 区: replace every eligible OLD tool result with the fixed
325
+ // C area: replace every eligible OLD tool result with the fixed
326
326
  // placeholder. Eligibility: the result's own event seq <= the
327
327
  // boundary, its tool in the whitelist, and no do-not-compact
328
328
  // tag. Deterministic — the boundary event IS the decision.
@@ -346,10 +346,10 @@ export function projectMessages(events) {
346
346
  flushResults(); // the results must be in `out` before the replacement pass
347
347
  flushAssistant();
348
348
  // Apply the EXACT persisted replacements — never re-run the
349
- // compaction algorithm (a future version could differ). 五:
349
+ // compaction algorithm (a future version could differ). round 5:
350
350
  // v2 entries are keyed by the replaced tool-result EVENT's
351
351
  // seq, so only the specific result is rewritten — never a
352
- // same-callId sibling from another turn or run. 第四轮: v1
352
+ // same-callId sibling from another turn or run. round 4: v1
353
353
  // entries (round-three sessions, no eventSeq) replay with v1
354
354
  // semantics — every tool result with that callId is replaced,
355
355
  // exactly as the old framework did.
@@ -369,7 +369,7 @@ export function projectMessages(events) {
369
369
  break;
370
370
  }
371
371
  case "thinking":
372
- // 自举 P1: accumulate the turn's reasoning — the flush (an
372
+ // bootstrap P1: accumulate the turn's reasoning — the flush (an
373
373
  // empty one at the turn's start) keeps the pending text, and
374
374
  // the assistant message that follows carries it. 0.1.26: the
375
375
  // assistant flush is guarded on the buffered results (a
@@ -440,9 +440,9 @@ export function messagesToEvents(messages) {
440
440
  break;
441
441
  }
442
442
  case "assistant": {
443
- // D 组: an explicit assistant_start/assistant_end pair frames
443
+ // D group: an explicit assistant_start/assistant_end pair frames
444
444
  // the message — adjacent and empty assistants round-trip.
445
- // 自举 P1: the reasoning re-enters the log as its ORIGINAL
445
+ // bootstrap P1: the reasoning re-enters the log as its ORIGINAL
446
446
  // thinking event — the projection re-attaches it identically.
447
447
  if (msg.reasoning !== undefined) {
448
448
  out.push({ type: "thinking", text: msg.reasoning });
@@ -49,7 +49,7 @@ export interface StreamOptions {
49
49
  readonly signal?: AbortSignalLike;
50
50
  }
51
51
  /**
52
- * The NARROW event set an adapter may produce (). Everything else in the
52
+ * The NARROW event set an adapter may produce (round 5). Everything else in the
53
53
  * union is kernel-owned — `terminal`, `tool_execution_*`, `permission_*`,
54
54
  * `user_input`, `compacted`, `summarized`, `uncertain_pending`,
55
55
  * `user_input_replaced`, `assistant_start`/`assistant_end` — and a
@@ -63,7 +63,7 @@ export type AdapterEvent = Extract<Event, {
63
63
  /** Runtime whitelist backing the narrowed type — the loop's trust gate. */
64
64
  export declare const ADAPTER_EVENT_TYPES: ReadonlySet<string>;
65
65
  /**
66
- * 第五轮(P1-8): the trust gate validates STRUCTURE, not just the type name.
66
+ * round 5(P1-8): the trust gate validates STRUCTURE, not just the type name.
67
67
  * A third-party adapter can emit a legal type with illegal fields (a stop
68
68
  * without a reason, a usage with known:true and no token, an array tool
69
69
  * input) — persisted, that would poison the next load. The gate reuses the
@@ -31,7 +31,7 @@ export const ADAPTER_EVENT_TYPES = new Set([
31
31
  "stop",
32
32
  ]);
33
33
  /**
34
- * 第五轮(P1-8): the trust gate validates STRUCTURE, not just the type name.
34
+ * round 5(P1-8): the trust gate validates STRUCTURE, not just the type name.
35
35
  * A third-party adapter can emit a legal type with illegal fields (a stop
36
36
  * without a reason, a usage with known:true and no token, an array tool
37
37
  * input) — persisted, that would poison the next load. The gate reuses the
@@ -62,7 +62,7 @@ export interface TextStart {
62
62
  readonly source?: import("./messages.js").MessageSource;
63
63
  }
64
64
  /**
65
- * The explicit boundary of an assistant message (D ). Adapters never emit
65
+ * The explicit boundary of an assistant message (D group). Adapters never emit
66
66
  * these (their implicit boundaries — tool_result/user_input/terminal — are
67
67
  * enough); the seed encoder uses them so ADJACENT assistant messages and
68
68
  * EMPTY assistant messages round-trip losslessly.
@@ -134,12 +134,12 @@ export interface ToolResultEvent {
134
134
  readonly seq: number;
135
135
  readonly type: "tool_result";
136
136
  readonly callId: string;
137
- /** Full content — blocks preserved losslessly (D ). */
137
+ /** Full content — blocks preserved losslessly (D group). */
138
138
  readonly content: string | readonly import("./messages.js").ContentBlock[];
139
139
  readonly isError: boolean;
140
140
  /** Present only when `isError` is true and the handler classified it. */
141
141
  readonly errorKind?: ToolErrorKind;
142
- /** The execution that produced this result (B ) — receipt pairing key. */
142
+ /** The execution that produced this result (B group) — receipt pairing key. */
143
143
  readonly executionId?: string;
144
144
  /** Provenance + product tags — preserved losslessly (Area 6). */
145
145
  readonly source?: import("./messages.js").MessageSource;
@@ -161,17 +161,17 @@ export interface UserInputEvent {
161
161
  /**
162
162
  * Compaction happened at this point in the trajectory. The EXACT
163
163
  * replacements are persisted; the projection applies them verbatim — it
164
- * never re-runs a future version of the compaction algorithm (A 组/D ).
164
+ * never re-runs a future version of the compaction algorithm (A group/D group).
165
165
  * The replay therefore equals the live run byte for byte, independent of
166
166
  * algorithm drift.
167
167
  *
168
- * 五: `eventSeq` is the STABLE identity — the seq of the specific
168
+ * round 5: `eventSeq` is the STABLE identity — the seq of the specific
169
169
  * `tool_result` event that was replaced. The provider callId may repeat
170
170
  * across runs and is correlation-only; `callId` is kept for traceability.
171
171
  * Only THIS turn's NEWLY cleared results are listed, never a cumulative
172
- * set of already-cleared markers ().
172
+ * set of already-cleared markers (round 5).
173
173
  *
174
- * 第四轮: `eventSeq` is OPTIONAL because sessions written by round three
174
+ * round 4: `eventSeq` is OPTIONAL because sessions written by round three
175
175
  * (v1) carry `{callId, content}` entries without it. Those are legal and
176
176
  * replay with v1 semantics (replace every tool result with that callId,
177
177
  * exactly as the old framework did); records written from now on always
@@ -212,7 +212,7 @@ export interface ToolExecutionSucceeded {
212
212
  readonly content: string;
213
213
  readonly isError: false;
214
214
  };
215
- /** 八: the tags ride on the durable RECEIPT so a crash-window repair
215
+ /** round 8: the tags ride on the durable RECEIPT so a crash-window repair
216
216
  * of the tool_result can reproduce the normal path losslessly. */
217
217
  readonly tags?: readonly string[];
218
218
  }
@@ -230,7 +230,7 @@ export interface ToolExecutionFailed {
230
230
  readonly error: string;
231
231
  readonly errorKind?: ToolErrorKind;
232
232
  readonly safeToRetry: boolean;
233
- /** 八: tags on the durable receipt, preserved across crash-window repair. */
233
+ /** round 8: tags on the durable receipt, preserved across crash-window repair. */
234
234
  readonly tags?: readonly string[];
235
235
  }
236
236
  /**
@@ -264,7 +264,7 @@ export interface PermissionDecided {
264
264
  readonly seq: number;
265
265
  readonly type: "permission_decided";
266
266
  readonly decisionId: string;
267
- /** The invocation this decision binds to (B ). */
267
+ /** The invocation this decision binds to (B group). */
268
268
  readonly callId?: string;
269
269
  readonly decision: "approved" | "denied";
270
270
  readonly reason?: string;
@@ -273,7 +273,7 @@ export interface PermissionDecided {
273
273
  readonly decidedBy?: string;
274
274
  }
275
275
  /**
276
- * A permission request was CLOSED because its run terminated first (B ):
276
+ * A permission request was CLOSED because its run terminated first (B group):
277
277
  * an aborted/completed/error run's dangling approval is dead — it is never
278
278
  * re-presented and a late approve() cannot resurrect the run.
279
279
  */
@@ -285,7 +285,7 @@ export interface PermissionExpired {
285
285
  }
286
286
  /**
287
287
  * A non-idempotent execution FAILED and the run PAUSES until a human
288
- * decides (C ): no next model turn, no sibling tool, no auto-retry. The
288
+ * decides (C group): no next model turn, no sibling tool, no auto-retry. The
289
289
  * verdict is recorded by the session (resolveUncertain) and the ledger
290
290
  * transitions uncertain → rerun/abandoned; the event itself is the durable
291
291
  * pause marker.
@@ -299,7 +299,7 @@ export interface UncertainPending {
299
299
  readonly error: string;
300
300
  }
301
301
  /**
302
- * A user input was VETOED or REWRITTEN by the harness (C ). `replaces`
302
+ * A user input was VETOED or REWRITTEN by the harness (C group). `replaces`
303
303
  * is the seq of the original user_input; the projection skips the original
304
304
  * and, when `content` is non-null, produces the replacement instead — the
305
305
  * rewritten fact is the ONLY fact every later turn sees. null content = a
@@ -310,11 +310,11 @@ export interface UserInputReplaced {
310
310
  readonly type: "user_input_replaced";
311
311
  readonly replaces: number;
312
312
  readonly content: string | readonly import("./messages.js").ContentBlock[] | null;
313
- /** Provenance of the replacement — preserved from the hook (). */
313
+ /** Provenance of the replacement — preserved from the hook (round 3). */
314
314
  readonly source?: import("./messages.js").MessageSource;
315
315
  }
316
316
  /**
317
- * C 区: a MICROCOMPACT boundary — the durable record of a context-clearing
317
+ * C area: a MICROCOMPACT boundary — the durable record of a context-clearing
318
318
  * decision. `beforeSeq` is the event seq up to which eligible tool results
319
319
  * are cleared: the projection replaces every tool_result with seq <=
320
320
  * beforeSeq (whose tool is in the compactable whitelist and carries no
@@ -22,13 +22,13 @@
22
22
  * This module is almost types-only: the only runtime value it emits is
23
23
  * `isKisoEvent`, the type guard the session store validates records with.
24
24
  */
25
- // ── deep-shape helpers (): every variant is validated field by field —
25
+ // ── deep-shape helpers (round 5): every variant is validated field by field —
26
26
  // legal enums, Terminal union members, Usage known/token combos, content
27
27
  // blocks, plain-object inputs, optional fields when present. A record that
28
28
  // parses as JSON but violates its variant's shape is corruption, never
29
29
  // history.
30
30
  const isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
31
- /** 九: counts (seq, tokens, turns, status) are non-negative SAFE integers —
31
+ /** round 9: counts (seq, tokens, turns, status) are non-negative SAFE integers —
32
32
  * negative values, NaN, Infinity, and fractional values are rejected. */
33
33
  const isNonNegativeInt = (v) => typeof v === "number" && Number.isSafeInteger(v) && v >= 0;
34
34
  const STOP_REASONS = new Set([
@@ -68,7 +68,7 @@ const MEDIA_TYPES = new Set(["image/png", "image/jpeg", "image/webp", "image/gif
68
68
  /**
69
69
  * A ContentBlock: text (text: string) or image (sourceType with the
70
70
  * documented payload — url for "url", data + mediaType for "base64").
71
- * 九: the two payload kinds are STRICTLY EXCLUSIVE — a url block must not
71
+ * round 9: the two payload kinds are STRICTLY EXCLUSIVE — a url block must not
72
72
  * carry data, a base64 block must not carry url.
73
73
  */
74
74
  function isContentBlock(v) {
@@ -102,7 +102,7 @@ function isErrorKind(v) {
102
102
  function isExecutionId(v) {
103
103
  return v.executionId === undefined || typeof v.executionId === "string";
104
104
  }
105
- /** A StructuredError — the shape the `error` terminal carries. 九: a
105
+ /** A StructuredError — the shape the `error` terminal carries. round 9: a
106
106
  * status, when present, is a non-negative safe integer (no negatives,
107
107
  * NaN, Infinity, or fractions). */
108
108
  function isStructuredError(v) {
@@ -122,7 +122,7 @@ function isTerminal(v) {
122
122
  case "max_tokens":
123
123
  return true;
124
124
  case "max_turns":
125
- return isNonNegativeInt(v.turns); // 九: a turn count is a safe integer
125
+ return isNonNegativeInt(v.turns); // round 9: a turn count is a safe integer
126
126
  case "error":
127
127
  return isStructuredError(v.error);
128
128
  case "aborted":
@@ -134,7 +134,7 @@ function isTerminal(v) {
134
134
  }
135
135
  }
136
136
  /**
137
- * Usage invariant (Area 6/九): `known: false` means the provider reported
137
+ * Usage invariant (Area 6/round 9): `known: false` means the provider reported
138
138
  * NO usage — every token field is null, never faked as zero. `known: true`
139
139
  * means SOME usage was reported — AT LEAST ONE field is a non-negative
140
140
  * safe integer; the others are null when the provider did not report
@@ -149,7 +149,7 @@ function isUsage(v) {
149
149
  return tokens.some((t) => isNonNegativeInt(t)) && tokens.every((t) => t === null || isNonNegativeInt(t));
150
150
  }
151
151
  /**
152
- * Per-variant runtime validation (): the table is
152
+ * Per-variant runtime validation (round 5): the table is
153
153
  * `satisfies Record<Event["type"], ...>` — adding a variant without a
154
154
  * validator here is a compile error (ADR-0003).
155
155
  */
@@ -165,7 +165,7 @@ const EVENT_VALIDATORS = {
165
165
  tool_result: (v) => typeof v.callId === "string" &&
166
166
  isContent(v.content) &&
167
167
  typeof v.isError === "boolean" &&
168
- // 九: an errorKind is only meaningful on an ERROR result.
168
+ // round 9: an errorKind is only meaningful on an ERROR result.
169
169
  (v.isError === true || v.errorKind === undefined) &&
170
170
  isErrorKind(v) &&
171
171
  isExecutionId(v) &&
@@ -177,7 +177,7 @@ const EVENT_VALIDATORS = {
177
177
  user_input: (v) => isContent(v.content) && isSource(v),
178
178
  compacted: (v) => Array.isArray(v.cleared) &&
179
179
  v.cleared.every((c) => isPlainObject(c) &&
180
- // 第四轮: eventSeq is optional — v1 (round three) entries are
180
+ // round 4: eventSeq is optional — v1 (round three) entries are
181
181
  // {callId, content} and remain legal; v2 entries must carry a
182
182
  // valid eventSeq.
183
183
  (c.eventSeq === undefined || isNonNegativeInt(c.eventSeq)) &&
@@ -2,7 +2,7 @@
2
2
  * E1 — extension approval policies: pure types, no runtime.
3
3
  *
4
4
  * An extension is a named bundle of optional capabilities: hooks (composed
5
- * AFTER the harness's own — 既有先行), tools (merged into the registry), and
5
+ * AFTER the harness's own — the existing come first), tools (merged into the registry), and
6
6
  * approval policies (the loop's policy chain, decided BEFORE the human
7
7
  * flow). This file is types-only: loading and composition live in the
8
8
  * runtime package (loadExtensions) and the kernel loop.
@@ -68,13 +68,13 @@ export interface KisoExtension {
68
68
  readonly append: string;
69
69
  };
70
70
  /**
71
- * 0.1.26 (MCP 懒连接): an optional LIVE flag — the CLI's banner renders
71
+ * 0.1.26 (MCP lazy connection): an optional LIVE flag — the CLI's banner renders
72
72
  * "name (connecting…)" while it is true. Soft surface: absent = no
73
73
  * marker (the default).
74
74
  */
75
75
  readonly connecting?: boolean;
76
76
  /**
77
- * 发现#8 (P1): the extension's shutdown action — the closing of external
77
+ * finding #8 (P1): the extension's shutdown action — the closing of external
78
78
  * resources it holds (child processes, connections). The LOADER is
79
79
  * responsible for calling it.
80
80
  */
@@ -2,7 +2,7 @@
2
2
  * E1 — extension approval policies: pure types, no runtime.
3
3
  *
4
4
  * An extension is a named bundle of optional capabilities: hooks (composed
5
- * AFTER the harness's own — 既有先行), tools (merged into the registry), and
5
+ * AFTER the harness's own — the existing come first), tools (merged into the registry), and
6
6
  * approval policies (the loop's policy chain, decided BEFORE the human
7
7
  * flow). This file is types-only: loading and composition live in the
8
8
  * runtime package (loadExtensions) and the kernel loop.
@@ -72,7 +72,7 @@ export interface AssistantMessage {
72
72
  readonly blocks: readonly AssistantBlock[];
73
73
  readonly source?: MessageSource;
74
74
  /**
75
- * 自举 P1: the turn's reasoning, derived deterministically from its
75
+ * bootstrap P1: the turn's reasoning, derived deterministically from its
76
76
  * `thinking` events (DeepSeek's thinking mode requires it back on
77
77
  * follow-up requests). Present only when the turn actually reasoned.
78
78
  */
@@ -96,7 +96,7 @@ export interface ToolResultMessage {
96
96
  /**
97
97
  * The seq of the `tool_result` EVENT this message was projected from —
98
98
  * the stable identity compaction uses to name WHICH result it replaced
99
- * (五: the callId may repeat across runs). DERIVED, never persisted: the
99
+ * (round 5: the callId may repeat across runs). DERIVED, never persisted: the
100
100
  * projection attaches it as a non-enumerable field, so it is invisible
101
101
  * to deep equality with seed messages and never survives a re-derive
102
102
  * from anywhere but the log.
@@ -12,7 +12,7 @@
12
12
  * model cannot call a tool that is not in its registry — no prompt can
13
13
  * achieve that guarantee.
14
14
  *
15
- * 0.1.26 (MCP 懒连接): `registerLive()` adds a LIVE tool source — a
15
+ * 0.1.26 (MCP lazy connection): `registerLive()` adds a LIVE tool source — a
16
16
  * function returning the extension's current tools array. The array grows
17
17
  * when the extension's background connections settle (the MCP bridge
18
18
  * registers its servers' tools post-connect); the registry consults the
@@ -12,7 +12,7 @@
12
12
  * model cannot call a tool that is not in its registry — no prompt can
13
13
  * achieve that guarantee.
14
14
  *
15
- * 0.1.26 (MCP 懒连接): `registerLive()` adds a LIVE tool source — a
15
+ * 0.1.26 (MCP lazy connection): `registerLive()` adds a LIVE tool source — a
16
16
  * function returning the extension's current tools array. The array grows
17
17
  * when the extension's background connections settle (the MCP bridge
18
18
  * registers its servers' tools post-connect); the registry consults the
@@ -49,7 +49,7 @@ export class ToolRegistry {
49
49
  list() {
50
50
  // The registered map WINS a name collision against a live source —
51
51
  // the same rule get()/has() already follow, applied here too
52
- // (0.1.27 失格调查: the agent eagerly registers a sync extension's
52
+ // (0.1.27 the disqualification investigation: the agent eagerly registers a sync extension's
53
53
  // tools AND registers its live source — a skills/subagent/MCP status
54
54
  // tool appeared twice in toSpecs() and the real API answered
55
55
  // "400 Tool names must be unique"; the identity is the same object,
@@ -27,7 +27,7 @@ export interface ToolContext {
27
27
  readonly meta?: Readonly<Record<string, unknown>>;
28
28
  }
29
29
  /**
30
- * 第五轮(P1-9): a DISCRIMINATED union — `errorKind` is structurally
30
+ * round 5(P1-9): a DISCRIMINATED union — `errorKind` is structurally
31
31
  * impossible on a non-error result, matching the persisted-event schema
32
32
  * (an isError:false result with an errorKind would be rejected by the
33
33
  * store's validator and poison the next load).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-core",
3
- "version": "0.1.29",
4
- "description": "kiso(基礎) core — protocol, event log, loop, hooks, modes, permissions, compaction, delivery truth. The 2,000-line kernel at the bottom of the kiso framework.",
3
+ "version": "0.1.30",
4
+ "description": "kiso (foundation) core — protocol, event log, loop, hooks, modes, permissions, compaction, delivery truth. The 2,000-line kernel at the bottom of the kiso framework.",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "exports": {