pi-fold 1.0.3 → 2.0.0

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.
@@ -2,11 +2,9 @@ import {
2
2
  denseOwnArrayValues,
3
3
  evidenceSha256,
4
4
  objectRefKey,
5
- sha256Text,
6
5
  sha256Value,
7
6
  stableStringify,
8
7
  } from "./json.ts";
9
- import type { EvidenceRef } from "./json.ts";
10
8
  import {
11
9
  bytes,
12
10
  clone,
@@ -18,18 +16,15 @@ import {
18
16
  import {
19
17
  activeContextStatus,
20
18
  automaticPreparationId,
21
- boundedOrientation,
22
19
  boundStatusPayload,
20
+ briefContractComplaint,
23
21
  commitPreparedFold,
24
- consolidationSourceText,
25
22
  descendantIds,
26
23
  encodedFoldSource,
27
- generatedBriefs,
28
24
  foldCandidatesDetail,
29
25
  foldTreeDetail,
30
26
  peekFoldSource,
31
27
  prepareFold,
32
- preparedFoldError,
33
28
  projectActiveContext,
34
29
  projectionSlateCandidates,
35
30
  protectEvidence,
@@ -52,6 +47,7 @@ import {
52
47
  latestProviderContextMeasurement,
53
48
  orderedRoots,
54
49
  parseNativeCompactionCompletion,
50
+ exactMapped,
55
51
  parseNativeCompactionDecision,
56
52
  parseProviderContextMeasurementReceipt,
57
53
  persistenceProjection,
@@ -103,31 +99,19 @@ import {
103
99
  COMMIT_RECLAIM_FLOOR_SHARE,
104
100
  CONTEXT_RECEIPT_BLOCK_BYTES,
105
101
  DEFAULT_CONTEXT_WINDOW,
106
- EPOCH_CONSOLIDATION_ROUNDS,
107
- MAX_THRESHOLD_NOTICES,
108
- THRESHOLD_NOTICE_SHARES,
109
102
  resolveGuidance,
110
103
  assertThresholdsServable,
111
104
  resolveThresholds,
112
105
  servingBudgetTokens,
113
106
  ESTIMATED_BYTES_PER_TOKEN,
114
107
  entryTypeNamespace,
115
- MAX_BRIEF_BATCH_SPANS,
116
- MAX_BRIEF_UPGRADE_QUEUE,
117
- MAX_BRIEF_UPGRADES_IN_FLIGHT,
118
108
  MAX_FOLD_SPAN_CHARS,
119
109
  MAX_PINNED_SHARE,
120
110
  MAX_WEDGE_ABSORB_TOKENS,
121
- OVERFLOW_RECOVERY_MAX_ATTEMPTS,
122
111
  PEEK_DEFAULT_MAX_BYTES,
123
112
  PEEK_MIN_SLICE_BYTES,
124
113
  PEEK_READ_ONLY_CONTEXT_ACTIONS,
125
114
  AUTO_FOLD_BLACKLIST_DEFAULT,
126
- SURFACING_BRIEF_HIT,
127
- SURFACING_CONTENT_HIT,
128
- SURFACING_DIVERGENCE_MARGIN,
129
- SURFACING_OUTCOME_WINDOW_ORDINALS,
130
- SURFACING_SLATE_SIZE,
131
115
  USER_RESCUE_MAX_SOURCE_CHARS,
132
116
  } from "./lib/policy.ts";
133
117
  import type {
@@ -136,7 +120,6 @@ import type {
136
120
  ActiveContextState,
137
121
  ActiveContextThresholds,
138
122
  ActiveContextToolAction,
139
- BriefProvenance,
140
123
  FoldCandidate,
141
124
  FoldKind,
142
125
  FoldRecordEntry,
@@ -148,16 +131,12 @@ import {
148
131
  import {
149
132
  contextReceipt,
150
133
  contextRiderText,
151
- curationSignals,
152
- lastCallText,
153
134
  markAwarenessText,
154
135
  receiptBlockText,
155
- thresholdNoticeText,
156
136
  withReceipt,
157
137
  } from "./lib/curation.ts";
158
138
  import type {
159
139
  ContextReceipt,
160
- CurationSignals,
161
140
  } from "./lib/curation.ts";
162
141
  import {
163
142
  addPendingMark,
@@ -165,7 +144,6 @@ import {
165
144
  commitPendingMarks,
166
145
  consolidationMarks,
167
146
  ephemeralPeekMarks,
168
- epochCommitDue,
169
147
  estimatedTokens,
170
148
  foldMarkFor,
171
149
  ladderSelectionMark,
@@ -184,10 +162,7 @@ import {
184
162
  withPendingMarks,
185
163
  } from "./lib/scheduling.ts";
186
164
  import {
187
- automaticToolBrief,
188
165
  candidateSpanChars,
189
- deterministicChapterCandidateBrief,
190
- deterministicConsolidationBrief,
191
166
  manualFoldCandidate,
192
167
  peekedSourceFoldIds,
193
168
  selectAutomaticToolBatch,
@@ -196,15 +171,6 @@ import {
196
171
  splitCandidateBySize,
197
172
  } from "./lib/selection.ts";
198
173
  import type { SpanCorrection } from "./lib/selection.ts";
199
- import {
200
- issueSurfacing,
201
- noteSurfacingAction,
202
- resolveSurfacing,
203
- selectSurfacingSlate,
204
- surfacingLedger,
205
- surfacingSilenced,
206
- surfacingSlateText,
207
- } from "./lib/surfacing.ts";
208
174
  import {
209
175
  compareProjections,
210
176
  emptyLedger,
@@ -234,17 +200,8 @@ import {
234
200
  unansweredToolCalls,
235
201
  } from "./lib/rollback.ts";
236
202
 
237
- /**
238
- * How a projection's token reading was reached.
239
- *
240
- * "anchored": the provider's own count for the projection this one extends, plus a rate
241
- * estimate of the bytes appended after it. "rewritten": the current projection does not
242
- * begin with the measured one, so there is nothing to add a delta to and the whole
243
- * projection is estimated. "unmeasured": no accepted provider count yet.
244
- */
245
203
  export type ProjectionReadingBasis = "anchored" | "rewritten" | "unmeasured";
246
204
 
247
- // Test seam only; the package API is registerPiFold because package.json exports block deep imports.
248
205
  export * from "./lib/canonical.ts";
249
206
  export * from "./lib/curation.ts";
250
207
  export * from "./lib/folding.ts";
@@ -255,13 +212,8 @@ export * from "./lib/policy.ts";
255
212
  export * from "./lib/rollback.ts";
256
213
  export * from "./lib/scheduling.ts";
257
214
  export * from "./lib/selection.ts";
258
- export * from "./lib/surfacing.ts";
259
215
  export * from "./lib/transcript.ts";
260
216
 
261
- /**
262
- * The batched fold request: several {span, brief} pairs in one call, with the single
263
- * `ids` form still accepted because it is the shape a status action hands back.
264
- */
265
217
  export interface BatchedMarkRequest {
266
218
  ids: string[];
267
219
  brief?: string;
@@ -295,37 +247,14 @@ export function batchedMarkRequests(params: Record<string, unknown>): BatchedMar
295
247
  }
296
248
 
297
249
  export function registerActiveContext(pi: any, options: {
298
- /**
299
- * INTERNAL brief-generator seam, not a public option: `registerPiFold` refuses the
300
- * name and builds the generator from `summarizer`. It stays a parameter because it
301
- * is the runtime's only brief-generator interface.
302
- */
303
- summarizeContextSpan?: (request: Record<string, unknown>, ctx: unknown) => Promise<Record<string, unknown>>;
304
- /**
305
- * INTERNAL deployment-identity seam, not public options: the package entry refuses all
306
- * five by name and the shipped identity is the one in `policy.ts`. They survive here
307
- * because the neutrality gate has to register a synthetic brand to prove none of it
308
- * reaches the defaults, and the experiment harness registers the pi-fold identity
309
- * explicitly so its sealed runs keep their entry types.
310
- */
311
250
  toolName?: string;
312
251
  toolLabel?: string;
313
252
  brandNoun?: string;
314
253
  entryTypePrefix?: string;
315
254
  commandNames?: { status?: string; fold?: string };
316
- /**
317
- * The auto-fold EXCEPTION list, empty by default: every completed tool batch folds
318
- * unmarked, and this names the tools whose results must stay raw.
319
- */
320
255
  blacklistAutoFoldTools?: ReadonlySet<string>;
321
- /** The serving budget itself, ALREADY NET of the deployment's output reservation. */
322
256
  providerInputBudget?: number;
323
- /**
324
- * The thermostat, set whole or not at all. USER policy: no agent action reads it back
325
- * as a mutable surface, and status reports the values without offering to change them.
326
- */
327
257
  thresholds?: ActiveContextThresholds;
328
- /** Both guidance surfaces, set together, defaulting on. */
329
258
  guidance?: Partial<ActiveContextGuidance>;
330
259
  }): {
331
260
  projectionCandidates: (ctx: any) => Array<Record<string, unknown>>;
@@ -335,11 +264,6 @@ export function registerActiveContext(pi: any, options: {
335
264
  const brandNoun = options.brandNoun ?? DEFAULT_ACTIVE_CONTEXT_BRAND_NOUN;
336
265
  const entryTypePrefix = options.entryTypePrefix ?? DEFAULT_ACTIVE_CONTEXT_ENTRY_TYPE_PREFIX;
337
266
  const blacklistAutoFoldTools = options.blacklistAutoFoldTools ?? AUTO_FOLD_BLACKLIST_DEFAULT;
338
- // Deleted options are REFUSED by name, never ignored. A deployment still passing one
339
- // believes it asked for something, and silence would hand it the opposite behavior:
340
- // `foldScheduling` chose between epoch and the deleted immediate scheduler,
341
- // `foldPeekResults` opted peek results out of the foldable classification, and
342
- // `toolActions` narrowed the action surface. All three are unconditional now.
343
267
  for (const removed of ["foldScheduling", "foldPeekResults", "toolActions"]) {
344
268
  if (Object.hasOwn(options, removed)) {
345
269
  throw new Error(`${removed} is no longer an option: epoch scheduling, peek foldability ` +
@@ -350,24 +274,12 @@ export function registerActiveContext(pi: any, options: {
350
274
  throw new Error("blockingTools is no longer an option: a tool call never causes a rewrite of " +
351
275
  "its own, and the commit epoch is the only path that mutates the projection");
352
276
  }
353
- // The per-request surfacing channel. `setProjectionProvider` was a second delivery
354
- // path for the value this call already returns, and `setSuggestionSourceRegistrar`
355
- // handed out registration into a carrier that no longer exists: the slate rode a
356
- // per-request ephemeral tail, which moved the prefix on every single pass. The
357
- // selector survives and returns at the commit boundary; the channel does not.
358
277
  for (const removed of ["setProjectionProvider", "setSuggestionSourceRegistrar"]) {
359
278
  if (Object.hasOwn(options, removed)) {
360
279
  throw new Error(`${removed} is no longer an option: projection candidates are returned by ` +
361
280
  "registration, and external suggestion sources have no carrier to render into");
362
281
  }
363
282
  }
364
- // The renamed options are refused by their OLD names, each pointing at the new one.
365
- // `readOnlyTools` and then `autoFoldableTools` were both ALLOW-lists, and the list runs
366
- // the other way now, so neither may be forwarded silently: an allow-list read as a
367
- // blacklist bars exactly the tools it meant to permit. `commandPrefix` derived two
368
- // command names from a stem the full-name override then overrode anyway;
369
- // `providerTotalWindow` was a gross window the runtime netted down with a GUESSED
370
- // reservation, and the guess is what the reshape deleted.
371
283
  for (const inverted of ["readOnlyTools", "autoFoldableTools"]) {
372
284
  if (Object.hasOwn(options, inverted)) {
373
285
  throw new Error(`${inverted} is now blacklistAutoFoldTools, and the sense is INVERTED: ` +
@@ -388,9 +300,6 @@ export function registerActiveContext(pi: any, options: {
388
300
  (!Number.isSafeInteger(options.providerInputBudget) || options.providerInputBudget <= 0)) {
389
301
  throw new Error("providerInputBudget must be a positive integer");
390
302
  }
391
- // The deployment's own fact, and the only capacity knob: declaring it makes every
392
- // ratio, fence and budget truthful, and leaving it out falls back to the provider
393
- // descriptor and SAYS "descriptor" in the capacity accounting.
394
303
  const providerInputBudget = options.providerInputBudget ?? null;
395
304
  const readOnlyContextActions = PEEK_READ_ONLY_CONTEXT_ACTIONS;
396
305
  if (!toolName || !toolLabel || !brandNoun || !entryTypePrefix ||
@@ -406,8 +315,6 @@ export function registerActiveContext(pi: any, options: {
406
315
  commandNames.status === commandNames.fold) {
407
316
  throw new Error("Active-context command names must be distinct kebab-case strings");
408
317
  }
409
- // The thermostat, validated atomically before anything else reads a threshold, and
410
- // then checked against the budget this deployment can actually serve.
411
318
  const thresholds = resolveThresholds(options.thresholds);
412
319
  assertThresholdsServable(thresholds, providerInputBudget ?? servingBudgetTokens(DEFAULT_CONTEXT_WINDOW));
413
320
  const guidance = resolveGuidance(options.guidance);
@@ -415,11 +322,8 @@ export function registerActiveContext(pi: any, options: {
415
322
  const foldRecordEntryType = `${entryTypePrefix}-fold-record`;
416
323
  const milestoneProjectionType = `${entryTypePrefix}-milestone`;
417
324
  const advisoryProjectionType = `${entryTypePrefix}-advisory`;
418
- const surfacingProjectionType = `${entryTypePrefix}-surfacing`;
419
325
  const receiptProjectionType = `${entryTypePrefix}-receipts`;
420
326
  const riderProjectionType = `${entryTypePrefix}-rider`;
421
- const lastCallProjectionType = `${entryTypePrefix}-lastcall`;
422
- const noticeProjectionType = `${entryTypePrefix}-notice`;
423
327
  const curationProjectionType = `${entryTypePrefix}-curation`;
424
328
  const entryNamespace = entryTypeNamespace(entryTypePrefix);
425
329
  const providerMeasurementEntryType = `${entryNamespace}-provider-context-measurement`;
@@ -439,8 +343,6 @@ export function registerActiveContext(pi: any, options: {
439
343
  persistenceDisposition: "none" | "record-only" | "state-committed";
440
344
  };
441
345
 
442
- // Owns in-memory/durable state and wire/record bookkeeping; persistenceQueue serializes it.
443
- // Once the state event succeeds, replay owns this exact state; RAM may not roll behind it.
444
346
  const persistence = {
445
347
  state: null as ActiveContextState | null,
446
348
  persisted: null as ActiveContextState | null,
@@ -450,7 +352,6 @@ export function registerActiveContext(pi: any, options: {
450
352
  persistenceQueue: Promise.resolve<void>(undefined),
451
353
  };
452
354
 
453
- // Owns preparation/ladder rollback, selection, and suspension; actionQueue serializes it.
454
355
  const ladder = {
455
356
  pendingManual: false,
456
357
  preparing: null as { id: string; controller: AbortController; promise: Promise<void> } | null,
@@ -461,102 +362,21 @@ export function registerActiveContext(pi: any, options: {
461
362
  lastSelectionSourceIds: [] as string[],
462
363
  pendingContextNote: null as string | null,
463
364
  lastAutomaticAction: null as Record<string, unknown> | null,
464
- /** What the last over-budget projection cost and whether the reduction saved it. */
465
365
  overBudgetReduction: null as Record<string, unknown> | null,
466
366
  automaticFailure: null as AutomaticFailureState | null,
467
- failedPreparations: new Set<string>(),
468
367
  actionQueue: Promise.resolve<unknown>(undefined),
469
368
  };
470
369
 
471
- /**
472
- * THE BRIEF UPGRADE LANE.
473
- *
474
- * A fold brief is model-written from this campaign forward; the deterministic brief is
475
- * what a failure leaves behind. The automatic ladder cannot wait for a generator: the
476
- * commit path is synchronous with a measured projection and a fold deferred until a
477
- * provider answers is a fold that does not happen. So the ladder commits deterministic,
478
- * a generator runs between boundaries, and the brief it writes lands as an UPGRADE
479
- * riding the next commit: the same law wedge absorption and the surfacing slate follow,
480
- * mutations only inside a rewrite the session already paid for.
481
- *
482
- * Everything here is process-local. An upgrade lost to a reload is a brief that stays
483
- * deterministic, which is exactly the failure the fallback exists for, and the state
484
- * wire keeps one shape instead of carrying work in progress.
485
- */
486
- const upgrades = {
487
- /**
488
- * BATCHES of folds committed deterministic, each holding the exact source its briefs
489
- * will cover. One batch is one generator call: a commit folds its spans together, so
490
- * they are briefed together, and the spans of one batch orient each other. Sending them
491
- * one at a time is what left the 2026-08-11 rep with 14 model briefs across 87 folds.
492
- */
493
- queue: [] as Array<{
494
- members: Array<{ foldId: string; sourceSha256: string }>;
495
- request: Record<string, unknown>;
496
- }>,
497
- /**
498
- * Generator calls in flight, keyed by every fold each one briefs, bounded by a constant
499
- * and cancel-safe on session change or shutdown. Keyed rather than counted because
500
- * the queue has to know a fold is already being briefed.
501
- */
502
- running: new Map<string, { controller: AbortController; promise: Promise<void> }>(),
503
- /** Written briefs waiting for a boundary. They never apply anywhere else. */
504
- ready: [] as Array<{ foldId: string; sourceSha256: string; brief: string; provenance: BriefProvenance }>,
505
- /** A generator that failed a fold does not get it back: one attempt, then deterministic stands. */
506
- failed: new Set<string>(),
507
- /**
508
- * Parents whose turn has not come: a group is read at depth one, so a child still
509
- * waiting on its own brief would be read through the sentence that brief is about to
510
- * replace. They are retried at every boundary and never dropped, because the wait ends
511
- * the moment the lane drains and a parent that was skipped once is a parent no
512
- * generator ever writes.
513
- */
514
- deferred: new Set<string>(),
515
- /** Failures since the last commit record carried them, so none of this is silent. */
516
- failures: 0,
517
- /**
518
- * Briefs that took a second ask before they met the contract. Counted because the cure
519
- * is the mechanism that lets the brief cap be a real limit rather than a truncation
520
- * point, so how often it fires is how we learn whether the cap is set anywhere near
521
- * right (Shane 2026-08-11).
522
- */
523
- cures: 0,
524
- lastError: null as string | null,
525
- };
526
-
527
- // Owns provider receipts, anchors, and usage; providerMeasurementQueue serializes receipt writes.
528
370
  const measurements = {
529
371
  latestRatio: null as number | null,
530
372
  lastProviderMeasurement: null as ProviderContextMeasurement | null,
531
- /** What the host/model descriptor last claimed, kept so the gap stays auditable. */
532
373
  descriptorWindow: null as number | null,
533
- /** Serialized size of the projection this process last handed the host. */
534
374
  lastProjectedChars: null as number | null,
535
- /**
536
- * Ground truth for the transmission fence: recent pairings of a projection's size
537
- * with the token count the provider reported for it. A fixed bytes-per-token
538
- * constant is a guess about a tokenizer, and it is wrong by different amounts in
539
- * different sessions -- measured 2026-08-06, 4.7 chars/token in rep11 and 7.0 in
540
- * rep12 for the SAME workload. It also DRIFTS within one session: rep13 moved
541
- * between 5.34 and 6.01 over its last twenty requests. Only the recent window
542
- * counts, and the fence reads it pessimistically.
543
- */
544
375
  projectionCalibrations: [] as Array<{ chars: number; tokens: number }>,
545
- /** What the fence estimated for the projection it last handed the host. */
546
376
  lastProjectedEstimate: null as number | null,
547
- /** Whether that estimate used a measured ratio rather than the bootstrap constant. */
548
377
  lastProjectedEstimateCalibrated: false,
549
- /** How that reading was reached, so an audit can tell an anchor from a fallback. */
550
378
  lastProjectedEstimateBasis: "unmeasured" as ProjectionReadingBasis,
551
- /** That projection's own size at one rate, the baseline a reduction is measured from. */
552
379
  lastProjectedSizeTokens: null as number | null,
553
- /**
554
- * The provider's own count for the last projection this process TRANSMITTED, held
555
- * with that projection's serialized text so a later projection can be tested against
556
- * it by construction. `head` is the serialization minus its closing bracket, which is
557
- * what makes "the same projection with more appended after it" a byte-exact prefix
558
- * test rather than a size comparison.
559
- */
560
380
  projectionAnchor: null as {
561
381
  tokens: number;
562
382
  chars: number;
@@ -565,11 +385,8 @@ export function registerActiveContext(pi: any, options: {
565
385
  sessionId: string;
566
386
  generation: number;
567
387
  } | null,
568
- /** Signed estimator error against recent measurements, as a share of measured tokens. */
569
388
  estimatorErrors: [] as number[],
570
- /** Growth in measured tokens between consecutive requests. */
571
389
  inflowSteps: [] as number[],
572
- /** Growth steps the OUTPUT WALL reads. Separate from `inflowSteps` on purpose: see noteWallInflow. */
573
390
  wallInflowSteps: [] as number[],
574
391
  providerMeasurementQueue: Promise.resolve<void>(undefined),
575
392
  providerMeasurementReceipts: new Set<string>(),
@@ -578,142 +395,79 @@ export function registerActiveContext(pi: any, options: {
578
395
  providerMeasurementAnchorByMessageSha: new Map<string, ProviderMeasurementAnchor>(),
579
396
  };
580
397
 
581
- // Owns the projection/cache ledger. Nothing here is durable: it is telemetry about
582
- // this process's own projections, rebuilt from scratch on every load.
583
398
  const instrumentation = {
584
399
  ledger: emptyLedger(),
585
400
  previousDigests: null as string[] | null,
586
- /** The previous TRANSMITTED projection, for the byte-level prefix comparison. */
587
401
  previousText: null as string | null,
588
402
  lastChange: "append" as ProjectionChange,
589
- /** Share of the PREVIOUS prompt the last projection kept, for miss attribution. */
590
403
  lastPreservedShare: null as number | null,
591
- /** Events emitted since the last handoff, which is the attribution candidate set. */
592
404
  sinceHandoff: [] as Array<{ seq: number; kind: string }>,
593
- /** Structural mutations emitted since the last handoff. The per-generation budget. */
594
405
  mutationsSinceHandoff: 0,
595
- /** Provider responses this session, so event SPACING is readable from the stream. */
596
406
  requests: 0,
597
407
  lastMutationRequest: 0,
598
408
  lastMutationTokens: null as number | null,
409
+ // WHAT THE SESSION SPENDS DERIVING ITSELF, cumulative for the process.
410
+ //
411
+ // Every lifecycle event remaps the whole branch, so the cost of a turn is not the
412
+ // cost of one derivation: it is however many the handlers happen to run. Measuring
413
+ // it at the two entry points and carrying the running totals on the projection means
414
+ // a consumer differences consecutive projections for the per-request cost and reads
415
+ // the last one for the exact session total. That is a SUM. The alternative, taking
416
+ // one terminal derivation and multiplying by the request count, treats every early
417
+ // request as though the session were already at its final size, which is invalid
418
+ // precisely when growth is the thing under study.
419
+ //
420
+ // These are process counters, not state. A rollback does not return the CPU, so they
421
+ // do not roll back either.
422
+ derivations: 0,
423
+ deriveMs: 0,
424
+ derivationHits: 0,
599
425
  };
600
- /**
601
- * MECHANISM 1. The frozen surface.
602
- *
603
- * Between fold events the projection is byte-frozen: the only change a context action
604
- * may cause is the append of its own tool result at the tail. Rep 17 measured every
605
- * single context attempt landing as a projection REWRITE -- status 0.60-0.90 prefix
606
- * identity, peek 0.96, the held gate down to 0.013 -- because the surface answered
607
- * each one by re-rendering blocks the agent had already paid to cache. Provider prefix
608
- * caches are positional, so each of those refreshes was a full or partial cache kill.
609
- *
610
- * `body` is the last rebuilt fold projection and `projection` is that body plus the
611
- * carriers appended to it. While the rebuilt body still starts with `body` verbatim,
612
- * nothing structural moved, so the previous projection is reused WHOLE and only the
613
- * newly arrived raw messages are appended after it. A carrier whose key is already in
614
- * the window is never re-rendered; a fold event, a reveal or an overflow recovery
615
- * diverges the body and takes the sanctioned rewrite.
616
- */
617
426
  const freeze = {
618
427
  body: null as unknown[] | null,
619
428
  bodyText: null as string | null,
620
429
  projection: null as unknown[] | null,
621
430
  keys: new Set<string>(),
622
- /** True only while assembling a pass that reused the frozen projection. */
623
431
  active: false,
624
432
  };
625
- /**
626
- * A carrier may be built exactly once per freeze window. This is checked BEFORE the
627
- * builder runs, because building a milestone spends its delivery budget and building
628
- * a reminder advances the reminder cursor: a carrier that cannot land must not pay.
629
- */
630
433
  const carrierAdmitted = (key: string): boolean => {
631
434
  if (freeze.active && freeze.keys.has(key)) return false;
632
435
  freeze.keys.add(key);
633
436
  return true;
634
437
  };
635
438
 
636
- // Owns the guided-curation gate, the receipt ring, the context-event stream, and the
637
- // overflow recovery lane. Nothing here is durable session STATE: it describes what
638
- // this process did to the live window, and the durable copy is the appended
639
- // instrumentation entry, which is what an external adjudicator reads.
640
439
  const curation = {
641
440
  receipts: [] as ContextReceipt[],
642
- /** Every context-management tool call this session. */
643
441
  contextCalls: 0,
644
- /** The last measurement the commit trigger took, reported by status. */
645
- lastSignals: null as CurationSignals | null,
646
- /**
647
- * COMMIT REOPEN HYSTERESIS. The eligible foldable share measured just after the last
648
- * triggered commit, or null when the trigger is free to fire. Measured 2026-08-07
649
- * (rep 17): occupancy plateaued at 0.85-0.92 of the truthful budget for the final
650
- * third of the run, and the trigger fired ten times over a window whose foldable mass
651
- * had not changed. A plateau is not an event. The trigger re-arms only once occupancy
652
- * falls back under it and crosses again, or once a reclaim floor of eligible mass is
653
- * NEW. This outlived the announcement it was built beside: it bounds how often the
654
- * runtime rewrites the projection, which is the whole cost model.
655
- */
656
- reopenBaselineShare: null as number | null,
657
- /** Whether the output wall's crossing has already spent its one forced commit. */
658
442
  wallEpisodeOpen: false,
659
- /**
660
- * Where the armed last-call actually LANDED: the exposure it rendered and the
661
- * ordinal of the pass that rendered it. In-memory on purpose: after a reload the
662
- * carrier re-renders on the first projection, this re-arms, and the commit waits
663
- * one more round rather than firing on a prompt nobody saw.
664
- */
665
- lastCallDelivery: null as { exposure: number; ordinal: number } | null,
666
- /** Recovery attempts spent on the CURRENT inflow; reset by any accepted request. */
667
443
  recoveryAttempts: 0,
668
- /** A provider rejection observed but not yet recovered from. */
669
444
  pendingRejection: null as { status: number; ordinal: number } | null,
670
445
  lastRecovery: null as Record<string, unknown> | null,
671
446
  instrumentationQueue: Promise.resolve<void>(undefined),
672
447
  };
673
448
 
674
- /**
675
- * The tree-rollback lane.
676
- *
677
- * Armed once per session against the pi surfaces it calls, because every one of them
678
- * is an internal the extension contract does not promise. Disarmed, the lane is OFF
679
- * and says so on the record: an overflow still emits `context.rollback` with
680
- * `armed: false` and the reason, the user is notified, and the session behaves
681
- * exactly as it did before this build -- the projection-budget fence aborts an
682
- * over-budget request rather than half-performing a recovery.
683
- */
684
449
  const rollback = {
685
450
  probes: null as ReturnType<typeof probeRollbackSurfaces> | null,
686
451
  armed: false,
687
- /** pi's own overflow classifier, resolved from the host; null when unreachable. */
688
452
  classifier: null as ((message: unknown, contextWindow: number) => boolean) | null,
689
453
  classifierSource: null as string | null,
690
- /** Ordinals of episodes handled, so the one-shot and the ledger agree. */
691
454
  attempts: 0,
692
455
  last: null as Record<string, unknown> | null,
693
- /** An overflow seen at message_end and not yet claimed by the compaction event. */
694
456
  pendingOverflow: null as { at: number; entryId: string | null } | null,
695
457
  };
696
458
 
697
- // Owns advisory arming and hard-fence delivery; durable effects use persistenceQueue.
698
459
  const advisory = {
699
460
  hardFenceNoticeKey: null as string | null,
700
461
  hardFenceReleaseSessionId: null as string | null,
701
462
  hardFenceReleasedProjectionKeys: new Set<string>(),
702
463
  };
703
464
 
704
- // Owns native-compaction decisions and completion retry state; nativeReceiptQueue serializes it.
705
465
  const nativeCompaction = {
706
466
  lastThresholdDecision: null as Record<string, unknown> | null,
707
467
  pendingNativeReceipt: null as NativeCompactionCompletionReceipt | null,
708
468
  nativeReceiptQueue: Promise.resolve<void>(undefined),
709
469
  };
710
470
 
711
- // Owns session generation, snapshots/reloads, and per-turn blocking-tool harvest state.
712
- // Pi normally requests context serially, but retries, reloads, and host
713
- // integrations can overlap callbacks. Serialize the entire authority →
714
- // preparation → commit → projection transaction so a follower cannot
715
- // observe a published measurement before the leader's durable receipt or
716
- // return raw final-rung context while the leader is preparing a brief.
717
471
  const lifecycle = {
718
472
  generation: 0,
719
473
  shuttingDown: false,
@@ -750,16 +504,34 @@ export function registerActiveContext(pi: any, options: {
750
504
  lifecycle.latestSnapshot ? markOrdinal(lifecycle.latestSnapshot) : 0;
751
505
 
752
506
  /**
753
- * Emit one record into THE context event stream, in the ledger AND as a durable
754
- * session entry. An in-memory ledger is invisible to an analyst reading session
755
- * artifacts, and telemetry may never block or fail the action it describes.
756
- */
757
- /**
758
- * Open a pass's mutation budget. ONE structural mutation per pass is the budget: the
759
- * rep-15 defect was a second commit inside the SAME pass, after the first had already
760
- * rebuilt the projection, so the counter is armed wherever a pass begins.
507
+ * ONE DERIVATION PER DISTINCT BRANCH, WITHIN ONE PASS.
508
+ *
509
+ * A lifecycle pass asks for the authoritative snapshot repeatedly: the fence asks, the
510
+ * ladder asks, the accounting asks, the status surface asks. Instrumented on a fixture,
511
+ * a single request cost up to TEN derivations, and a derivation remaps the entire
512
+ * branch. On sol-20260813-paired rep 2 one of those cost 18.5 seconds.
513
+ *
514
+ * The memo is deliberately the SMALLEST one that is airtight rather than the largest
515
+ * one that would pay. It lives for exactly one pass and is dropped at the start of the
516
+ * next, so nothing it holds can outlive the moment it was true. Within a pass the only
517
+ * way the branch changes is by APPENDING, which moves a length, so keying on the two
518
+ * lengths and the window catches every change that can occur. A cache that had to
519
+ * reason about entries being replaced underneath it would be the kind of guard this
520
+ * project does not keep; this one cannot face that question.
761
521
  */
762
- const beginMutationPass = (): void => { instrumentation.mutationsSinceHandoff = 0; };
522
+ const derivationMemo = {
523
+ key: null as string | null,
524
+ snapshot: null as ActiveContextSnapshot | null,
525
+ };
526
+ const dropDerivationMemo = (): void => {
527
+ derivationMemo.key = null;
528
+ derivationMemo.snapshot = null;
529
+ };
530
+
531
+ const beginMutationPass = (): void => {
532
+ instrumentation.mutationsSinceHandoff = 0;
533
+ dropDerivationMemo();
534
+ };
763
535
 
764
536
  const emit = (kind: ContextEventKind, payload: Record<string, unknown> = {}): ContextEvent => {
765
537
  const record = recordContextEvent(instrumentation.ledger, kind, {
@@ -771,114 +543,12 @@ export function registerActiveContext(pi: any, options: {
771
543
  instrumentation.sinceHandoff.push({ seq: record.seq, kind });
772
544
  const operation = curation.instrumentationQueue.then(async () => {
773
545
  try { await pi.appendEntry(contextEventEntryType, record); }
774
- catch { /* Telemetry is never a lifecycle boundary. */ }
546
+ catch { }
775
547
  });
776
548
  curation.instrumentationQueue = operation.then(() => undefined, () => undefined);
777
549
  return record;
778
550
  };
779
551
 
780
- /**
781
- * The generator, wrapped once so every brief it writes is on the record.
782
- *
783
- * Wrapping HERE rather than instrumenting the two call sites is deliberate. The inline
784
- * path in `prepareFold` and the async upgrade lane both receive this function, so one
785
- * wrapper covers both, no signature changes and no way to add a third caller that
786
- * quietly escapes the ledger. It also covers a deployment's OWN summarizer, which is
787
- * the case a call-site patch would have missed.
788
- *
789
- * A generator call is invisible everywhere else: it runs outside the session, so it
790
- * lands in no provider ledger, and it runs off the turn, so it lands in no turn timing.
791
- * Duration, queue wait and usage are therefore recorded here or nowhere.
792
- *
793
- * A failure is emitted and rethrown unchanged. This observes; it decides nothing, and
794
- * the fallback to the deterministic brief stays exactly where it was.
795
- */
796
- const observedSummarize = options.summarizeContextSpan
797
- ? async (request: Record<string, unknown>, summarizerCtx: unknown): Promise<Record<string, unknown>> => {
798
- const startedAt = Date.now();
799
- const queuedAt = typeof request.queuedAtMs === "number" ? request.queuedAtMs : null;
800
- const spans = Array.isArray(request.spans)
801
- ? request.spans as Array<Record<string, unknown>>
802
- : null;
803
- const sourceText = typeof request.sourceText === "string" ? request.sourceText : "";
804
- // A span is a CONSOLIDATION when it is a group of folds, and an automatic fold
805
- // otherwise. Both kinds are counted and both kinds' source is measured, because a
806
- // call can carry a mix and the honest way to attribute its tokens across kinds is by
807
- // the share of source each kind contributed, never by pretending the call was one
808
- // kind (Shane 2026-08-11: track cures and tokens by fold type).
809
- const groupSpan = (span: Record<string, unknown>): boolean =>
810
- Number.isInteger(span.children) && (span.children as number) > 1;
811
- const charsOf = (span: Record<string, unknown>): number =>
812
- typeof span.sourceText === "string" ? span.sourceText.length : 0;
813
- const kindCounts = spans
814
- ? {
815
- spans: spans.length,
816
- group_spans: spans.filter(groupSpan).length,
817
- leaf_spans: spans.filter((span) => !groupSpan(span)).length,
818
- group_source_chars: spans.filter(groupSpan).reduce((sum, span) => sum + charsOf(span), 0),
819
- leaf_source_chars: spans.filter((span) => !groupSpan(span))
820
- .reduce((sum, span) => sum + charsOf(span), 0),
821
- fold_ids: spans.map((span) => typeof span.candidateId === "string" ? span.candidateId : ""),
822
- }
823
- : {
824
- spans: 1,
825
- group_spans: groupSpan(request) ? 1 : 0,
826
- leaf_spans: groupSpan(request) ? 0 : 1,
827
- group_source_chars: groupSpan(request) ? sourceText.length : 0,
828
- leaf_source_chars: groupSpan(request) ? 0 : sourceText.length,
829
- };
830
- const base = {
831
- fold_id: typeof request.candidateId === "string" ? request.candidateId : "",
832
- source_chars: spans ? spans.reduce((sum, span) => sum + charsOf(span), 0) : sourceText.length,
833
- source_sha256: typeof request.sourceSha256 === "string" ? request.sourceSha256 : sha256Text(sourceText),
834
- ...kindCounts,
835
- // The second ask, not the first. How often this fires is how we learn whether the
836
- // brief cap is anywhere near right, so it is a field rather than an inference.
837
- cure: typeof request.cure === "string" && request.cure.length > 0,
838
- ...(queuedAt === null ? {} : { queued_ms: Math.max(0, startedAt - queuedAt) }),
839
- };
840
- try {
841
- const result = await options.summarizeContextSpan!(request, summarizerCtx);
842
- const written = Array.isArray(result?.briefs)
843
- ? (result.briefs as unknown[]).map((item) => typeof item === "string" ? item.trim() : "")
844
- : [typeof result?.brief === "string" ? result.brief.trim() : ""];
845
- emit("context.brief", {
846
- ...base,
847
- outcome: "ok",
848
- duration_ms: Date.now() - startedAt,
849
- provider: typeof result?.provider === "string" ? result.provider : "",
850
- model: typeof result?.model === "string" ? result.model : "",
851
- effort: typeof result?.effort === "string" ? result.effort : "",
852
- brief_chars: written.reduce((sum, item) => sum + item.length, 0),
853
- // Per span, so a batch where one brief came back empty is visible as that rather
854
- // than as a slightly short total.
855
- brief_chars_each: written.map((item) => item.length),
856
- brief_sha256: written.length === 1 && written[0] ? sha256Text(written[0]) : "",
857
- // Absent when the provider reported none. Never defaulted: a call whose cost we
858
- // do not know and a call that cost nothing are different facts.
859
- usage: result?.usage && typeof result.usage === "object" ? clone(result.usage) : null,
860
- });
861
- return result;
862
- } catch (error) {
863
- const message = error instanceof Error ? error.message : String(error);
864
- emit("context.brief", {
865
- ...base,
866
- // A timeout is not a refusal and not a provider fault, and telling them apart is
867
- // the difference between raising the bound and changing the generator.
868
- outcome: /exceeded \d+ms/.test(message) ? "timeout" : "error",
869
- duration_ms: Date.now() - startedAt,
870
- error: boundReceiptText(message, 240, "brief generator"),
871
- });
872
- throw error;
873
- }
874
- }
875
- : undefined;
876
-
877
- /**
878
- * Actions of ours that move bytes at or before a prefix position. Receipts, gate
879
- * notices and suggestions are appended after the whole projection, so they can only
880
- * move the tail and are never a prefix cause.
881
- */
882
552
  const PREFIX_MUTATING_KINDS: ReadonlySet<string> = new Set([
883
553
  "context.commit", "context.fold", "context.absorb", "context.split", "context.recovery",
884
554
  ]);
@@ -901,7 +571,7 @@ export function registerActiveContext(pi: any, options: {
901
571
  };
902
572
 
903
573
  const safeNotify = (ctx: any, message: string, level: "info" | "warning" | "error"): void => {
904
- try { ctx.ui?.notify?.(message, level); } catch { /* Presentation cannot block Pi lifecycle progress. */ }
574
+ try { ctx.ui?.notify?.(message, level); } catch { }
905
575
  };
906
576
 
907
577
  const contextSessionMatches = (ctx: any, sessionId: string): boolean => {
@@ -922,34 +592,14 @@ export function registerActiveContext(pi: any, options: {
922
592
  : " · provider usage unmeasured";
923
593
  const suspended = ladder.automaticFailure ? " · automatic suspended" : "";
924
594
  ctx.ui?.setStatus?.(entryTypePrefix, `${toolName} folds: ${roots}${prepared}${usage}${suspended}`);
925
- } catch { /* Status presentation is request-ephemeral and never a lifecycle boundary. */ }
595
+ } catch { }
926
596
  };
927
597
 
928
- /**
929
- * The number every ratio, fence and budget is computed against. Declared, it is the
930
- * deployment's own serving budget, already net of whatever output reservation it holds
931
- * back; undeclared, it is the per-request max-input descriptor, which bakes in a full
932
- * output reservation the deployment never asked for and so aborts requests inside real
933
- * headroom. The descriptor is still read, and still reported, so the gap stays
934
- * auditable rather than assumed.
935
- */
936
598
  const budgetWindowFor = (ctx: any): number | null => {
937
- // Remembered so the ctx-free callers (trigger, gate, reminders, advisory) report the
938
- // same descriptor gap the fence does instead of re-reading a second source.
939
599
  measurements.descriptorWindow = contextWindowFor(ctx);
940
600
  return providerInputBudget ?? measurements.descriptorWindow;
941
601
  };
942
602
 
943
- /**
944
- * THE serving budget. One resolution, one formula, one value.
945
- *
946
- * Every consumer -- the curation trigger, the last-call gate, the sparse reminders,
947
- * the transmission fence, the projection estimator and every instrumentation record --
948
- * reads this. Measured 2026-08-06 (rep 15): the trigger and gate ran a whole run
949
- * against a 272,000-token per-request DESCRIPTOR (budget 255,616) while the fence used
950
- * the truthful 383,616, because the same arithmetic lived in three places. A second
951
- * copy of this formula is the defect; there is now only one.
952
- */
953
603
  const servingCapacity = (window: number | null): ReturnType<typeof capacityAccounting> =>
954
604
  capacityAccounting({
955
605
  window: window ?? lifecycle.latestSnapshot?.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
@@ -961,7 +611,23 @@ export function registerActiveContext(pi: any, options: {
961
611
  const currentCapacity = (ctx: any): ReturnType<typeof capacityAccounting> =>
962
612
  servingCapacity(budgetWindowFor(ctx));
963
613
 
964
- const snapshotForEvent = (ctx: any, messages: unknown[]): ActiveContextSnapshot => mapActiveContext({
614
+ /**
615
+ * The one place a derivation is timed. Both entry points route through it, so the
616
+ * counters cannot drift from the work: a new call site that forgets to time itself
617
+ * would have to call `mapActiveContext` directly, which nothing outside these two
618
+ * functions does.
619
+ */
620
+ const timedDerivation = (derive: () => ActiveContextSnapshot): ActiveContextSnapshot => {
621
+ const started = Date.now();
622
+ try { return derive(); }
623
+ finally {
624
+ instrumentation.derivations += 1;
625
+ instrumentation.deriveMs += Date.now() - started;
626
+ }
627
+ };
628
+
629
+ const snapshotForEvent = (ctx: any, messages: unknown[]): ActiveContextSnapshot =>
630
+ timedDerivation(() => mapActiveContext({
965
631
  sessionId: ctx.sessionManager.getSessionId(),
966
632
  eventMessages: messages,
967
633
  contextEntries: ctx.sessionManager.buildContextEntries(),
@@ -973,27 +639,37 @@ export function registerActiveContext(pi: any, options: {
973
639
  contextWindow: budgetWindowFor(ctx) ?? undefined,
974
640
  netBudget: providerInputBudget !== null,
975
641
  thresholds,
976
- });
642
+ }));
977
643
 
978
644
  const authoritativeSnapshotFor = (ctx: any): ActiveContextSnapshot => {
979
645
  const sessionId = ctx.sessionManager.getSessionId();
980
646
  if (!lifecycle.latestSnapshot || lifecycle.latestSnapshot.sessionId !== sessionId) {
981
647
  throw new Error("A current same-session Pi context event is required");
982
648
  }
983
- return mapActiveContext({
649
+ const entries = ctx.sessionManager.buildContextEntries();
650
+ const window = budgetWindowFor(ctx) ?? undefined;
651
+ const key = `${sessionId}:${entries.length}:${lifecycle.latestSnapshot.messages.length}:${window}`;
652
+ if (derivationMemo.snapshot && derivationMemo.key === key) {
653
+ instrumentation.derivationHits += 1;
654
+ return derivationMemo.snapshot;
655
+ }
656
+ const derived = timedDerivation(() => mapActiveContext({
984
657
  sessionId,
985
658
  eventMessages: lifecycle.latestSnapshot.messages,
986
- contextEntries: ctx.sessionManager.buildContextEntries(),
659
+ contextEntries: entries,
987
660
  policy: lifecycle.latestSnapshot.policy,
988
661
  toolName,
989
662
  brandNoun,
990
663
  entryTypePrefix,
991
664
  blacklistAutoFoldTools,
992
665
  readOnlyContextActions,
993
- contextWindow: budgetWindowFor(ctx) ?? undefined,
666
+ contextWindow: window,
994
667
  netBudget: providerInputBudget !== null,
995
668
  thresholds,
996
- });
669
+ }));
670
+ derivationMemo.key = key;
671
+ derivationMemo.snapshot = derived;
672
+ return derived;
997
673
  };
998
674
 
999
675
  const providerMeasurementBranchIndex = (
@@ -1036,7 +712,6 @@ export function registerActiveContext(pi: any, options: {
1036
712
  lifecycle.generation += 1;
1037
713
  lifecycle.shuttingDown = false;
1038
714
  cancelPreparation();
1039
- cancelBriefUpgrades();
1040
715
  lifecycle.latestSnapshot = null;
1041
716
  lifecycle.latestSnapshotError = null;
1042
717
  measurements.latestRatio = null;
@@ -1064,15 +739,12 @@ export function registerActiveContext(pi: any, options: {
1064
739
  instrumentation.mutationsSinceHandoff = 0;
1065
740
  curation.receipts = [];
1066
741
  curation.contextCalls = 0;
1067
- curation.lastSignals = null;
1068
- curation.reopenBaselineShare = null;
1069
742
  curation.recoveryAttempts = 0;
1070
743
  curation.pendingRejection = null;
1071
744
  curation.lastRecovery = null;
1072
745
  ladder.lastAutomaticAction = null;
1073
746
  ladder.automaticFailure = null;
1074
747
  advisory.hardFenceNoticeKey = null;
1075
- ladder.failedPreparations.clear();
1076
748
  measurements.providerMeasurementReceipts.clear();
1077
749
  measurements.providerMeasurementRevisionByMessageSha.clear();
1078
750
  measurements.providerMeasurementByMessageSha.clear();
@@ -1159,11 +831,31 @@ export function registerActiveContext(pi: any, options: {
1159
831
  const operation = persistence.persistenceQueue.then(async () => {
1160
832
  if (!persistence.state || !persistence.persisted) return;
1161
833
  let next = clone(persistence.state);
834
+ const persistedFoldIds = new Set(persistence.persisted.folds.map((fold) => fold.id));
835
+ const arrivingFoldIds = next.folds.filter((fold) => !persistedFoldIds.has(fold.id)).map((fold) => fold.id);
836
+ const foldsInMemory = next.folds.length;
837
+ let projectionSnapshot: ActiveContextSnapshot | null = null;
1162
838
  if (ctx && lifecycle.latestSnapshot?.sessionId === next.sessionId) {
1163
- next = persistenceProjection(next, authoritativeSnapshotFor(ctx));
839
+ projectionSnapshot = authoritativeSnapshotFor(ctx);
840
+ next = persistenceProjection(next, projectionSnapshot);
1164
841
  }
1165
842
  next.folds = normalizeFoldsForPersistedRecords(next.folds, persistence.persistedFoldRecords);
1166
843
  if (sameStateProjection(next, persistence.persisted)) {
844
+ if (arrivingFoldIds.length) {
845
+ const lost = clone(persistence.state).folds.find((fold) => fold.id === arrivingFoldIds[0]);
846
+ const lostRefs = lost ? flattenFoldRefs(lost, persistence.state) : [];
847
+ const unresolved = projectionSnapshot
848
+ ? lostRefs.filter((ref) => !exactMapped(projectionSnapshot!, ref)).length
849
+ : null;
850
+ throw new Error(
851
+ `Active-context commit discarded at persistence: ${arrivingFoldIds.length} arriving fold(s) ` +
852
+ `did not survive the persistence projection (${foldsInMemory} in memory, ` +
853
+ `${next.folds.length} durable) at revision ${persistence.state.revision}; ` +
854
+ `first ${arrivingFoldIds[0]} with ${unresolved ?? "unknown"} of ${lostRefs.length} refs ` +
855
+ `unmapped against a ${projectionSnapshot?.mapped.length ?? 0}-message, ` +
856
+ `${projectionSnapshot?.branchObjects.length ?? 0}-object projection snapshot`,
857
+ );
858
+ }
1167
859
  persistence.state = clone(persistence.persisted);
1168
860
  return;
1169
861
  }
@@ -1261,7 +953,6 @@ export function registerActiveContext(pi: any, options: {
1261
953
  occurredAt: Date.now(),
1262
954
  }, sessionId);
1263
955
  await pi.appendEntry(providerMeasurementEntryType, receipt);
1264
- // The append is authoritative even if lifecycle attribution changes immediately after it.
1265
956
  measurements.providerMeasurementReceipts.add(receiptKey);
1266
957
  measurements.providerMeasurementRevisionByMessageSha.set(measurement.messageSha256, revision);
1267
958
  measurements.providerMeasurementByMessageSha.set(measurement.messageSha256, receipt);
@@ -1476,10 +1167,7 @@ export function registerActiveContext(pi: any, options: {
1476
1167
  let selection: Record<string, unknown> = { kind: lifecyclePhase };
1477
1168
  try {
1478
1169
  if (persistence.state && snapshot && ratio !== null) {
1479
- const selected = selectAutomaticRung(snapshot, persistence.state, ratio, {
1480
- summarizerAvailable: Boolean(options.summarizeContextSpan),
1481
- failedPreparationIds: ladder.failedPreparations,
1482
- });
1170
+ const selected = selectAutomaticRung(snapshot, persistence.state, ratio);
1483
1171
  if (selected?.kind === "refold") {
1484
1172
  selection = { kind: "refold", foldId: selected.foldId };
1485
1173
  } else if (selected && "candidate" in selected) {
@@ -1524,6 +1212,25 @@ export function registerActiveContext(pi: any, options: {
1524
1212
  ladder.boundaryFailure = message;
1525
1213
  cancelPreparation();
1526
1214
  if (persistence.state?.prepared) persistence.state = clearPrepared(persistence.state);
1215
+ const firstFailure = !ladder.automaticFailure;
1216
+ if (firstFailure || ladder.automaticFailure!.message !== message) {
1217
+ emit("context.suspend", {
1218
+ phase,
1219
+ error: message,
1220
+ error_name: error instanceof Error ? error.name : typeof error,
1221
+ disposition: firstFailure ? persistenceDisposition : ladder.automaticFailure!.persistenceDisposition,
1222
+ outcome: "suspended",
1223
+ repeat: !firstFailure,
1224
+ suppressed_callbacks: ladder.automaticFailure?.suppressedCallbacks ?? 0,
1225
+ state_revision: persistence.state?.revision ?? null,
1226
+ durable_revision: persistence.persisted?.revision ?? null,
1227
+ folds_in_memory: persistence.state?.folds.length ?? null,
1228
+ folds_durable: persistence.persisted?.folds.length ?? null,
1229
+ fold_records_durable: persistence.persistedFoldRecords.size,
1230
+ pending_marks: persistence.state?.pendingMarks?.length ?? 0,
1231
+ key: firstFailure ? key : ladder.automaticFailure!.key,
1232
+ });
1233
+ }
1527
1234
  if (ladder.automaticFailure) {
1528
1235
  ladder.automaticFailure.suppressedCallbacks = Math.min(
1529
1236
  Number.MAX_SAFE_INTEGER,
@@ -1553,12 +1260,6 @@ export function registerActiveContext(pi: any, options: {
1553
1260
  const measuredRevision = measurements.lastProviderMeasurement
1554
1261
  ? measurements.providerMeasurementRevisionByMessageSha.get(measurements.lastProviderMeasurement.messageSha256)
1555
1262
  : undefined;
1556
- // A durable projection topology after the measured response gets exactly
1557
- // one provider attempt so its fold can be measured. Concurrent
1558
- // callbacks, retries, and same-session reloads may not repeatedly release
1559
- // that unmeasured projection. Non-structural state persistence does not
1560
- // spend this release. A failed automatic transaction never gets this
1561
- // escape, even if a record/state append preceded its projection failure.
1562
1263
  if (allowUnmeasuredRevisionRelease && !ladder.automaticFailure &&
1563
1264
  measuredRevision !== undefined && measurements.lastProviderMeasurement &&
1564
1265
  !durableProviderMeasurementMatches(measurements.lastProviderMeasurement)) {
@@ -1591,10 +1292,6 @@ export function registerActiveContext(pi: any, options: {
1591
1292
  "error",
1592
1293
  );
1593
1294
  }
1594
- // Stock Pi exposes abort() in every extension event context. Calling it
1595
- // here aborts the signal passed to the provider stream after this context
1596
- // transform returns, so exact raw Pi messages remain canonical but are not
1597
- // transmitted as an overflowing request.
1598
1295
  if (typeof ctx.abort !== "function") {
1599
1296
  throw new Error(`Pi hard-fence abort capability is unavailable at ratio ${measurements.latestRatio}`);
1600
1297
  }
@@ -1602,40 +1299,18 @@ export function registerActiveContext(pi: any, options: {
1602
1299
  return true;
1603
1300
  };
1604
1301
 
1605
- /**
1606
- * Bytes per token, measured rather than assumed.
1607
- *
1608
- * `ESTIMATED_BYTES_PER_TOKEN` is a constant over RAW text, and the fence weighs a
1609
- * SERIALIZED projection: roles, ids, custom types and JSON escaping all count toward
1610
- * the bytes and none of them reach the provider's tokenizer the same way. Measured
1611
- * 2026-08-06 on one workload: rep11 ran at 4.7 serialized chars per measured token
1612
- * and rep12 at 7.0. Against the fixed 4 that is a 76% over-estimate in rep12, which
1613
- * is exactly how a session whose real window was 49% full (187,805 tokens of a
1614
- * 400,000 window, ratio 0.47) had its request judged over a 383,616-token budget,
1615
- * reduced, judged over again, and finally ABORTED at stage 37 of 64.
1616
- *
1617
- * So the ratio is calibrated per session against ground truth: the size of a
1618
- * projection this process handed the host, paired with the token count the provider
1619
- * reported for it. Tiny early requests are ignored -- a 466-char first projection
1620
- * measured against a system prompt gives a meaningless 0.46 -- and the result is
1621
- * bounded, so a pathological pairing can neither disable the fence nor trip it.
1622
- */
1623
1302
  const PROJECTION_CALIBRATION_MIN_CHARS = 20_000;
1624
1303
  const PROJECTION_CALIBRATION_MIN_TOKENS = 5_000;
1625
1304
  const PROJECTION_CHARS_PER_TOKEN_FLOOR = 2;
1626
1305
  const PROJECTION_CHARS_PER_TOKEN_CEILING = 12;
1627
- /** How many recent pairings the ratio, the error window and the inflow window keep. */
1628
1306
  const PROJECTION_CALIBRATION_WINDOW = 6;
1629
1307
  const PROJECTION_ERROR_WINDOW = 8;
1630
- /** Margin floor, as a share of the window, before any error or inflow is measured. */
1631
1308
  const PROJECTION_MARGIN_FLOOR_SHARE = 0.05;
1632
1309
 
1633
1310
  const noteProjectionCalibration = (measurement: ProviderContextMeasurement): void => {
1634
1311
  const previous = measurements.lastProviderMeasurement;
1635
1312
  if (Number.isFinite(measurement.tokens) && previous && Number.isFinite(previous.tokens)) {
1636
1313
  const step = measurement.tokens - previous.tokens;
1637
- // Only GROWTH is an inflow step. A commit shrinks the window; that is the thing
1638
- // the margin has to survive, not a size the next request can be predicted from.
1639
1314
  if (step > 0) {
1640
1315
  measurements.inflowSteps.push(step);
1641
1316
  if (measurements.inflowSteps.length > PROJECTION_ERROR_WINDOW) measurements.inflowSteps.shift();
@@ -1644,11 +1319,6 @@ export function registerActiveContext(pi: any, options: {
1644
1319
  const chars = measurements.lastProjectedChars;
1645
1320
  if (chars === null || chars < PROJECTION_CALIBRATION_MIN_CHARS) return;
1646
1321
  if (!Number.isFinite(measurement.tokens) || measurement.tokens < PROJECTION_CALIBRATION_MIN_TOKENS) return;
1647
- // The signed error of the estimate we made for the projection this measurement
1648
- // describes. This is the only direct measure of how wrong the fence can be.
1649
- // Only a CALIBRATED estimate's error belongs in the window. The bootstrap constant
1650
- // is wrong by design -- 76% high in rep12 -- and letting that one reading set the
1651
- // margin would keep every later request permanently inside it.
1652
1322
  if (measurements.lastProjectedEstimate !== null && measurements.lastProjectedEstimateCalibrated &&
1653
1323
  measurement.tokens > 0) {
1654
1324
  measurements.estimatorErrors.push(
@@ -1662,17 +1332,6 @@ export function registerActiveContext(pi: any, options: {
1662
1332
  }
1663
1333
  };
1664
1334
 
1665
- /**
1666
- * Recent, and pessimistic.
1667
- *
1668
- * A single latest pairing tracks drift but carries its noise; an average lags it.
1669
- * Near the top of the window neither is acceptable, because the error that matters is
1670
- * one-sided: a ratio that is too HIGH under-counts tokens and transmits a request the
1671
- * provider will reject. So the fence takes the smallest ratio in the recent window,
1672
- * which converges instantly in the dangerous direction and within a window in the
1673
- * cheap one. Measured 2026-08-06 (rep13): the ratio moved 5.34 to 6.01 and back
1674
- * across twenty requests while the window sat above 90% full.
1675
- */
1676
1335
  const projectionCharsPerToken = (): number => {
1677
1336
  const usable = measurements.projectionCalibrations.filter((entry) =>
1678
1337
  entry.tokens > 0 && Number.isFinite(entry.chars / entry.tokens) && entry.chars / entry.tokens > 0);
@@ -1684,40 +1343,14 @@ export function registerActiveContext(pi: any, options: {
1684
1343
  );
1685
1344
  };
1686
1345
 
1687
- /**
1688
- * Bind the provider's count to the projection it counted.
1689
- *
1690
- * The anchor is the number the provider reported for a request this process actually
1691
- * TRANSMITTED, held with that projection's serialized bytes. Identity is carried three
1692
- * ways so a stale anchor cannot pass for a fresh one: the session it belongs to, the
1693
- * attribution generation (a model or thinking-level change is a different tokenizer, so
1694
- * its counts describe nothing here), and the projection text itself, which the reading
1695
- * re-checks byte for byte before adding anything to it.
1696
- */
1697
1346
  const noteProviderProjectionAnchor = (measurement: ProviderContextMeasurement): void => {
1698
- // ONE ANCHOR PER MEASURED RESPONSE. A pass that re-observes the same assistant
1699
- // message -- the retry after a provider rejection, or any pass the host runs without
1700
- // a new response -- would otherwise re-bind that count to a newer projection the
1701
- // provider never counted, and the count would silently describe the wrong bytes.
1702
1347
  if (measurements.projectionAnchor?.messageSha256 === measurement.messageSha256) return;
1703
1348
  const text = instrumentation.previousText;
1704
- // Only a TRANSMITTED projection can be anchored: an aborted pass built a projection
1705
- // the provider never saw, so no reported count describes it.
1706
1349
  if (!text || text.length < 2 || !text.endsWith("]") || !persistence.state) {
1707
1350
  measurements.projectionAnchor = null;
1708
1351
  return;
1709
1352
  }
1710
1353
  const chars = bytes(text);
1711
- // AND THE COUNT HAS TO FIT THE BYTES IT IS BOUND TO.
1712
- //
1713
- // An anchor is exact for the bytes it covers only if it actually describes them. A
1714
- // pairing that implies fewer serialized chars per token than any tokenizer produces
1715
- // is not describing this projection, and taken at face value it would put the fence
1716
- // under permanent pressure a projection of that size cannot explain. The calibration
1717
- // window already refuses such a ratio through the same floor; the anchor refuses it
1718
- // outright and falls back to the estimate. Only the FLOOR applies: a rate ABOVE the
1719
- // calibration ceiling is the signature-heavy composition this mechanism exists to
1720
- // read, and clamping it would throw away the measurement that motivated the build.
1721
1354
  if (!(measurement.tokens > 0) || chars / measurement.tokens < PROJECTION_CHARS_PER_TOKEN_FLOOR) {
1722
1355
  measurements.projectionAnchor = null;
1723
1356
  return;
@@ -1732,45 +1365,6 @@ export function registerActiveContext(pi: any, options: {
1732
1365
  };
1733
1366
  };
1734
1367
 
1735
- /**
1736
- * THE OCCUPANCY READING: what the provider counted, plus only what arrived after it.
1737
- *
1738
- * A whole-projection estimate divides every byte in the window by one rate, and one
1739
- * rate does not fit the window's contents. Measured 2026-08-10 on the sealed rep-23
1740
- * run, byte exact against that run's own projection records: the estimate is unbiased
1741
- * at the pre-commit PEAKS (provider over estimate, mean 1.004 across six) and over-reads
1742
- * the post-fold TROUGHS by 22 to 35 percent (mean ratio 0.784 across six). It is a phase
1743
- * effect, not drift: encrypted reasoning-signature blobs on assistant messages grew from
1744
- * 14.6 to 51.3 percent of projection bytes over that run and price at a fitted 24.8 chars
1745
- * per token against 3.957 for ordinary content, so a projection's rate depends on what it
1746
- * is made of. The runtime therefore believed its floor climbed 0.298 to 0.490 of budget
1747
- * while the provider read 0.276 to 0.382: roughly 45 percent of the apparent floor rise
1748
- * was measurement error, five of six true troughs sat at or below the 0.35 minTarget, and
1749
- * the ladder was folding past its own floor without seeing it.
1750
- *
1751
- * So the rate is applied to the DELTA only. The provider's count for the projection this
1752
- * one extends is exact for every byte it covers, whatever those bytes are made of, and
1753
- * only the material appended since is estimated. Measured on the same run: mean absolute
1754
- * occupancy error across all requests falls from 8.38 to 3.08 percent, and inside every
1755
- * post-fold refill window it drops from the +9 to +27 percent band to under 4 percent from
1756
- * the second request onward.
1757
- *
1758
- * Two things this deliberately does NOT do. It does not move the commit trigger: at all
1759
- * twelve commit points of that run the delta since the last provider count was exactly
1760
- * zero, because the commit hook runs after the response and its usage record have landed.
1761
- * And it does not fix the one pass per cycle where the projection is REWRITTEN rather than
1762
- * appended, right after a commit: the anchor describes a projection this one does not
1763
- * begin with, so there is nothing to add a delta to and the whole-projection estimate
1764
- * stands, error and all (+27 to +35 percent, measured). That case is detected by
1765
- * construction, not by the sign of the delta: the current serialization must begin with
1766
- * the anchored one verbatim, up to the array separator.
1767
- *
1768
- * The anchor is the provider's TOTAL for that request, which includes the output tokens
1769
- * of the response the next projection appends and then prices again as bytes. That is one
1770
- * response's worth of double count, it runs HIGH rather than low, and it keeps a single
1771
- * definition of "the provider's number" across occupancy, the ratio and the calibration
1772
- * instead of a second one that only this reading would use.
1773
- */
1774
1368
  const projectedTokenReading = (projected: unknown[]): {
1775
1369
  tokens: number;
1776
1370
  basis: ProjectionReadingBasis;
@@ -1787,10 +1381,6 @@ export function registerActiveContext(pi: any, options: {
1787
1381
  anchor.sessionId !== persistence.state?.sessionId) {
1788
1382
  return { tokens: estimate, basis: "unmeasured", chars, anchorTokens: null, deltaChars: null };
1789
1383
  }
1790
- // By construction: the anchored serialization minus its closing bracket must be a
1791
- // byte-exact prefix, and the byte after it must be the array separator or the close.
1792
- // A message that merely GREW in place fails this, because the anchored head ends with
1793
- // that message's own closing brace.
1794
1384
  const separator = text.length > anchor.head.length ? text[anchor.head.length] : "";
1795
1385
  if (!text.startsWith(anchor.head) || (separator !== "," && separator !== "]")) {
1796
1386
  return { tokens: estimate, basis: "rewritten", chars, anchorTokens: anchor.tokens, deltaChars: null };
@@ -1805,39 +1395,19 @@ export function registerActiveContext(pi: any, options: {
1805
1395
  };
1806
1396
  };
1807
1397
 
1808
- /** The largest recent estimator error, as a share. Unmeasured sessions assume none. */
1809
1398
  const estimatorErrorShare = (): number => measurements.estimatorErrors.length
1810
1399
  ? Math.max(...measurements.estimatorErrors.map((error) => Math.abs(error)))
1811
1400
  : 0;
1812
1401
 
1813
- /** The largest recent growth step, which is what one more turn can add. */
1814
1402
  const expectedInflowTokens = (): number => measurements.inflowSteps.length
1815
1403
  ? Math.max(...measurements.inflowSteps)
1816
1404
  : 0;
1817
1405
 
1818
- /**
1819
- * THE OUTPUT WALL'S OWN FORWARD LOOK, AND WHY IT IS NOT THE ONE ABOVE.
1820
- *
1821
- * `inflowSteps` is filled by `noteProjectionCalibration`, which runs on the context pass.
1822
- * By then the message-end path has already advanced `lastProviderMeasurement` to the
1823
- * count being calibrated, so the difference is a measurement against itself and the step
1824
- * is zero. That window has therefore been empty in every session ever run, which means
1825
- * the transmission fence margin and the commit depth floor, both of which read it, have
1826
- * been running on their floor shares alone. Reviving it moves both, and both are
1827
- * calibrated against reps recorded while it was empty, so that is its own build with its
1828
- * own gates rather than a rider on this one.
1829
- *
1830
- * This window is filled where the previous count is still readable, and nothing but the
1831
- * wall reads it. When a count reaches only the context pass the window stays empty and
1832
- * the wall degrades to the condition it replaced, which is the safe direction.
1833
- */
1834
1406
  const WALL_INFLOW_WINDOW = 8;
1835
1407
  const noteWallInflow = (measurement: ProviderContextMeasurement): void => {
1836
1408
  const previous = measurements.lastProviderMeasurement;
1837
1409
  if (!previous || !Number.isFinite(measurement.tokens) || !Number.isFinite(previous.tokens)) return;
1838
1410
  const step = measurement.tokens - previous.tokens;
1839
- // Only GROWTH. A commit shrinks the window; that is what the wall has to survive, not
1840
- // a size the next request can be predicted from.
1841
1411
  if (step <= 0) return;
1842
1412
  measurements.wallInflowSteps.push(step);
1843
1413
  if (measurements.wallInflowSteps.length > WALL_INFLOW_WINDOW) measurements.wallInflowSteps.shift();
@@ -1847,64 +1417,18 @@ export function registerActiveContext(pi: any, options: {
1847
1417
  ? Math.max(...measurements.wallInflowSteps)
1848
1418
  : 0;
1849
1419
 
1850
- /**
1851
- * The safety margin.
1852
- *
1853
- * A fence that fires AT the budget is a fence that fires after the wire: the request
1854
- * that kills the session is the one built after the last measurement, and it is never
1855
- * the one being weighed. Measured 2026-08-06 (rep13): the last measurement read
1856
- * 370,320 tokens against a 383,616 budget -- 13,296 of headroom against a median
1857
- * inflow of 13,865 and a maximum of 27,815 -- while the estimate for that request was
1858
- * 366,934, comfortably "under budget". The next request crossed the real limit and
1859
- * the provider rejected it. Every number in that sentence was known to the runtime.
1860
- *
1861
- * So the reduction threshold carries what the runtime knows it does not know: the
1862
- * worst recent estimator error applied to this estimate, plus one worst recent inflow
1863
- * step, never less than a floor share of the window.
1864
- */
1865
1420
  const projectionMarginTokens = (estimate: number, windowTokens: number): number => Math.ceil(Math.max(
1866
1421
  PROJECTION_MARGIN_FLOOR_SHARE * windowTokens,
1867
1422
  estimatorErrorShare() * estimate + expectedInflowTokens(),
1868
1423
  ));
1869
1424
 
1870
- /**
1871
- * The TRANSMISSION fence.
1872
- *
1873
- * `abortUnsafeHardContext` gates on `measurements.latestRatio`, which describes the
1874
- * request the provider ALREADY answered. It is a lagging indicator: between that
1875
- * response and the next request an excursion can add a hundred thousand tokens of
1876
- * tool results, and nothing in the fence looks at the projection actually about to
1877
- * be sent. Measured 2026-08-06 (rep 11): the last measurement read 359,625 tokens of
1878
- * a 400,000 window, ratio 0.937 against a 0.959 hard fence, so no abort fired -- and
1879
- * the projection that went out was 1,831,936 chars, about 458k estimated tokens, 1.2x
1880
- * the whole window. The provider rejected it twice and the run died. rep4 aborted
1881
- * correctly only because its 272k DESCRIPTOR window put the stale ratio over the
1882
- * fence by luck of arithmetic, not because anything measured the request.
1883
- *
1884
- * So the projection itself is measured here, against the truthful serving budget the
1885
- * capacity accounting already computes. Over budget, an emergency reduction runs at
1886
- * fence pressure -- where every guarded mark is waived -- and the rebuilt projection
1887
- * is measured again. If it still does not fit, the request is aborted BEFORE
1888
- * transmission, which is the whole point of having a fence.
1889
- */
1890
1425
  const projectionExceedsBudget = (projected: unknown[], ctx: any): {
1891
- /** Occupancy: what the provider counted, plus what was appended after it. */
1892
1426
  tokens: number;
1893
- /**
1894
- * This projection's OWN size, every byte of it at one rate. Occupancy answers "how
1895
- * full is the window"; a before-and-after comparison between two projections answers
1896
- * "did this pass make the request smaller", and those are different questions. A
1897
- * reduction is measured in size space on both sides, because the projection the pass
1898
- * rebuilds is a rewrite the anchor does not describe, and subtracting an anchored
1899
- * reading from an unanchored one reports a change that no folding caused.
1900
- */
1901
1427
  sizeTokens: number;
1902
1428
  basis: ProjectionReadingBasis;
1903
1429
  budgetTokens: number;
1904
1430
  marginTokens: number;
1905
- /** Past the wire: this request must not be transmitted at all. */
1906
1431
  over: boolean;
1907
- /** Inside the margin: still sendable, but the next one may not be. Reduce NOW. */
1908
1432
  crowded: boolean;
1909
1433
  } => {
1910
1434
  const capacity = currentCapacity(ctx);
@@ -1963,17 +1487,6 @@ export function registerActiveContext(pi: any, options: {
1963
1487
  ctx.abort();
1964
1488
  };
1965
1489
 
1966
- /**
1967
- * Enforce the budget, and RECOVER rather than die.
1968
- *
1969
- * A provider context-overflow rejection mutates nothing durable: the assistant
1970
- * message never lands and this runtime rebuilds the projection from the branch on
1971
- * every request. So the terminal path is not an abort, it is a rollback: do not
1972
- * append the failed exchange, fold at fence pressure until the request fits, rebuild,
1973
- * and let Pi resend. Recovery is capped, and the cap is what makes it safe -- an
1974
- * inflow that still will not fit after maximal folding is a genuine impossibility,
1975
- * and that one fails LOUDLY exactly as before.
1976
- */
1977
1490
  const enforceProjectionBudget = async (
1978
1491
  snapshot: ActiveContextSnapshot,
1979
1492
  projected: unknown[],
@@ -1981,44 +1494,28 @@ export function registerActiveContext(pi: any, options: {
1981
1494
  ): Promise<{ projected: unknown[]; aborted: boolean }> => {
1982
1495
  let measured = projectionExceedsBudget(projected, ctx);
1983
1496
  const rejected = curation.pendingRejection !== null;
1984
- // CROWDED, not over, is the trigger for reducing: the request that kills a session
1985
- // is the one built after this one. A provider rejection outranks our own estimate:
1986
- // it is ground truth that the last request did not fit, whatever we measured.
1987
1497
  if (!measured.crowded && !rejected) return { projected, aborted: false };
1988
- // Crowded is a MARGIN PREDICTION, not an overflow. While a last-call round is
1989
- // genuinely OPEN, exposure rendered this pass or the agent's response still
1990
- // outstanding, the prediction waits for it: this request still fits and the
1991
- // round ends on the very next context pass. Once the round has elapsed the
1992
- // margin lane acts freely, because a stale exposure parked behind the reopen
1993
- // latch must never muzzle the one reducer that can still act (the 20k-window
1994
- // probe climbed from crowded to the wire in exactly that state). Genuine
1995
- // untransmissibility, an over-budget projection or a provider rejection, never
1996
- // waits: a request whose projection exceeds the provider input budget is rejected
1997
- // outright, so recovery must produce a window that fits. Economy does not outrank
1998
- // the one round.
1999
- const lastCall = persistence.state?.lastCall;
2000
- const delivery = curation.lastCallDelivery;
2001
- const roundOpen = Boolean(lastCall) && (!delivery || delivery.exposure !== lastCall.exposure ||
2002
- markOrdinal(snapshot) <= delivery.ordinal);
2003
- if (!measured.over && !rejected && roundOpen) {
2004
- return { projected, aborted: false };
2005
- }
2006
- // Why this fired, recorded from the measurement that TRIGGERED it rather than the
2007
- // one taken afterwards, which by then describes a projection that fits.
2008
1498
  const trigger = measured;
2009
1499
  let reduced = projected;
2010
1500
  let attempts = 0;
2011
1501
  let reducedAtLeastOnce = false;
2012
- // At the fence the only useful action is the fold that keeps the request
2013
- // transmissible, so every reduction runs with every guarded mark waived.
2014
- while (attempts < OVERFLOW_RECOVERY_MAX_ATTEMPTS && (measured.crowded || measured.over || rejected)) {
1502
+ while (measured.crowded || measured.over || rejected) {
2015
1503
  attempts += 1;
2016
- curation.recoveryAttempts += 1;
1504
+ // THE EMERGENCY IS THE REQUEST THAT WILL NOT FIT, and only that. A projection at
1505
+ // the margin is ordinary work: the fence commits it because it is the pass holding
1506
+ // the request, but it is not a recovery, it does not waive the current-turn guard,
1507
+ // and it does not buy an exemption from the reclaim floor. Waiving at the margin
1508
+ // spends the open turn's own evidence on headroom the boundary was about to buy.
1509
+ const emergency = measured.over || rejected;
1510
+ if (emergency) curation.recoveryAttempts += 1;
2017
1511
  let action: Record<string, unknown> | null = null;
2018
1512
  try {
2019
- action = await attemptAutomaticRung(snapshot, 1, ctx, "projection-budget", {
2020
- waiverRatio: 1,
2021
- });
1513
+ // The fence COMMITS. A mark moves no bytes, and the request it is holding is the
1514
+ // one that will not fit, so marking here would spin the loop against an unchanged
1515
+ // projection until it ran out of things to mark.
1516
+ action = await attemptAutomaticCommit(
1517
+ snapshot, ctx, "projection-budget", emergency ? 1 : measurements.latestRatio,
1518
+ );
2022
1519
  } catch (error) {
2023
1520
  suspendAutomatic(error, "projection-budget", ctx);
2024
1521
  break;
@@ -2031,7 +1528,6 @@ export function registerActiveContext(pi: any, options: {
2031
1528
  }
2032
1529
  if (reducedAtLeastOnce) {
2033
1530
  ladder.overBudgetReduction = {
2034
- // Size space on both sides: what this pass CHANGED, not how full the window is.
2035
1531
  estimatedTokensBefore: trigger.sizeTokens,
2036
1532
  estimatedTokensAfter: measured.sizeTokens,
2037
1533
  occupancyTokensAfter: measured.tokens,
@@ -2049,34 +1545,10 @@ export function registerActiveContext(pi: any, options: {
2049
1545
  }
2050
1546
  if (rejected) {
2051
1547
  const overflowBefore = trigger.sizeTokens;
2052
- // RECOVERY IS A CHANGE, NOT AN OPINION.
2053
- //
2054
- // This read `!measured.over`: our own estimator answering the question the
2055
- // provider had just answered differently. A rejection is ground truth that the
2056
- // estimate was wrong, so the estimate cannot also be the evidence that the retry
2057
- // will work. And a rejection mutates nothing durable -- the rolled-back branch
2058
- // rebuilds the same projection -- so a pass that changed nothing hands the
2059
- // provider a byte-identical request and calls it a rescue. Measured 2026-08-10
2060
- // (luna-20260810 pifold rep 2): two rejections at stage 25, not one byte folded
2061
- // either time, both recorded recovered true, and the run died anyway.
2062
- //
2063
- // The baseline is the request that was actually REJECTED, which is the last
2064
- // projection this process built: it is written at the end of every pass that
2065
- // builds one, and this lane runs before the current pass overwrites it. Measuring
2066
- // against the projection handed to this function instead would credit only the
2067
- // recovery loop's own folds and miss the ordinary commit that already ran earlier
2068
- // in the same pass, which is the usual way a retried request gets smaller.
2069
- //
2070
- // Size space on both sides. Occupancy is anchored to the provider's count for the
2071
- // projection it measured, and the projection this lane rebuilds is a rewrite that
2072
- // anchor does not describe, so a rejected-minus-retried subtraction across the two
2073
- // bases reports a change no folding caused.
2074
1548
  const rejectedTokens = measurements.lastProjectedSizeTokens;
2075
1549
  const freedTokens = typeof rejectedTokens === "number"
2076
1550
  ? Math.max(0, rejectedTokens - measured.sizeTokens)
2077
1551
  : 0;
2078
- // Smaller than what the provider refused, AND inside the budget. Either half alone
2079
- // is a claim this runtime has already been wrong about once.
2080
1552
  const recovered = freedTokens > 0 && !measured.over;
2081
1553
  curation.lastRecovery = {
2082
1554
  status: curation.pendingRejection?.status ?? null,
@@ -2088,7 +1560,6 @@ export function registerActiveContext(pi: any, options: {
2088
1560
  emit("context.recovery", {
2089
1561
  provider_status: curation.pendingRejection?.status ?? null,
2090
1562
  attempts,
2091
- max_attempts: OVERFLOW_RECOVERY_MAX_ATTEMPTS,
2092
1563
  tokens_before: overflowBefore,
2093
1564
  tokens_after: measured.sizeTokens,
2094
1565
  occupancy_tokens_after: measured.tokens,
@@ -2096,15 +1567,9 @@ export function registerActiveContext(pi: any, options: {
2096
1567
  budget_tokens: measured.budgetTokens,
2097
1568
  margin_tokens: measured.marginTokens,
2098
1569
  recovered,
2099
- // What the verdict rests on, so a false claim cannot be read back as a true one:
2100
- // the size of the request the provider refused, and how much smaller this one is.
2101
1570
  rejected_tokens: typeof rejectedTokens === "number" ? rejectedTokens : null,
2102
1571
  freed_tokens: freedTokens,
2103
- // Whether the recovery loop itself folded, as distinct from the pass as a whole.
2104
1572
  loop_reduced: reducedAtLeastOnce,
2105
- // The join. `context.rollback` records what left the branch; this records what
2106
- // the retried pass folded to make the shorter window fit, and the two are one
2107
- // episode. Null when a rejection was recorded without a tree rollback.
2108
1573
  rollback_seq: typeof rollback.last?.seq === "number" ? rollback.last.seq : null,
2109
1574
  });
2110
1575
  const unchangedNote = "The provider rejected the last request and this pass made it no smaller, so the " +
@@ -2139,21 +1604,14 @@ export function registerActiveContext(pi: any, options: {
2139
1604
 
2140
1605
  const startPreparation = (snapshot: ActiveContextSnapshot, ratio: number | null, ctx: any): void => {
2141
1606
  if (lifecycle.shuttingDown || !persistence.state || ladder.automaticFailure || ratio === null || persistence.state.prepared || ladder.preparing ||
2142
- ratio < snapshot.policy.warmRatio ||
1607
+ ratio < snapshot.policy.prepareRatio ||
2143
1608
  !measurements.lastProviderMeasurement || !durableProviderMeasurementMatches(measurements.lastProviderMeasurement)) return;
2144
- // Preparation is asynchronous but never jumps ahead of an immediately
2145
- // committable deterministic fold on the same measured projection.
2146
- const selection = selectAutomaticRung(snapshot, persistence.state, ratio, {
2147
- summarizerAvailable: Boolean(options.summarizeContextSpan),
2148
- failedPreparationIds: ladder.failedPreparations,
2149
- });
1609
+ const selection = selectAutomaticRung(snapshot, persistence.state, ratio);
2150
1610
  ladder.lastSelectionKind = selection && "candidate" in selection ? selection.candidate.kind : null;
2151
1611
  ladder.lastSelectionSourceIds = selection && "candidate" in selection
2152
1612
  ? selection.candidate.sourceRefs.slice(0, 8).map((ref) => ref.entryId)
2153
1613
  : [];
2154
1614
  if (selection?.kind !== "chapter-prepare") return;
2155
- // Already bite-sized: the chapter selector never proposes a span past the cap, so a
2156
- // model brief is never spent on a fold nobody can read back cheaply.
2157
1615
  const candidate = selection.candidate;
2158
1616
  const id = automaticPreparationId(candidate, persistence.state);
2159
1617
  const controller = new AbortController();
@@ -2168,11 +1626,6 @@ export function registerActiveContext(pi: any, options: {
2168
1626
  snapshot,
2169
1627
  state: capturedState,
2170
1628
  generation: capturedGeneration,
2171
- summarize: ladder.failedPreparations.has(id) ? undefined : observedSummarize,
2172
- onSummarizerFailure: (error) => {
2173
- ladder.lastPreparationError = error instanceof Error ? error.message : String(error);
2174
- ladder.failedPreparations.add(id);
2175
- },
2176
1629
  ctx,
2177
1630
  signal: controller.signal,
2178
1631
  }).then((preparedFold) => {
@@ -2191,7 +1644,6 @@ export function registerActiveContext(pi: any, options: {
2191
1644
  if (controller.signal.aborted ||
2192
1645
  !sessionIdentityStillValid(ctx, snapshot.sessionId, capturedGeneration)) return;
2193
1646
  ladder.lastPreparationError = error instanceof Error ? error.message : String(error);
2194
- ladder.failedPreparations.add(id);
2195
1647
  suspendAutomatic(
2196
1648
  error,
2197
1649
  "chapter-prepare",
@@ -2204,18 +1656,6 @@ export function registerActiveContext(pi: any, options: {
2204
1656
  if (ownsSlot && sessionIdentityStillValid(ctx, snapshot.sessionId, capturedGeneration)) updateStatus(ctx);
2205
1657
  });
2206
1658
  };
2207
- // Appended at the very TAIL, after the stable prefix, so a suggestion never
2208
- // invalidates a cached prefix and never becomes durable transcript.
2209
- /**
2210
- * The receipt block: what the runtime did to this window, as status rather than as
2211
- * advice. It is the only carrier this runtime builds.
2212
- *
2213
- * It is free because it is RETROSPECTIVE. A receipt exists only after a commit has
2214
- * already rewritten the projection, so it rides a cache break the runtime had to pay
2215
- * for regardless, and the freeze then closes over it so it is never paid for again.
2216
- * It is hard-bounded and its ring evicts the oldest entry, because a report about
2217
- * bloat that becomes bloat has argued against itself.
2218
- */
2219
1659
  const appendReceipts = (projected: unknown[], snapshot: ActiveContextSnapshot): unknown[] => {
2220
1660
  const content = receiptBlockText({ receipts: curation.receipts, toolName, brandNoun });
2221
1661
  if (!content) return projected;
@@ -2238,12 +1678,6 @@ export function registerActiveContext(pi: any, options: {
2238
1678
  return projected;
2239
1679
  };
2240
1680
 
2241
- /**
2242
- * The rider rides the SAME admission as the receipt block: it renders from the
2243
- * persisted literal bytes, lands once per freeze cycle, and the freeze closes over
2244
- * it, so it can never diverge a prefix on its own. It is never regenerated: the
2245
- * bytes the epoch persisted are the bytes every re-render carries.
2246
- */
2247
1681
  const appendRider = (projected: unknown[], snapshot: ActiveContextSnapshot): unknown[] => {
2248
1682
  const rider = persistence.state?.rider;
2249
1683
  if (!rider) return projected;
@@ -2265,92 +1699,6 @@ export function registerActiveContext(pi: any, options: {
2265
1699
  return projected;
2266
1700
  };
2267
1701
 
2268
- /**
2269
- * Threshold notices are APPEND-ONCE: each delivered notice is its own carrier with
2270
- * its own key, so a notice that fires mid-freeze lands at the tail as a pure append,
2271
- * the freeze closes over it, and it then persists in the window the way a tool
2272
- * result does. A freeze break re-renders every retained notice from its persisted
2273
- * literal bytes inside the rewrite that broke the freeze.
2274
- */
2275
- const appendNotices = (projected: unknown[], snapshot: ActiveContextSnapshot): unknown[] => {
2276
- const notices = persistence.state?.notices;
2277
- if (!notices?.ring.length) return projected;
2278
- for (const notice of notices.ring) {
2279
- if (!carrierAdmitted(`notice-${notice.share}-${notice.ordinal}`)) continue;
2280
- projected.push({
2281
- role: "custom",
2282
- customType: noticeProjectionType,
2283
- content: notice.text,
2284
- display: false,
2285
- details: {
2286
- source: activeContextSource(entryTypePrefix),
2287
- ephemeral: true,
2288
- share: notice.share,
2289
- noticeOrdinal: notice.ordinal,
2290
- },
2291
- timestamp: typeof ownValue(snapshot.messages.at(-1), "timestamp") === "number"
2292
- ? ownValue(snapshot.messages.at(-1), "timestamp")
2293
- : 0,
2294
- });
2295
- }
2296
- return projected;
2297
- };
2298
-
2299
- /**
2300
- * The pre-commit last-call rides the commit BOUNDARY: it is armed when the band-top
2301
- * trigger fires, appended at the tail (a pure append) for exactly one gated round,
2302
- * and the commit that consumes it clears the state, so the carrier's disappearance
2303
- * rides the rewrite that commit already pays for. Rendering records the delivery,
2304
- * which is what the one-round clock is measured from.
2305
- */
2306
- const appendLastCall = (projected: unknown[], snapshot: ActiveContextSnapshot): unknown[] => {
2307
- const lastCall = persistence.state?.lastCall;
2308
- if (!lastCall) return projected;
2309
- if (carrierAdmitted(`lastcall-${lastCall.exposure}`)) {
2310
- projected.push({
2311
- role: "custom",
2312
- customType: lastCallProjectionType,
2313
- content: lastCall.text,
2314
- display: false,
2315
- details: {
2316
- source: activeContextSource(entryTypePrefix),
2317
- ephemeral: true,
2318
- exposure: lastCall.exposure,
2319
- },
2320
- timestamp: typeof ownValue(snapshot.messages.at(-1), "timestamp") === "number"
2321
- ? ownValue(snapshot.messages.at(-1), "timestamp")
2322
- : 0,
2323
- });
2324
- }
2325
- if (curation.lastCallDelivery?.exposure !== lastCall.exposure) {
2326
- curation.lastCallDelivery = { exposure: lastCall.exposure, ordinal: markOrdinal(snapshot) };
2327
- }
2328
- return projected;
2329
- };
2330
-
2331
- /**
2332
- * Whatever this pass ended up sending becomes the frozen surface for the next one, in
2333
- * full. Nothing rides after the frozen region.
2334
- *
2335
- * The earlier build kept a live suggestion slate outside the freeze, reasoning that
2336
- * advice goes stale and that a re-rendered block "only diverges the prefix when its
2337
- * own content changes". That reasoning is wrong, and rep 21 measured the cost. A
2338
- * positional cache compares bytes from the start: this pass sends [frozen][slate] and
2339
- * the next sends [frozen][new messages][slate], so at the offset where the slate sat
2340
- * the next pass has new messages instead. The slate diverges the prefix EVERY pass
2341
- * whatever it says, because appending anything displaces it. There is no stable
2342
- * position at a moving tail.
2343
- *
2344
- * Measured on rep 21: a 1503-character slate against a 1.5M-character prompt, 99.86%
2345
- * of the projection preserved by our own accounting, and 16 full cache rebuilds
2346
- * costing 3.71M tokens -- 21.9% of every input token in the run. Prefix caching is a
2347
- * step function, not a gradient: mutation cost has no relation to mutation size.
2348
- *
2349
- * So the rule this build enforces: the runtime adds to the window only at a moment it
2350
- * is already rewriting the window, which means at a commit. A carrier landed there is
2351
- * free, because the break is already paid for, and it stays landed forever because
2352
- * the freeze closes over it.
2353
- */
2354
1702
  const holdFrozen = (projected: unknown[]): unknown[] => {
2355
1703
  freeze.projection = [...projected];
2356
1704
  freeze.active = false;
@@ -2361,13 +1709,9 @@ export function registerActiveContext(pi: any, options: {
2361
1709
  const body = projectActiveContext(snapshot, persistence.state!).filter((message) => {
2362
1710
  const customType = ownValue(message, "customType");
2363
1711
  return customType !== milestoneProjectionType && customType !== advisoryProjectionType &&
2364
- customType !== surfacingProjectionType && customType !== receiptProjectionType &&
2365
- customType !== riderProjectionType && customType !== curationProjectionType &&
2366
- customType !== lastCallProjectionType && customType !== noticeProjectionType;
1712
+ customType !== receiptProjectionType &&
1713
+ customType !== riderProjectionType && customType !== curationProjectionType;
2367
1714
  });
2368
- // The freeze test, stated as bytes rather than as intent: if the rebuilt body still
2369
- // OPENS with the frozen body verbatim, nothing structural moved and the previous
2370
- // projection is reused whole, with only what arrived since appended after it.
2371
1715
  const held = freeze.body?.length ?? 0;
2372
1716
  freeze.active = freeze.projection !== null && body.length >= held &&
2373
1717
  stableStringify(body.slice(0, held)) === freeze.bodyText;
@@ -2377,28 +1721,10 @@ export function registerActiveContext(pi: any, options: {
2377
1721
  if (!freeze.active) freeze.keys.clear();
2378
1722
  freeze.body = body;
2379
1723
  freeze.bodyText = stableStringify(body);
2380
- // The one carrier left, and the only one that can ever be free: a statement of what
2381
- // the runtime just did. It is built only when a commit produced a receipt, it lands
2382
- // inside the freeze, and it is never rendered twice.
2383
- //
2384
- // Everything that used to stand here was ANTICIPATORY -- pressure milestones, the
2385
- // live advisory, curation reminders, the last-call notice. Anticipatory guidance has
2386
- // to arrive BEFORE the event it warns about, so it can never ride a break the
2387
- // runtime was already paying for; it has to create one. Anticipatory guidance and an
2388
- // append-only projection are mutually exclusive, and eleven runs say the warning
2389
- // bought nothing anyway: voluntary fold share was 0.00, and the three runs built
2390
- // specifically to invite curation produced 0, 1 and 0 voluntary folds.
2391
1724
  appendReceipts(projected, snapshot);
2392
1725
  appendRider(projected, snapshot);
2393
- appendNotices(projected, snapshot);
2394
- appendLastCall(projected, snapshot);
2395
1726
  return holdFrozen(projected);
2396
1727
  };
2397
- /**
2398
- * Classify the projection we are about to send against the one before it. A rewrite
2399
- * is ours; a pure append that the provider still re-reads is not, and conflating the
2400
- * two is what made a scheduling lever look responsible for 12 misses it never caused.
2401
- */
2402
1728
  const noteProjection = (projected: unknown[]): void => {
2403
1729
  const digests = messageDigests(projected);
2404
1730
  const comparison = compareProjections(instrumentation.previousDigests, digests);
@@ -2408,17 +1734,12 @@ export function registerActiveContext(pi: any, options: {
2408
1734
  const text = stableStringify(projected);
2409
1735
  const divergence = prefixDivergence(instrumentation.previousText, text);
2410
1736
  const previousChars = instrumentation.previousText?.length ?? 0;
2411
- // How much of the PREVIOUS prompt this projection still opens with. identicalShare
2412
- // measures the new projection instead, which grows every pass and would call a
2413
- // total rewrite "preserved" as soon as enough fresh content landed after it.
2414
1737
  instrumentation.lastPreservedShare = previousChars > 0
2415
1738
  ? divergence.identicalChars / previousChars
2416
1739
  : null;
2417
1740
  const charsPerToken = projectionCharsPerToken();
2418
1741
  const causes = instrumentation.sinceHandoff.filter((event) =>
2419
1742
  PREFIX_MUTATING_KINDS.has(event.kind));
2420
- // The reading this projection was judged by, with the pieces it was built from, so
2421
- // the anchored series is readable from the stream instead of reconstructed.
2422
1743
  const reading = projectedTokenReading(projected);
2423
1744
  emit("context.projection", {
2424
1745
  change: comparison.change,
@@ -2432,10 +1753,10 @@ export function registerActiveContext(pi: any, options: {
2432
1753
  anchor_tokens: reading.anchorTokens,
2433
1754
  delta_chars: reading.deltaChars,
2434
1755
  chars_per_token: charsPerToken,
1756
+ derivations: instrumentation.derivations,
1757
+ derive_ms: Math.round(instrumentation.deriveMs),
1758
+ derivation_hits: instrumentation.derivationHits,
2435
1759
  });
2436
- // Emission only. Which of these is a provider-side miss and which is a rewrite we
2437
- // caused is a join against provider-reported cacheRead, and that join is the
2438
- // analyst's, not this runtime's.
2439
1760
  emit("context.prefix", {
2440
1761
  change: comparison.change,
2441
1762
  divergent_char: divergence.index,
@@ -2450,8 +1771,6 @@ export function registerActiveContext(pi: any, options: {
2450
1771
  : (causes.length ? causes.map((event) => event.kind).join(",") : "unattributed"),
2451
1772
  cause_event_seqs: causes.map((event) => event.seq).join(","),
2452
1773
  events_since_handoff: instrumentation.sinceHandoff.length,
2453
- // The request class, which falls straight out of the attribution and makes a run
2454
- // directly comparable to a production cache table. Not new measurement.
2455
1774
  request_class: divergence.index === null
2456
1775
  ? "steady-state"
2457
1776
  : (causes.some((event) => event.kind === "context.recovery")
@@ -2463,368 +1782,6 @@ export function registerActiveContext(pi: any, options: {
2463
1782
  instrumentation.mutationsSinceHandoff = 0;
2464
1783
  };
2465
1784
 
2466
- /**
2467
- * Enqueue the folds this commit created with a deterministic brief.
2468
- *
2469
- * The request is built HERE, against the snapshot and the pre-commit state, because
2470
- * this is the last moment the fold's source is still exact active evidence: after the
2471
- * commit its span is a placeholder and the orientation either side of it is gone.
2472
- * These are the bytes `prepareFold` already hashed into the fold's identity, so the
2473
- * generator briefs the span that was folded and nothing else.
2474
- *
2475
- * A PARENT is queued too, and reads its children at depth one rather than through their
2476
- * briefs: `consolidationSourceText` opens each child and leaves the grandchildren folded,
2477
- * so the group is briefed from material instead of from a summary of summaries. The one
2478
- * thing it must not race is a child's own upgrade, so a parent whose children are still
2479
- * in this lane is deferred to the next boundary instead of reading briefs about to be
2480
- * replaced. Unlike a leaf, a parent's source keeps: its children are folds, and folds
2481
- * stay resolvable after the commit that nested them.
2482
- */
2483
- const queueBriefUpgrades = (
2484
- snapshot: ActiveContextSnapshot,
2485
- stateBeforeCommit: ActiveContextState,
2486
- foldIds: readonly string[],
2487
- ): void => {
2488
- if (!observedSummarize || !persistence.state) return;
2489
- const queued = (id: string): boolean =>
2490
- upgrades.queue.some((entry) => entry.members.some((member) => member.foldId === id));
2491
- const pending = (id: string): boolean => upgrades.running.has(id) || queued(id) ||
2492
- upgrades.ready.some((entry) => entry.foldId === id) ||
2493
- upgrades.deferred.has(id);
2494
- // Gathered before any packing, because a batch is a property of the whole commit and
2495
- // not of the fold that happens to be read first.
2496
- const gathered: Array<{
2497
- foldId: string;
2498
- sourceSha256: string;
2499
- refs: EvidenceRef[];
2500
- span: Record<string, unknown>;
2501
- chars: number;
2502
- parent: boolean;
2503
- }> = [];
2504
- // Parents that waited are considered first and at every boundary, so the wait ends as
2505
- // soon as the children settle rather than whenever the ladder happens to build another.
2506
- for (const foldId of [...upgrades.deferred, ...foldIds]) {
2507
- const full = upgrades.queue.length >= MAX_BRIEF_UPGRADE_QUEUE;
2508
- if (upgrades.failed.has(foldId) || upgrades.running.has(foldId) || queued(foldId) ||
2509
- upgrades.ready.some((entry) => entry.foldId === foldId)) continue;
2510
- const fold = persistence.state.folds.find((item) => item.id === foldId);
2511
- // A supplied brief is agent judgment and outranks the generator; a model brief is
2512
- // already what this lane exists to produce. A fold that is no longer there is no
2513
- // longer owed anything, so a rolled-back parent leaves the wait rather than sitting
2514
- // in it.
2515
- if (!fold || foldProvenance(fold, persistence.state).kind !== "deterministic") {
2516
- upgrades.deferred.delete(foldId);
2517
- continue;
2518
- }
2519
- const parent = fold.parts.some((part) => part.kind === "fold");
2520
- // A parent waits rather than being shed: its children are folds, so its source is
2521
- // still there whenever the lane has room, and a group that loses its turn at a busy
2522
- // boundary would otherwise keep the index its children could not write. A leaf is the
2523
- // other way round. Its source is exact active evidence at this commit and a
2524
- // placeholder after it, so a full queue drops it here and the receipt says so.
2525
- if (parent && (full || childFoldIds(fold).some(pending))) {
2526
- upgrades.deferred.add(foldId);
2527
- continue;
2528
- }
2529
- if (full) continue;
2530
- upgrades.deferred.delete(foldId);
2531
- const refs = parent
2532
- ? flattenFoldRefs(fold, persistence.state)
2533
- : fold.parts.every((part) => part.kind === "raw")
2534
- ? fold.parts.map((part) => (part as { kind: "raw"; ref: EvidenceRef }).ref)
2535
- : null;
2536
- if (!refs) continue;
2537
- try {
2538
- // The parent reads the state that holds its children and their upgraded briefs;
2539
- // a leaf reads the state where its own span was still raw active evidence.
2540
- const sourceText = parent
2541
- ? consolidationSourceText(snapshot, persistence.state, fold.parts)
2542
- : encodedFoldSource(snapshot, stateBeforeCommit, fold.parts, fold.kind);
2543
- const chars = bytes(sourceText);
2544
- if (chars > snapshot.policy.maxSourceChars) continue;
2545
- gathered.push({
2546
- foldId,
2547
- sourceSha256: fold.sourceSha256,
2548
- refs,
2549
- chars,
2550
- parent,
2551
- span: {
2552
- candidateId: fold.id,
2553
- sourceRefs: clone(refs),
2554
- sourceText,
2555
- sourceSha256: sha256Text(sourceText),
2556
- // What the PAYLOAD holds, which is one entry per part: a consolidation can
2557
- // carry absorbed raw evidence beside its folded children, and the coverage
2558
- // rule counts the things the model is actually shown. Counting only the fold
2559
- // children told it to write fewer clauses than the payload has subjects.
2560
- children: parent ? fold.parts.length : 0,
2561
- },
2562
- });
2563
- } catch (error) {
2564
- // Evidence drift between the commit and this read leaves the deterministic brief
2565
- // standing, and the next commit record reports the attempt rather than hiding it.
2566
- upgrades.failed.add(foldId);
2567
- upgrades.failures += 1;
2568
- upgrades.lastError = boundReceiptText(
2569
- error instanceof Error ? error.message : String(error), 240, "brief upgrade",
2570
- );
2571
- }
2572
- }
2573
- // Pack the commit's spans into as few calls as the source budget allows. Order is the
2574
- // order they were gathered, which is span order within the commit, so the numbered
2575
- // spans a batch shows the generator run the way the session did and one really is the
2576
- // orientation for the next.
2577
- for (let at = 0; at < gathered.length;) {
2578
- if (upgrades.queue.length >= MAX_BRIEF_UPGRADE_QUEUE) {
2579
- // No room for another call. A parent goes back to waiting, because its children are
2580
- // folds and its source will still be there whenever the lane frees up. A leaf
2581
- // cannot wait: its source is exact active evidence at THIS commit and a placeholder
2582
- // after it, so it keeps the deterministic brief it committed with.
2583
- for (const item of gathered.slice(at)) {
2584
- if (item.parent) upgrades.deferred.add(item.foldId);
2585
- }
2586
- break;
2587
- }
2588
- const members: typeof gathered = [];
2589
- let chars = 0;
2590
- while (at < gathered.length && members.length < MAX_BRIEF_BATCH_SPANS &&
2591
- (!members.length || chars + gathered[at].chars <= snapshot.policy.maxSourceChars)) {
2592
- chars += gathered[at].chars;
2593
- members.push(gathered[at]);
2594
- at += 1;
2595
- }
2596
- // Orientation is the run's, not each span's: where this batch of consecutive spans
2597
- // sits in the wider conversation. Taken from the ends rather than from the union,
2598
- // because a commit can fold spans with protected material still raw between them and
2599
- // the union of those refs is not one contiguous range.
2600
- const before = boundedOrientation(snapshot, members[0].refs);
2601
- const after = boundedOrientation(snapshot, members[members.length - 1].refs);
2602
- upgrades.queue.push({
2603
- members: members.map((item) => ({ foldId: item.foldId, sourceSha256: item.sourceSha256 })),
2604
- request: {
2605
- spans: members.map((item) => item.span),
2606
- beforeRefs: clone(before.beforeRefs),
2607
- beforeText: before.beforeText,
2608
- beforeSha256: sha256Text(before.beforeText),
2609
- afterRefs: clone(after.afterRefs),
2610
- afterText: after.afterText,
2611
- afterSha256: sha256Text(after.afterText),
2612
- maxBriefChars: snapshot.policy.maxBriefChars,
2613
- // Read by the observed wrapper and by nothing else, so a queue that backs up is
2614
- // visible as waiting rather than as a slow generator. The summarizer contract is
2615
- // on the RESULT, so an extra request field reaches it harmlessly.
2616
- queuedAtMs: Date.now(),
2617
- },
2618
- });
2619
- }
2620
- };
2621
-
2622
- /**
2623
- * One generator call, between boundaries, cancel-safe. It writes nothing durable: a
2624
- * finished brief waits in `ready` for a commit to carry it, and an aborted or failed
2625
- * call leaves the fold exactly as it committed.
2626
- *
2627
- * Returns whether a call was started, which is what lets the drain below stop.
2628
- */
2629
- const startBriefUpgrade = (snapshot: ActiveContextSnapshot, ctx: any): boolean => {
2630
- const summarize = observedSummarize;
2631
- // In CALLS, not folds. `running` is keyed by every fold a call briefs so the queue can
2632
- // ask whether one is already being written, so its size is a fold count and reading it
2633
- // as the in-flight bound would stop the lane after a single batch.
2634
- const inFlight = new Set(upgrades.running.values()).size;
2635
- if (!summarize || lifecycle.shuttingDown || !upgrades.queue.length ||
2636
- inFlight >= MAX_BRIEF_UPGRADES_IN_FLIGHT) return false;
2637
- const entry = upgrades.queue.shift()!;
2638
- const controller = new AbortController();
2639
- const slot = { controller, promise: Promise.resolve() };
2640
- // Keyed by EVERY fold the call briefs, so the queue's "already being briefed" check and
2641
- // the in-flight bound both read one call as the one thing it is.
2642
- for (const member of entry.members) upgrades.running.set(member.foldId, slot);
2643
- const capturedSessionId = snapshot.sessionId;
2644
- const capturedGeneration = lifecycle.generation;
2645
- let timeout: ReturnType<typeof setTimeout> | undefined;
2646
- slot.promise = (async () => {
2647
- const timed = new Promise<never>((_resolve, reject) => {
2648
- timeout = setTimeout(() => {
2649
- controller.abort();
2650
- reject(new Error(`Brief upgrade exceeded ${snapshot.policy.briefTimeoutMs}ms`));
2651
- }, snapshot.policy.briefTimeoutMs);
2652
- });
2653
- // The same contract `prepareFold` holds a generated brief to, through the same
2654
- // function: an upgrade with its own copy of the check would drift from the fold
2655
- // path's, and the cure a missed criterion earns belongs to both or to neither.
2656
- const generated = await Promise.race([
2657
- generatedBriefs({
2658
- summarize: (request, callCtx) => summarize({ ...request, signal: controller.signal }, callCtx),
2659
- request: entry.request,
2660
- spans: entry.request.spans as Array<Record<string, unknown>>,
2661
- ctx,
2662
- maxBriefChars: snapshot.policy.maxBriefChars,
2663
- toolName: snapshot.toolName,
2664
- }),
2665
- timed,
2666
- ]);
2667
- if (controller.signal.aborted ||
2668
- !sessionIdentityStillValid(ctx, capturedSessionId, capturedGeneration)) return;
2669
- // Per span, not per call. A batch is one request and many answers, so one span that
2670
- // could not be cured is one fold keeping its deterministic brief while its neighbours
2671
- // take theirs; the whole call failing on it would be the coverage problem batching
2672
- // exists to solve, wearing a different hat.
2673
- entry.members.forEach((member, at) => {
2674
- const written = generated.briefs[at];
2675
- if (!written) {
2676
- upgrades.failed.add(member.foldId);
2677
- upgrades.failures += 1;
2678
- upgrades.lastError = boundReceiptText(
2679
- `span ${at + 1} of ${entry.members.length}: ${generated.complaints[0] ?? "no brief"}`,
2680
- 240, "brief upgrade",
2681
- );
2682
- return;
2683
- }
2684
- upgrades.ready.push({
2685
- foldId: member.foldId,
2686
- sourceSha256: member.sourceSha256,
2687
- brief: written.brief,
2688
- provenance: written.provenance,
2689
- });
2690
- });
2691
- upgrades.cures += generated.cured;
2692
- })().catch((error) => {
2693
- if (controller.signal.aborted) return;
2694
- // LOUD, and once, for every fold the call carried. They keep their deterministic
2695
- // briefs, the failure is counted onto the next commit record, and none of them is
2696
- // ever sent again: a generator that fails on a span fails on it again, and a retry
2697
- // loop would spend the session's provider calls proving that.
2698
- for (const member of entry.members) upgrades.failed.add(member.foldId);
2699
- upgrades.failures += 1;
2700
- upgrades.lastError = boundReceiptText(
2701
- error instanceof Error ? error.message : String(error), 240, "brief upgrade",
2702
- );
2703
- }).finally(() => {
2704
- clearTimeout(timeout);
2705
- for (const member of entry.members) {
2706
- if (upgrades.running.get(member.foldId) === slot) upgrades.running.delete(member.foldId);
2707
- }
2708
- // A finished call starts the next one, so the drain rate is the generator's latency
2709
- // rather than however often a ladder pass happens to look. Still between
2710
- // boundaries: nothing here touches the projection, and the generation check is the
2711
- // same fence `cancelBriefUpgrades` is called behind, so a session that moved on
2712
- // cannot be restarted by a call that outlived it.
2713
- if (!lifecycle.shuttingDown && lifecycle.generation === capturedGeneration) {
2714
- resumeBriefUpgrades(snapshot, ctx);
2715
- }
2716
- });
2717
- return true;
2718
- };
2719
-
2720
- /**
2721
- * Fill the in-flight slots from the queue. The bound is a constant, not a pace: the
2722
- * lane starts everything it is allowed to start the moment there is work, because a
2723
- * fold whose brief is written late is a fold the session read deterministic in the
2724
- * meantime.
2725
- */
2726
- const startBriefUpgrades = (snapshot: ActiveContextSnapshot, ctx: any): void => {
2727
- while (startBriefUpgrade(snapshot, ctx)) { /* Bounded by the in-flight constant. */ }
2728
- };
2729
-
2730
- /**
2731
- * Take up the waiting parents, then fill the slots.
2732
- *
2733
- * A deferred parent was waiting on the lane, so the lane finishing is the news, not the
2734
- * next commit. Boundaries are where briefs APPLY; hanging the retry on them too would
2735
- * leave a session that stops folding holding parents whose children were briefed long
2736
- * ago, and the last group the ladder built is exactly the one a session ends beside.
2737
- */
2738
- const resumeBriefUpgrades = (snapshot: ActiveContextSnapshot, ctx: any): void => {
2739
- if (upgrades.deferred.size && persistence.state) {
2740
- queueBriefUpgrades(snapshot, persistence.state, []);
2741
- }
2742
- startBriefUpgrades(snapshot, ctx);
2743
- };
2744
-
2745
- const cancelBriefUpgrades = (): void => {
2746
- for (const slot of upgrades.running.values()) slot.controller.abort();
2747
- upgrades.running.clear();
2748
- upgrades.queue = [];
2749
- upgrades.ready = [];
2750
- upgrades.deferred.clear();
2751
- };
2752
-
2753
- /**
2754
- * Apply finished upgrades INSIDE the commit's own mutation.
2755
- *
2756
- * Called between `commitPendingMarks` and the byte accounting, so an upgraded brief is
2757
- * part of what this commit is measured to have done rather than a rewrite nobody
2758
- * charged for. Nothing else may call this: an upgrade that finishes between boundaries
2759
- * waits, however long the wait is.
2760
- *
2761
- * Identity is revalidated the way `preparedFoldError` revalidates a prepared fold. A
2762
- * fold that was expanded, reclaimed, re-briefed by the agent, or rebuilt over a
2763
- * different span is a different object than the one the generator read, and its upgrade
2764
- * is DROPPED rather than deferred.
2765
- *
2766
- * It lands in the brief OVERRIDE map, the same channel the agent's own `rebrief` uses,
2767
- * and carries its generator beside the text. A fold record is content-addressed and
2768
- * immutable: rewriting one in place reports a conflicting durable fold at the next
2769
- * persist and suspends automatic management, which is precisely why the override map
2770
- * exists.
2771
- *
2772
- * EVERY finished brief lands, and there is no per-boundary cap. A prefix cache is
2773
- * invalidated from the FIRST byte that differs, so the commit's mutation point is the
2774
- * position of the earliest fold it upgrades and every later upgrade in the same commit
2775
- * sits inside a suffix that break already re-sent: the second and third upgrade on one
2776
- * boundary cost nothing the first did not already cost. Holding one back does not save
2777
- * that cost, it defers the same break to a later commit and pays it there on top of
2778
- * whatever that commit does. What bounds the count is the work that can be outstanding,
2779
- * MAX_BRIEF_UPGRADE_QUEUE waiting plus MAX_BRIEF_UPGRADES_IN_FLIGHT running, and the
2780
- * boundary that clears them.
2781
- */
2782
- const applyBriefUpgrades = (): string[] => {
2783
- if (!upgrades.ready.length || !persistence.state) return [];
2784
- const applied: string[] = [];
2785
- for (const entry of upgrades.ready) {
2786
- const state = persistence.state;
2787
- const fold = state.folds.find((item) => item.id === entry.foldId);
2788
- if (!fold || fold.sourceSha256 !== entry.sourceSha256 ||
2789
- foldProvenance(fold, state).kind !== "deterministic" ||
2790
- state.expanded.includes(fold.id) || state.briefs?.[fold.id] !== undefined) continue;
2791
- persistence.state = {
2792
- ...state,
2793
- briefs: {
2794
- ...(state.briefs ?? {}),
2795
- [fold.id]: { brief: entry.brief, provenance: clone(entry.provenance) },
2796
- },
2797
- };
2798
- applied.push(fold.id);
2799
- }
2800
- upgrades.ready = [];
2801
- return applied;
2802
- };
2803
-
2804
- const commitDeterministicCandidate = async (
2805
- snapshot: ActiveContextSnapshot,
2806
- candidate: FoldCandidate,
2807
- brief: string,
2808
- ): Promise<string> => {
2809
- const stateBeforeCommit = persistence.state!;
2810
- const preparedFold = await prepareFold({
2811
- candidate,
2812
- snapshot,
2813
- state: stateBeforeCommit,
2814
- generation: lifecycle.generation,
2815
- brief,
2816
- briefProvenance: "deterministic",
2817
- });
2818
- persistence.state = commitPreparedFold({
2819
- prepared: preparedFold,
2820
- snapshot,
2821
- state: stateBeforeCommit,
2822
- generation: lifecycle.generation,
2823
- });
2824
- queueBriefUpgrades(snapshot, stateBeforeCommit, [preparedFold.id]);
2825
- return preparedFold.id;
2826
- };
2827
-
2828
1785
  const prepareAndCommitExplicit = async (input: {
2829
1786
  snapshot: ActiveContextSnapshot;
2830
1787
  candidate: FoldCandidate;
@@ -2846,7 +1803,6 @@ export function registerActiveContext(pi: any, options: {
2846
1803
  state: baseState,
2847
1804
  generation: generationAtStart,
2848
1805
  brief: input.brief,
2849
- summarize: observedSummarize,
2850
1806
  ctx: input.ctx,
2851
1807
  signal: input.signal,
2852
1808
  });
@@ -2866,18 +1822,6 @@ export function registerActiveContext(pi: any, options: {
2866
1822
  return { preparedFold, nextState };
2867
1823
  };
2868
1824
 
2869
- /**
2870
- * The one mutation of an epoch: every pending mark, plus the automatic additions
2871
- * a commit is allowed to make, applied through the same machinery as an immediate
2872
- * fold. Free additions come first (peek reads the agent already discarded), then
2873
- * the quota top-up that guarantees the commit is worth its rewrite.
2874
- */
2875
- /**
2876
- * One turn of inflow, as a share of the window: the least a commit at high occupancy
2877
- * has to free to be worth its rewrite. Measured inflow is used when the session has
2878
- * any -- rep13 ran at a median 13,865 and a maximum 27,815 tokens per request against
2879
- * a 400,000 window -- and the floor share stands in until then.
2880
- */
2881
1825
  const commitDepthFloorShare = (snapshot: ActiveContextSnapshot): number => {
2882
1826
  const window = snapshot.contextWindow;
2883
1827
  if (!Number.isFinite(window) || window <= 0) return COMMIT_RECLAIM_FLOOR_SHARE;
@@ -2890,89 +1834,18 @@ export function registerActiveContext(pi: any, options: {
2890
1834
  return occupancy !== null && occupancy >= snapshot.policy.refoldRatio;
2891
1835
  };
2892
1836
 
2893
- /**
2894
- * THE OUTPUT WALL.
2895
- *
2896
- * A declared serving budget has already netted out the reservation the answer needs,
2897
- * so the runtime treats the whole budget as spendable and fences only when it is
2898
- * spent. That fence is the input one, and the input is not what fails first. The host
2899
- * derives the answer's ceiling per request as its DESCRIPTOR window less its own
2900
- * estimate of the projection less a fixed safety margin, so filling the declared
2901
- * budget to the brim leaves the answer exactly the reservation and nothing else.
2902
- *
2903
- * Which is a fence that fires after the wire, the same defect the transmission fence
2904
- * was given a forward look to fix in rep 13. The commit trigger never got one.
2905
- * Measured 2026-08-12 (sol-20260812 rep 1): occupancy walked 218,713 -> 236,595 over
2906
- * twelve ordinals against a 251,520 budget with no commit, and the request built after
2907
- * the last measurement was served 16 output tokens and aborted. Every number was known
2908
- * to the runtime; nothing was weighing the request that had not been built yet.
2909
- *
2910
- * So the trigger carries what the transmission fence already carries: one worst recent
2911
- * inflow step. With no measured inflow this is exactly the old `used > budget`
2912
- * condition, which is the state it degrades to on a session's first turns.
2913
- */
2914
1837
  const outputWallDue = (snapshot: ActiveContextSnapshot): boolean => {
2915
1838
  const capacity = servingCapacity(snapshot.contextWindow);
2916
1839
  if (capacity.usedTokens === null || !(capacity.budgetTokens > 0)) return false;
2917
- // THE EARLY ZONE ONLY, so this is strictly additive.
2918
- //
2919
- // Past the budget the pre-existing overflow paths already own the emergency: the
2920
- // commit-path exemption, the last-call gate and the fence all read `used > budget`
2921
- // and have since before this existed. A second trigger in that territory changes the
2922
- // cadence of sessions that were already being handled, and gate 107 measured what
2923
- // that costs: a fixture parked at 88,000 against an 83,616 budget put four generator
2924
- // calls in flight against a bound of two. So the wall speaks only where nothing spoke
2925
- // before, in the band one inflow step wide below the budget.
2926
1840
  if (capacity.usedTokens > capacity.budgetTokens) return false;
2927
1841
  return capacity.usedTokens + expectedWallInflowTokens() > capacity.budgetTokens;
2928
1842
  };
2929
1843
 
2930
- /**
2931
- * What the gated round did, measured against the arming snapshot. Pins and unpins
2932
- * are read from the stream itself (context.protect records after the exposure); the
2933
- * call and mark deltas are clamped at zero because contextCalls is process-local and
2934
- * a reload inside a round must not report a negative response.
2935
- */
2936
- const lastCallAttribution = (
2937
- lastCall: NonNullable<ActiveContextState["lastCall"]>,
2938
- agentMarksNow: number,
2939
- ): { responded: boolean; context_calls: number; marks_added: number; protects: number; unprotects: number } => {
2940
- const contextCalls = Math.max(0, curation.contextCalls - lastCall.contextCalls);
2941
- const protectRecords = instrumentation.ledger.events.filter((record) =>
2942
- record.seq > lastCall.exposure && record.kind === "context.protect");
2943
- const protects = protectRecords.filter((record) => record.protect === true).length;
2944
- return {
2945
- responded: contextCalls > 0,
2946
- context_calls: contextCalls,
2947
- marks_added: Math.max(0, agentMarksNow - lastCall.agentMarks),
2948
- protects,
2949
- unprotects: protectRecords.length - protects,
2950
- };
2951
- };
2952
-
2953
- const clearLastCall = (): void => {
2954
- if (!persistence.state?.lastCall) return;
2955
- const next = { ...persistence.state };
2956
- delete next.lastCall;
2957
- persistence.state = next;
2958
- curation.lastCallDelivery = null;
2959
- };
2960
-
2961
1844
  const runCommitEpoch = async (
2962
1845
  snapshot: ActiveContextSnapshot,
2963
1846
  trigger: string,
2964
1847
  topUp: boolean,
2965
- /**
2966
- * Pressure the waiver is measured against. Defaults to the measured ratio; the
2967
- * over-budget reduction forces the fence so nothing survivable is held back.
2968
- */
2969
1848
  waiverRatio: number | null = measurements.latestRatio,
2970
- /**
2971
- * A user asked for this commit. It outranks the two ECONOMIC guards -- the reclaim
2972
- * floor and the one-mutation-per-handoff budget -- because those exist to spend the
2973
- * session's rewrites well and the user just said where to spend one. It outranks
2974
- * nothing else: freshness, pins, exactness and the provider fence are unchanged.
2975
- */
2976
1849
  userRequested = false,
2977
1850
  ): Promise<Record<string, unknown> | null> => {
2978
1851
  const ordinal = markOrdinal(snapshot);
@@ -2985,79 +1858,16 @@ export function registerActiveContext(pi: any, options: {
2985
1858
  const addition = addPendingMark(state, mark);
2986
1859
  if (addition.added) { state = addition.state; peekAdded += 1; }
2987
1860
  }
2988
- // THE COUNT LAW RUNS AT EVERY COMMIT EPOCH, BEFORE ANYTHING ELSE PROPOSES.
2989
- //
2990
- // The number of parents the eligible-root count owes is arithmetic, not a judgment
2991
- // about pressure, so it is not the top-up's to make and not the user commit's to
2992
- // skip: at any point the count allows k groups, k parents form. Running first is
2993
- // what makes the rest coherent -- the groups claim their children before the top-up
2994
- // reads the claim set, so nothing proposes a span over a fold a parent is taking.
2995
1861
  for (const mark of consolidationMarks({ snapshot, state, ordinal })) {
2996
1862
  const addition = addPendingMark(state, mark);
2997
1863
  if (addition.added) { state = addition.state; consolidationAdded += 1; }
2998
1864
  }
2999
1865
  const guarded = currentTurnRefKeys(snapshot);
3000
- // THE GUARD IS ADJUDICATED AT COMMIT, NEVER AT PROPOSAL.
3001
- //
3002
- // `guarded` is every tool result since the last terminal assistant message. When no
3003
- // turn has ever closed, `currentTurnBoundary` is -1 and that set is the WHOLE
3004
- // window. Handing it to `topUpMarks` as `excludeRefKeys` therefore proposed nothing
3005
- // at all on that shape, so `guardWaiverCount` below counted zero guarded marks and
3006
- // the waiver it exists to grant could never fire. Measured 2026-08-10
3007
- // (luna-20260810 pifold rep 2): 274,173 tokens of unmarked stale spans, zero marks
3008
- // proposed, zero commits, two provider rejections.
3009
- //
3010
- // So the top-up proposes freely and `commitPendingMarks({ guardCurrentTurn: true,
3011
- // guardWaiver })` decides. That is the only place the guard has ever had a waiver,
3012
- // and one adjudicator is why the starvation case is reachable at all.
3013
- //
3014
- // Wedge absorption keeps the exclusion (below): it grows a mark backward over a
3015
- // gap without any waiver of its own, so the guard there has no second chance.
3016
- // THE CLASS LAW IS UNCONDITIONAL.
3017
- //
3018
- // There was a fence-only snapshot here: at high occupancy it narrowed the fresh
3019
- // tail to a quarter and extended the automatic reach over the middle, so a reduction
3020
- // that had to make a rejected request sendable had mass to reach. That existed
3021
- // because the runtime had exactly one answer to a provider rejection, folding
3022
- // harder, and folding harder inside a positional region runs out of legal material.
3023
- // The rollback lane is the answer now: an overflow rolls the leaf back past the
3024
- // request that failed and the ordinary commit runs on the shorter window. So the
3025
- // law holds in EVERY snapshot at every occupancy -- membership decides what folds,
3026
- // the fresh tail never folds, pins are exempt -- and there is one set of rules to
3027
- // reason about instead of two.
3028
- // The thermostat. Firing at the trigger line and folding down to the target line is
3029
- // what makes event SPACING structural rather than hoped for.
3030
1866
  const capacity = servingCapacity(snapshot.contextWindow);
3031
1867
  const usedTokens = capacity.usedTokens;
3032
1868
  const budgetTokens = capacity.budgetTokens;
3033
- // THE UNTRANSMISSIBILITY EXEMPTION, NARROWED.
3034
- //
3035
- // A request whose projection exceeds the provider input budget is rejected outright,
3036
- // so recovery must produce a window that fits. The hard fence, though, is a RATIO
3037
- // prediction. Standing near it is not the same as being unable to send, and treating
3038
- // the two alike handed the fence path a standing waiver from both economy guards. Measured 2026-08-07 (rep 17): fence-path
3039
- // window-pressure commits fired at eligible-freed shares as low as 0.018, under the
3040
- // 0.02 floor the guided path honors, and re-fired inside a single ordinal. So only
3041
- // two states outrank the economy: the overflow recovery lane, which runs because a
3042
- // request already did not fit, and an occupancy genuinely past the serving budget,
3043
- // where the next request aborts unless something moves. Everything else defers.
3044
- // The output wall deliberately does NOT join this list. It decides WHEN the one
3045
- // structural mutation of a handoff fires, not how many fire: exempting it here let a
3046
- // window parked one inflow step under the budget rebuild its prefix on every pass,
3047
- // which is the cost the mutation budget exists to refuse and what gate 58 caught.
3048
1869
  const overflowExempt = userRequested || curation.recoveryAttempts > 0 ||
3049
1870
  (usedTokens !== null && budgetTokens > 0 && usedTokens > budgetTokens);
3050
- // ONE STRUCTURAL MUTATION PER HANDOFF.
3051
- //
3052
- // Measured 2026-08-06 (rep 15): two context.commit records 50ms apart inside one
3053
- // ordinal, revisions 14 and 15 -- two REAL mutations, not a duplicated record. The
3054
- // pass had committed at the announced trigger, rebuilt the projection, found it
3055
- // still CROWDED (inside the fence margin, but transmissible), and committed again.
3056
- // The second commit bought margin the next pass would have bought anyway and cost a
3057
- // whole second prefix rewrite. So a second commit in the same handoff defers unless
3058
- // the request is genuinely untransmittable: a request whose projection exceeds the
3059
- // provider input budget is rejected outright, so recovery must produce a window that
3060
- // fits, and the fence and the recovery lane spend the budget to get one.
3061
1871
  if (instrumentation.mutationsSinceHandoff > 0 && !overflowExempt) {
3062
1872
  emit("context.commit", {
3063
1873
  trigger,
@@ -3069,20 +1879,10 @@ export function registerActiveContext(pi: any, options: {
3069
1879
  });
3070
1880
  return null;
3071
1881
  }
3072
- // THE HYSTERESIS, AND THE WHOLE FREEING TARGET.
3073
- //
3074
- // How deep this event cuts is one subtraction on one denominator: what is used,
3075
- // less where the thermostat wants to land, over the serving budget. The separate
3076
- // 0.40 floor is gone -- it was a share of the WINDOW under a share of the BUDGET,
3077
- // so it never once bound (the hysteresis share at these thresholds bottoms out at
3078
- // 0.405 of window), and a floor that cannot fire is a number that only drifts.
3079
1882
  const freeingTarget = usedTokens === null || budgetTokens <= 0
3080
1883
  ? 0
3081
1884
  : Math.max(0, (usedTokens - thresholds.minTarget * budgetTokens) / budgetTokens);
3082
1885
  if (topUp) {
3083
- // Measuring top-up progress against ELIGIBLE mass is what keeps the pressure
3084
- // backstop working under a peek-heavy agent: pinned and retained marks are mass
3085
- // no commit can move, and counting them as progress stops the top-up dead.
3086
1886
  for (const mark of topUpMarks({
3087
1887
  snapshot,
3088
1888
  state,
@@ -3093,17 +1893,6 @@ export function registerActiveContext(pi: any, options: {
3093
1893
  const addition = addPendingMark(state, mark);
3094
1894
  if (addition.added) { state = addition.state; topUpAdded += 1; }
3095
1895
  }
3096
- // DEPTH, inside the zones.
3097
- //
3098
- // Near the top of the window a commit that frees less than one turn of inflow
3099
- // does not reduce anything: it pays a full prefix rewrite, gives back less than
3100
- // the next stage adds, and the window ratchets UP through commit after commit.
3101
- // Measured 2026-08-06 (rep13): once the big stale mass was folded, six commits of
3102
- // two to four folds each carried the window from 340k to 370k and into a provider
3103
- // rejection, with the backstop firing the whole way. So a commit at or above the
3104
- // backstop that has not reached one inflow step tops up against everything
3105
- // ELIGIBLE instead of billing a rewrite for crumbs. Eligible is the operative
3106
- // word: this reaches harder inside what the class law admits, never outside it.
3107
1896
  const reachedShare = markAccounting(snapshot, state).eligibleFreedBudgetShare;
3108
1897
  const shallow = reachedShare < Math.max(commitDepthFloorShare(snapshot), freeingTarget);
3109
1898
  if (shallow && atOrAboveBackstop(snapshot, waiverRatio)) {
@@ -3119,9 +1908,6 @@ export function registerActiveContext(pi: any, options: {
3119
1908
  }
3120
1909
  }
3121
1910
  }
3122
- // Boundary slivers ride along in the mutation this commit already pays for; they
3123
- // are never a mutation of their own, and a gap above the tiny token threshold is
3124
- // deliberate curation the absorber must not touch.
3125
1911
  const wedges = absorbWedgeMarks({
3126
1912
  snapshot,
3127
1913
  state,
@@ -3130,18 +1916,6 @@ export function registerActiveContext(pi: any, options: {
3130
1916
  });
3131
1917
  state = wedges.state;
3132
1918
  const accounting = markAccounting(snapshot, state);
3133
- // A COMMIT PASS THAT FINDS NOTHING SAYS SO.
3134
- //
3135
- // This was a bare `return null`, and it is how the rep-2 starvation stayed invisible
3136
- // for 25 stages: the last call announced 274,173 tokens of unmarked stale spans, the
3137
- // pass that answered it proposed nothing, and the stream carried no record that a
3138
- // commit had even been attempted. Every other deferral on this path already names
3139
- // itself; this one is the same shape with the reason that matters, and it reports
3140
- // the remainder beside the emptiness so the contradiction -- mass on the table, no
3141
- // proposal -- is readable on one record instead of inferred across two.
3142
- //
3143
- // Stream record, not a `context.receipt`: receipts are window carriers, and a pass
3144
- // that changed nothing must not add bytes to the projection to announce it.
3145
1919
  if (!accounting.pending) {
3146
1920
  const remainder = unmarkedRemainder(snapshot, state, projectionCharsPerToken());
3147
1921
  emit("context.commit", {
@@ -3156,12 +1930,6 @@ export function registerActiveContext(pi: any, options: {
3156
1930
  });
3157
1931
  return null;
3158
1932
  }
3159
- // The reclaim floor. One structural mutation per model call is the budget, so a
3160
- // commit that would free crumbs spends the whole budget on nothing: it defers and
3161
- // the marks accumulate. A request whose projection exceeds the provider input budget
3162
- // is rejected outright, so recovery must produce a window that fits: genuine overflow
3163
- // -- the recovery lane, or an occupancy already past the serving budget -- fires
3164
- // regardless of what it frees. Standing at the fence RATIO does not.
3165
1933
  if (!overflowExempt &&
3166
1934
  accounting.eligibleFreedBudgetShare < COMMIT_RECLAIM_FLOOR_SHARE) {
3167
1935
  persistence.state = state;
@@ -3179,19 +1947,12 @@ export function registerActiveContext(pi: any, options: {
3179
1947
  return null;
3180
1948
  }
3181
1949
  const bytesBefore = bytes(projectActiveContext(snapshot, state));
3182
- // The guard protects an in-flight excursion, never at the cost of the session's
3183
- // ability to send a request at all: above the pressure backstop the oldest guarded
3184
- // marks are released. The guard is a protection with a WAIVER, which is why it
3185
- // survived the fence-snapshot deletion: one protection, one owner, one waiver.
3186
1950
  const guardWaiver = guardWaiverCount({
3187
1951
  snapshot,
3188
1952
  ratio: waiverRatio,
1953
+ boundary: trigger === "compaction-boundary",
3189
1954
  guardedMarks: pendingMarks(state).filter((mark) =>
3190
1955
  markTouchesCurrentTurn(state, mark, guarded)).length,
3191
- // The starvation test asks the same question the commit will, against the same
3192
- // snapshot the commit adjudicates against: does this epoch have work that does
3193
- // not touch the open turn? Two snapshots gave two answers, and the one that
3194
- // decided the commit was not the one being asked. There is one snapshot now.
3195
1956
  otherApplicableMarks: pendingMarks(state).filter((mark) =>
3196
1957
  !markTouchesCurrentTurn(state, mark, guarded) &&
3197
1958
  markEligibility(snapshot, state, mark) === "eligible").length,
@@ -3204,17 +1965,7 @@ export function registerActiveContext(pi: any, options: {
3204
1965
  guardCurrentTurn: true,
3205
1966
  guardWaiver,
3206
1967
  });
3207
- // THE EPOCH CLOSES ITS OWN COUNT.
3208
- //
3209
- // The folds this commit just landed are eligible roots the moment they exist, and
3210
- // the law is about the count, not about which pass noticed it. Leaving them for the
3211
- // next epoch is what let the pile stand between commits: measured 2026-08-10 (PT-3),
3212
- // a commit that landed 26 tool folds left 32 visible roots up until the next band
3213
- // crossing four cycles later. So the epoch re-reads its own count and parents what
3214
- // it just made, inside the rewrite it has already paid for. No waiver here: a parent
3215
- // this round cannot apply is held by the ordinary guard and waits, exactly like any
3216
- // other fold. It converges because a parent is excluded from the count it came from.
3217
- for (let round = 0; round < EPOCH_CONSOLIDATION_ROUNDS; round += 1) {
1968
+ for (;;) {
3218
1969
  let closing = result.state;
3219
1970
  for (const mark of consolidationMarks({ snapshot, state: closing, ordinal })) {
3220
1971
  const addition = addPendingMark(closing, mark);
@@ -3229,9 +1980,6 @@ export function registerActiveContext(pi: any, options: {
3229
1980
  guardCurrentTurn: true,
3230
1981
  });
3231
1982
  if (!closed.applied.length) break;
3232
- // A mark the guard RETAINED is still pending, so the closing round sees it again
3233
- // and reports it again; only the terminal refusals accumulate, and the last round
3234
- // is the truth about what is still held.
3235
1983
  result = {
3236
1984
  ...closed,
3237
1985
  applied: [...result.applied, ...closed.applied],
@@ -3240,20 +1988,8 @@ export function registerActiveContext(pi: any, options: {
3240
1988
  };
3241
1989
  }
3242
1990
  persistence.state = result.state;
3243
- // The upgrade wedge: model briefs written since the last boundary replace their
3244
- // deterministic ones HERE, inside the mutation this commit already pays for, before
3245
- // anything measures what the commit did.
3246
- const upgradedFolds = applyBriefUpgrades();
3247
- const upgradeFailures = upgrades.failures;
3248
- const upgradeError = upgrades.lastError;
3249
- const upgradeCures = upgrades.cures;
3250
- upgrades.failures = 0;
3251
- upgrades.cures = 0;
3252
- upgrades.lastError = null;
3253
1991
  const bytesAfter = bytes(projectActiveContext(snapshot, persistence.state));
3254
1992
  const freedBytes = Math.max(0, bytesBefore - bytesAfter);
3255
- // The cost of the agent's pins, measured at the moment it matters: mass this
3256
- // commit could not touch because protect holds it.
3257
1993
  const pinHeld = protectedStaleMass(snapshot, result.state);
3258
1994
  const commitEvent = emit("context.commit", {
3259
1995
  trigger,
@@ -3261,19 +1997,12 @@ export function registerActiveContext(pi: any, options: {
3261
1997
  reason: null,
3262
1998
  eligible_freed_share: accounting.eligibleFreedBudgetShare,
3263
1999
  reclaim_floor_share: COMMIT_RECLAIM_FLOOR_SHARE,
3264
- // The two first-class dials: how much ONE event reclaims, and how long since the
3265
- // last one. A trigger that frees too little re-fires immediately, and that shape
3266
- // is only visible with both numbers on the same record.
3267
2000
  target_freed_share: freeingTarget,
3268
2001
  hysteresis_target_share: freeingTarget,
3269
2002
  target_occupancy_share: thresholds.minTarget,
3270
2003
  shortfall_share: Math.max(0, freeingTarget - accounting.eligibleFreedBudgetShare),
3271
2004
  occupancy_tokens_before: usedTokens,
3272
2005
  budget_tokens: budgetTokens,
3273
- // The forward look, on the record beside the occupancy it was added to. A commit
3274
- // that fired because one more turn would have spent the answer's reservation reads
3275
- // differently from one that fired at the band top, and the difference is only
3276
- // legible with the allowance printed.
3277
2006
  expected_inflow_tokens: expectedWallInflowTokens(),
3278
2007
  output_wall: outputWallDue(snapshot),
3279
2008
  requests_since_previous: instrumentation.requests - instrumentation.lastMutationRequest,
@@ -3281,8 +2010,6 @@ export function registerActiveContext(pi: any, options: {
3281
2010
  ? null
3282
2011
  : usedTokens - instrumentation.lastMutationTokens,
3283
2012
  applied_marks: result.applied.length,
3284
- // Refusal is TERMINAL only. A mark whose span was still fresh is deferred, not
3285
- // refused: it is held and folds at the first commit after the span ages out.
3286
2013
  refused_marks: result.refused.filter((mark) => !mark.retained).length,
3287
2014
  deferred_marks: result.retained.length,
3288
2015
  waived_marks: result.waived.length,
@@ -3294,28 +2021,6 @@ export function registerActiveContext(pi: any, options: {
3294
2021
  consolidation_marks: consolidationAdded,
3295
2022
  closing_consolidation_marks: closingAdded,
3296
2023
  absorbed_wedges: wedges.absorbed.length,
3297
- // The upgrade is a mutation of a fold whose `context.fold` record was written at
3298
- // creation, so the stream would otherwise show a brief that silently changed. The
3299
- // count, the ids, and the failures ride the boundary that carried them.
3300
- brief_upgrades: upgradedFolds.length,
3301
- brief_upgrade_ids: upgradedFolds.join(","),
3302
- brief_upgrade_failures: upgradeFailures,
3303
- // Briefs that needed a second ask before they met the contract. Beside the failures
3304
- // rather than inside them: a cured brief is a brief that landed, and the two together
3305
- // are how the brief cap gets judged against something other than intuition.
3306
- brief_upgrade_cures: upgradeCures,
3307
- brief_upgrade_error: upgradeError,
3308
- // Everything still owed to a FOLD: queued, in flight, and (always zero once the
3309
- // wedge above ran) written but uncarried. In flight is counted because the lane
3310
- // holds several calls open and work nobody can see is work nobody bounds. Counted in
3311
- // folds rather than calls because a call now carries a whole commit's spans, and the
3312
- // question this answers is how many folds are still reading deterministic.
3313
- brief_upgrades_waiting: upgrades.ready.length + upgrades.running.size +
3314
- upgrades.queue.reduce((total, entry) => total + entry.members.length, 0),
3315
- // The same work in the unit the lane's two constants actually bound: calls, queued
3316
- // plus in flight. Reported beside the fold count so a backed-up lane cannot read as
3317
- // a busy one, or the reverse.
3318
- brief_upgrade_calls: upgrades.queue.length + new Set(upgrades.running.values()).size,
3319
2024
  freed_bytes: freedBytes,
3320
2025
  freed_tokens: estimatedTokens(freedBytes),
3321
2026
  rewrite_tokens: accounting.rewriteTokens,
@@ -3328,39 +2033,6 @@ export function registerActiveContext(pi: any, options: {
3328
2033
  instrumentation.mutationsSinceHandoff += 1;
3329
2034
  instrumentation.lastMutationRequest = instrumentation.requests;
3330
2035
  instrumentation.lastMutationTokens = usedTokens;
3331
- // THE RESPONSE ATTRIBUTION. Whatever the gated round did, or that it did nothing,
3332
- // is linked to the exposure it answered, and the exposure is consumed by the
3333
- // commit whatever its trigger: a fence or user commit landing mid-round is still
3334
- // the commit boundary the last-call announced. The carrier's disappearance rides
3335
- // this commit's own rewrite.
3336
- if (persistence.state.lastCall) {
3337
- const lastCall = persistence.state.lastCall;
3338
- const attribution = lastCallAttribution(lastCall, accounting.agentMarks);
3339
- emit("context.response", {
3340
- exposure_seq: lastCall.exposure,
3341
- commit_seq: commitEvent.seq,
3342
- trigger,
3343
- outcome: attribution.responded ? "responded" : "silent",
3344
- ...attribution,
3345
- });
3346
- clearLastCall();
3347
- }
3348
- // A commit that drops occupancy back under a waypoint re-arms its notice: the next
3349
- // upward crossing is a new event and earns a new one. The estimate is the same one
3350
- // the receipt reports: measured occupancy before, less what this commit freed.
3351
- if (persistence.state.notices && usedTokens !== null && budgetTokens > 0) {
3352
- const postOccupancy = Math.max(0, usedTokens - estimatedTokens(freedBytes)) / budgetTokens;
3353
- const fired = persistence.state.notices.fired.filter((share) => postOccupancy >= share);
3354
- if (fired.length !== persistence.state.notices.fired.length) {
3355
- persistence.state = { ...persistence.state, notices: { ...persistence.state.notices, fired } };
3356
- }
3357
- }
3358
- // The rider: at most ONE action prompt per fold epoch, composed from post-commit
3359
- // numbers, persisted as literal bytes, delivered beside the receipt inside the
3360
- // rewrite this commit already paid for. The epoch key is the commit event's own
3361
- // stream sequence: strictly monotone, one per applied commit, so refold-only
3362
- // epochs get their rider too and no two epochs can ever share a key. The next
3363
- // epoch REPLACES the text; nothing stacks.
3364
2036
  const riderEpoch = commitEvent.seq;
3365
2037
  if (persistence.state.rider?.epoch !== riderEpoch) {
3366
2038
  const postAccounting = markAccounting(snapshot, persistence.state);
@@ -3372,7 +2044,6 @@ export function registerActiveContext(pi: any, options: {
3372
2044
  const riderText = contextRiderText({
3373
2045
  toolName,
3374
2046
  brandNoun,
3375
- suggestion: deliverSurfacing(snapshot, "rider"),
3376
2047
  pendingAgentMarks: postAccounting.agentMarks,
3377
2048
  eligibleMarks: postAccounting.eligibleMarks,
3378
2049
  freedTokens: postAccounting.freedTokens,
@@ -3398,17 +2069,12 @@ export function registerActiveContext(pi: any, options: {
3398
2069
  const fold = persistence.state.folds.find((item) => item.id === applied.foldId);
3399
2070
  if (fold?.kind === "tool-result") foldedToolResults += 1;
3400
2071
  else foldedSpans += 1;
3401
- // A reclaimed peek copy names what it copied. Derived from the transcript rather
3402
- // than carried on the mark, so the pointer is the same whichever mechanism claimed
3403
- // the copy: the exposure's reclaim marking, the commit's, or the doorless ladder.
3404
2072
  const peekedSources = fold?.kind === "tool-result"
3405
2073
  ? peekedSourceFoldIds(snapshot, flattenFoldRefs(fold, persistence.state))
3406
2074
  : null;
3407
2075
  emit("context.fold", {
3408
2076
  commit_seq: commitEvent.seq,
3409
2077
  fold_id: applied.foldId,
3410
- // The MARK this fold came from. The stream is now the only account of what a
3411
- // commit applied, so it has to name both ends of that mapping.
3412
2078
  mark_id: applied.id,
3413
2079
  fold_kind: fold?.kind ?? applied.mark,
3414
2080
  origin: applied.origin,
@@ -3418,9 +2084,6 @@ export function registerActiveContext(pi: any, options: {
3418
2084
  brief_provenance: fold ? foldProvenance(fold, persistence.state).kind : null,
3419
2085
  });
3420
2086
  }
3421
- // Queued AFTER the applications above, so no fold can be committed and upgraded on
3422
- // one boundary: the generator has not run yet, and the wait is the mechanism.
3423
- queueBriefUpgrades(snapshot, state, result.applied.map((applied) => applied.foldId));
3424
2087
  for (const wedge of wedges.absorbed) {
3425
2088
  emit("context.absorb", {
3426
2089
  commit_seq: commitEvent.seq,
@@ -3433,9 +2096,7 @@ export function registerActiveContext(pi: any, options: {
3433
2096
  threshold_tokens: MAX_WEDGE_ABSORB_TOKENS,
3434
2097
  });
3435
2098
  }
3436
- // A bound-out top-up and a silently dropped agent mark are both invisible in an
3437
- // applied/refused list alone, so the epoch reports its own composition.
3438
- return {
2099
+ const epoch = {
3439
2100
  trigger,
3440
2101
  applied: result.applied,
3441
2102
  refused: result.refused,
@@ -3445,13 +2106,9 @@ export function registerActiveContext(pi: any, options: {
3445
2106
  peekMarks: peekAdded,
3446
2107
  topUpMarks: topUpAdded,
3447
2108
  consolidationMarks: consolidationAdded,
3448
- // Parents formed over the folds THIS commit landed. They were never in
3449
- // `pendingMarks`, so an epoch's arithmetic is applied = pending + closing.
3450
2109
  closingMarks: closingAdded,
3451
2110
  absorbedWedges: wedges.absorbed.length,
3452
2111
  absorbed: wedges.absorbed,
3453
- // What the commit actually folded, the way an agent counts it, so the receipt can
3454
- // report impact instead of an opaque mark total.
3455
2112
  foldedSpans,
3456
2113
  foldedToolResults,
3457
2114
  occupancyTokensBefore: usedTokens,
@@ -3482,125 +2139,18 @@ export function registerActiveContext(pi: any, options: {
3482
2139
  requestsSincePreviousCommit: instrumentation.requests - instrumentation.lastMutationRequest,
3483
2140
  instrumentation: ledgerSummary(instrumentation.ledger),
3484
2141
  };
2142
+ // The receipt is the LAST statement of the commit, and stays that way: harness gate
2143
+ // 54 reads a commit that reported applied marks and delivered no receipt as one that
2144
+ // threw partway and left its folds in the stream and nowhere else. The rung used to
2145
+ // write it because the rung used to own the epoch; the boundary owns it now.
2146
+ ladder.lastAutomaticAction = { kind: "epoch-commit", foldIds: [], sourceIds: [], epoch };
2147
+ ladder.pendingContextNote =
2148
+ `A commit epoch applied ${result.applied.length} pending mark(s) in one rewrite; ` +
2149
+ "exact evidence remains expandable.";
2150
+ noteAutomaticReceipt(snapshot, ladder.lastAutomaticAction, epoch);
2151
+ return epoch;
3485
2152
  };
3486
2153
 
3487
- /** The two curation signals, measured against the ONE serving budget. */
3488
- const measuredCurationSignals = (snapshot: ActiveContextSnapshot): CurationSignals => {
3489
- const capacity = servingCapacity(snapshot.contextWindow);
3490
- curation.lastSignals = curationSignals({
3491
- snapshot,
3492
- state: persistence.state!,
3493
- usedTokens: capacity.usedTokens,
3494
- budgetTokens: capacity.budgetTokens,
3495
- window: capacity.window,
3496
- charsPerToken: projectionCharsPerToken(),
3497
- eligibleFolds: markAccounting(snapshot, persistence.state!).eligibleMarks,
3498
- });
3499
- return curation.lastSignals;
3500
- };
3501
-
3502
- /**
3503
- * The silent early commit. The two signals decide, the reclaim floor stops a commit
3504
- * that would free nothing, and the hysteresis stops a plateau from reading as a
3505
- * stream of events. What is gone is only the announcement in front of it.
3506
- */
3507
- /**
3508
- * THE trigger, with its one piece of hysteresis.
3509
- *
3510
- * Occupancy at or above maxTarget, and then the reopen latch: a window that is still
3511
- * full because the last commit could not reach the target is the SAME event, not a
3512
- * new one, so a second commit waits for at least a reclaim floor of genuinely new
3513
- * eligible mass. Without it a parked window fires a commit per pass and every one of
3514
- * them rebuilds the prefix for crumbs.
3515
- */
3516
- const commitTriggerDue = (snapshot: ActiveContextSnapshot, ratio: number | null): boolean => {
3517
- if (!persistence.state) return false;
3518
- // The output wall outranks the quiet-runtime line rather than sitting under it. A
3519
- // window one inflow step from spending the answer's whole reservation is past
3520
- // economising, and the band top is not the thing it is about to cross.
3521
- //
3522
- // ONE COMMIT PER CROSSING, NOT ONE PER PASS. The wall is a level, and a window that
3523
- // sits on it sits there for many passes: releasing the reopen latch on each of them
3524
- // fires a commit per pass, which is the prefix-rewrite churn the latch exists to
3525
- // prevent and which the quiet cadence is built around. Measured on gate 52's fixture:
3526
- // the first wall commit applied 44 marks and correctly retained all ten of the open
3527
- // turn, and the two that followed it applied nothing, rewrote the prefix anyway, and
3528
- // dragged the guard's starvation waiver in on a session that had just made progress.
3529
- // So the crossing is the event. While the wall stays due the ordinary hysteresis
3530
- // decides, which is what makes a second commit wait for genuinely new foldable mass.
3531
- const wall = outputWallDue(snapshot);
3532
- if (!wall) curation.wallEpisodeOpen = false;
3533
- if (!wall && !epochCommitDue(snapshot, ratio)) return false;
3534
- measuredCurationSignals(snapshot);
3535
- if (wall && !curation.wallEpisodeOpen) {
3536
- curation.wallEpisodeOpen = true;
3537
- curation.reopenBaselineShare = null;
3538
- return true;
3539
- }
3540
- // The latch is an ECONOMY rule, and the fence is not latched: a request whose
3541
- // projection exceeds the provider input budget is rejected outright, so recovery
3542
- // must produce a window that fits.
3543
- // A request that does not fit gets its commit whether or not the previous one left
3544
- // new eligible mass behind; holding it back would be spending the session's
3545
- // transmissibility to save a prefix rewrite.
3546
- if (typeof ratio === "number" && Number.isFinite(ratio) && ratio >= hardFenceRatio(snapshot)) {
3547
- curation.reopenBaselineShare = null;
3548
- return true;
3549
- }
3550
- if (curation.reopenBaselineShare !== null) {
3551
- const eligibleShare = markAccounting(snapshot, persistence.state).eligibleFreedBudgetShare;
3552
- if (eligibleShare - curation.reopenBaselineShare < COMMIT_RECLAIM_FLOOR_SHARE) {
3553
- // A HOLD THAT SAYS SO.
3554
- //
3555
- // This was a bare `return false`, and it is the last silent deferral on the
3556
- // commit path: every other one names itself and reports its numbers. In
3557
- // sol-20260812 rep 1 the trigger was due for twelve straight ordinals while
3558
- // occupancy climbed to 94 percent of budget, and the stream carries no record of
3559
- // what held it, so the stall can be proven but not explained. Emitted on every
3560
- // held pass rather than once per episode: under-reporting is the defect being
3561
- // fixed, the record is a stream record that never reaches the projection, and
3562
- // the volume is bounded by passes above the band top.
3563
- const capacity = servingCapacity(snapshot.contextWindow);
3564
- emit("context.commit", {
3565
- trigger: "band-top",
3566
- deferred: true,
3567
- reason: "reopen-latch",
3568
- applied_marks: 0,
3569
- eligible_freed_share: eligibleShare,
3570
- reopen_baseline_share: curation.reopenBaselineShare,
3571
- reclaim_floor_share: COMMIT_RECLAIM_FLOOR_SHARE,
3572
- occupancy_tokens: capacity.usedTokens,
3573
- expected_inflow_tokens: expectedWallInflowTokens(),
3574
- budget_tokens: capacity.budgetTokens,
3575
- window_tokens: snapshot.contextWindow,
3576
- });
3577
- return false;
3578
- }
3579
- curation.reopenBaselineShare = null;
3580
- }
3581
- return true;
3582
- };
3583
-
3584
- /**
3585
- * Condition (a) of the reopen hysteresis, evaluated on EVERY context pass. A window
3586
- * that fell back under the trigger has ended its cycle, and the next crossing is a
3587
- * fresh event. This cannot live inside the trigger: the quiet passes that matter are
3588
- * exactly the ones too far below it to evaluate it.
3589
- */
3590
- const clearCommitLatchBelowTrigger = (): void => {
3591
- if (curation.reopenBaselineShare === null) return;
3592
- const capacity = servingCapacity(lifecycle.latestSnapshot?.contextWindow ?? null);
3593
- if (capacity.usedTokens === null || capacity.budgetTokens <= 0) return;
3594
- if (capacity.usedTokens / capacity.budgetTokens < thresholds.maxTarget) {
3595
- curation.reopenBaselineShare = null;
3596
- }
3597
- };
3598
-
3599
- /**
3600
- * One receipt per automatic context action, in the window and in the durable stream.
3601
- * Informatory, never exhortative: it says what happened, what it freed, and which
3602
- * verbs correct it. A mark that changed nothing is not an event and gets no receipt.
3603
- */
3604
2154
  const noteAutomaticReceipt = (
3605
2155
  snapshot: ActiveContextSnapshot,
3606
2156
  action: Record<string, unknown>,
@@ -3623,7 +2173,6 @@ export function registerActiveContext(pi: any, options: {
3623
2173
  foldsCommitted: epoch ? Number(epoch.appliedMarks ?? 0) : 0,
3624
2174
  foldsCreated: foldIds || (epoch ? Number(epoch.appliedMarks ?? 0) : 0),
3625
2175
  freedTokens,
3626
- // The impact, in the same unit the budget is stated in.
3627
2176
  occupancyBefore,
3628
2177
  occupancyAfter: occupancyBefore === null ? null : Math.max(0, occupancyBefore - freedTokens),
3629
2178
  spansFolded: epoch ? Number(epoch.foldedSpans ?? 0) : foldIds,
@@ -3637,234 +2186,6 @@ export function registerActiveContext(pi: any, options: {
3637
2186
  }));
3638
2187
  };
3639
2188
 
3640
- /**
3641
- * Threshold notices, evaluated on every pass the ladder runs on. One waypoint fires
3642
- * once per upward crossing of the measured occupancy; delivery is an append-once
3643
- * carrier plus its stream record, and re-arming belongs to the commit that drops
3644
- * occupancy back under the line. Default on; `guidance.thresholdNotices: false`
3645
- * registers the runtime with the waypoints silent.
3646
- */
3647
- const deliverThresholdNotices = (snapshot: ActiveContextSnapshot): boolean => {
3648
- if (!guidance.thresholdNotices || !persistence.state) return false;
3649
- const capacity = servingCapacity(snapshot.contextWindow);
3650
- if (capacity.usedTokens === null || capacity.budgetTokens <= 0) return false;
3651
- const occupancy = capacity.usedTokens / capacity.budgetTokens;
3652
- const current = persistence.state.notices ?? { fired: [], ring: [] };
3653
- let fired = current.fired;
3654
- let ring = current.ring;
3655
- let changed = false;
3656
- for (const share of THRESHOLD_NOTICE_SHARES) {
3657
- if (occupancy < share || fired.includes(share)) continue;
3658
- const text = thresholdNoticeText({
3659
- share,
3660
- occupancyTokens: capacity.usedTokens,
3661
- budgetTokens: capacity.budgetTokens,
3662
- maxTarget: thresholds.maxTarget,
3663
- toolName,
3664
- brandNoun,
3665
- });
3666
- fired = [...fired, share];
3667
- ring = [...ring, { share, ordinal: markOrdinal(snapshot), text }];
3668
- if (ring.length > MAX_THRESHOLD_NOTICES) ring = ring.slice(ring.length - MAX_THRESHOLD_NOTICES);
3669
- changed = true;
3670
- emit("context.notice", {
3671
- share,
3672
- occupancy,
3673
- occupancy_tokens: capacity.usedTokens,
3674
- budget_tokens: capacity.budgetTokens,
3675
- max_target: thresholds.maxTarget,
3676
- chars: text.length,
3677
- });
3678
- }
3679
- if (changed) persistence.state = { ...persistence.state, notices: { fired, ring } };
3680
- return changed;
3681
- };
3682
-
3683
- /**
3684
- * The same selection, read rather than delivered: what the next carrier WOULD say,
3685
- * with the ledger that decides whether it says anything at all.
3686
- */
3687
- const statusSurfacing = (snapshot: ActiveContextSnapshot): Record<string, unknown> => {
3688
- const ledger = persistence.state ? surfacingLedger(persistence.state) : [];
3689
- if (!persistence.state) return { slate: [], line: null, ledger, silenced: [] };
3690
- const selection = selectSurfacingSlate({
3691
- state: persistence.state,
3692
- snapshot,
3693
- toolName,
3694
- ordinal: markOrdinal(snapshot),
3695
- });
3696
- return {
3697
- slate: selection.slate.map((suggestion) => ({
3698
- id: suggestion.id,
3699
- route: suggestion.route,
3700
- contentScore: suggestion.contentScore,
3701
- briefScore: suggestion.briefScore,
3702
- margin: suggestion.margin,
3703
- slot: suggestion.slot,
3704
- })),
3705
- line: surfacingSlateText({ slate: selection.slate, queryTerms: selection.queryTerms, brandNoun }),
3706
- considered: selection.considered,
3707
- divergent: selection.divergent,
3708
- suppressed: selection.suppressed,
3709
- intentTerms: selection.queryTerms.size,
3710
- contentHit: SURFACING_CONTENT_HIT,
3711
- briefHit: SURFACING_BRIEF_HIT,
3712
- divergenceMargin: SURFACING_DIVERGENCE_MARGIN,
3713
- slateSize: SURFACING_SLATE_SIZE,
3714
- silenced: [...surfacingSilenced(ledger)],
3715
- ledger,
3716
- };
3717
- };
3718
-
3719
- /**
3720
- * THE SURFACING SLATE, delivered.
3721
- *
3722
- * The agent cannot peek a fold it does not know to want, so one line names the fold
3723
- * whose stored content matches the task in hand when its brief does not. Where it
3724
- * lands is the whole economics: only carriers that ride a rewrite the runtime is
3725
- * already paying for (the pre-commit last call and the post-commit rider) plus the
3726
- * on-demand status surface, which the agent asked for. The per-request ephemeral
3727
- * carrier stays dead; it cost 21.9% of every input token in rep 21 and nothing else
3728
- * about this build changes that verdict.
3729
- *
3730
- * One suggestion per delivery point, and most delivery points get none. Every
3731
- * delivery first resolves whatever offers have run out of window, so the ignore that
3732
- * silences a fold is recorded before the next selection reads the ledger.
3733
- */
3734
- const deliverSurfacing = (snapshot: ActiveContextSnapshot, carrier: string): string | null => {
3735
- if (!persistence.state) return null;
3736
- const ordinal = markOrdinal(snapshot);
3737
- const resolved = resolveSurfacing({ state: persistence.state, snapshot, ordinal });
3738
- persistence.state = resolved.state;
3739
- for (const transition of resolved.transitions) {
3740
- emit("context.outcome", {
3741
- fold_id: transition.id,
3742
- from_outcome: transition.from,
3743
- outcome: transition.to,
3744
- outcome_ordinal: transition.ordinal,
3745
- window_ordinals: SURFACING_OUTCOME_WINDOW_ORDINALS,
3746
- });
3747
- }
3748
- const selection = selectSurfacingSlate({ state: persistence.state, snapshot, toolName, ordinal });
3749
- const suggestion = selection.slate[0];
3750
- if (!suggestion) return null;
3751
- const text = surfacingSlateText({
3752
- slate: selection.slate,
3753
- queryTerms: selection.queryTerms,
3754
- brandNoun,
3755
- });
3756
- if (!text) return null;
3757
- persistence.state = issueSurfacing(persistence.state, suggestion.id, ordinal);
3758
- emit("context.suggestion", {
3759
- carrier,
3760
- fold_id: suggestion.id,
3761
- content_score: suggestion.contentScore,
3762
- brief_score: suggestion.briefScore,
3763
- margin: suggestion.margin,
3764
- content_hit: SURFACING_CONTENT_HIT,
3765
- brief_hit: SURFACING_BRIEF_HIT,
3766
- divergence_margin: SURFACING_DIVERGENCE_MARGIN,
3767
- slot: suggestion.slot,
3768
- slate_size: SURFACING_SLATE_SIZE,
3769
- fold_depth: suggestion.depth,
3770
- considered: selection.considered,
3771
- divergent: selection.divergent,
3772
- suppressed: selection.suppressed,
3773
- intent_terms: selection.queryTerms.size,
3774
- chars: text.length,
3775
- });
3776
- return text;
3777
- };
3778
-
3779
- /**
3780
- * THE PRE-COMMIT LAST-CALL GATE. When the band-top trigger fires, the commit defers
3781
- * exactly one gated round behind one exposure of the ruled prompt; then it proceeds
3782
- * with whatever marks exist. A request whose projection exceeds the provider input
3783
- * budget is rejected outright, so recovery must produce a window that fits: fence
3784
- * pressure, the recovery lane, or an occupancy already past the serving budget
3785
- * commit NOW, and the user
3786
- * command never reaches this gate because explicit intent is its own answer. The
3787
- * round is measured from DELIVERY: the commit proceeds only on a context pass whose
3788
- * ordinal is past the pass that rendered the exposure, which is exactly one agent
3789
- * response between prompt and rewrite.
3790
- */
3791
- const lastCallVerdict = (
3792
- snapshot: ActiveContextSnapshot,
3793
- pressure: number | null,
3794
- phase: string,
3795
- ): "expose" | "hold" | "proceed" => {
3796
- const state = persistence.state!;
3797
- const capacity = servingCapacity(snapshot.contextWindow);
3798
- const fenceLevel = typeof pressure === "number" && Number.isFinite(pressure) &&
3799
- pressure >= hardFenceRatio(snapshot);
3800
- // The output wall deliberately does NOT proceed here. It buys the crossing one inflow
3801
- // step of lead, and the gated round is what that lead is for: the agent still gets its
3802
- // one bounded turn to curate before a rewrite, which is a contract the wall has no
3803
- // business cancelling. If the round overruns and occupancy passes the budget outright,
3804
- // the condition below is what proceeds, on the pass that builds the next request.
3805
- const overBudget = capacity.usedTokens !== null && capacity.budgetTokens > 0 &&
3806
- capacity.usedTokens > capacity.budgetTokens;
3807
- if (fenceLevel || overBudget || curation.recoveryAttempts > 0 || curation.pendingRejection) {
3808
- return "proceed";
3809
- }
3810
- if (!state.lastCall) return "expose";
3811
- if (phase !== "context") return "hold";
3812
- const delivery = curation.lastCallDelivery;
3813
- if (!delivery || delivery.exposure !== state.lastCall.exposure) return "hold";
3814
- return markOrdinal(snapshot) > delivery.ordinal ? "proceed" : "hold";
3815
- };
3816
-
3817
- const exposeLastCall = (snapshot: ActiveContextSnapshot): void => {
3818
- if (!persistence.state) return;
3819
- // THE PEEK RECLAIM IS MARKED HERE, NOT ONLY AT THE COMMIT.
3820
- //
3821
- // A peek copy is reclaimed at the next commit by contract, and a contract the agent
3822
- // cannot see until after it executes is not one it can veto. The exposure is the one
3823
- // bounded round before the rewrite, so minting the reclaim marks now puts the pending
3824
- // disposal in front of the agent while a pin still changes the outcome: a pinned mark
3825
- // waits instead of applying, and lifting the pin hands the copy to a later commit.
3826
- const exposureOrdinal = markOrdinal(snapshot);
3827
- let peekReclaims = 0;
3828
- for (const mark of ephemeralPeekMarks({ snapshot, state: persistence.state, ordinal: exposureOrdinal })) {
3829
- const addition = addPendingMark(persistence.state, mark);
3830
- if (addition.added) { persistence.state = addition.state; peekReclaims += 1; }
3831
- }
3832
- const signals = measuredCurationSignals(snapshot);
3833
- const remainder = unmarkedRemainder(snapshot, persistence.state, projectionCharsPerToken());
3834
- const accounting = markAccounting(snapshot, persistence.state);
3835
- const text = lastCallText({
3836
- signals,
3837
- unmarked: { spans: remainder.spans, tokens: remainder.tokens },
3838
- pendingMarks: accounting.pending,
3839
- peekReclaims,
3840
- suggestion: deliverSurfacing(snapshot, "lastcall"),
3841
- toolName,
3842
- brandNoun,
3843
- });
3844
- const record = emit("context.lastcall", {
3845
- occupancy: signals.occupancy,
3846
- max_target: thresholds.maxTarget,
3847
- occupancy_tokens: signals.occupancyTokens,
3848
- budget_tokens: signals.budgetTokens,
3849
- unmarked_stale_spans: remainder.spans,
3850
- unmarked_stale_tokens: remainder.tokens,
3851
- pending_marks: accounting.pending,
3852
- pending_agent_marks: accounting.agentMarks,
3853
- peek_marks: peekReclaims,
3854
- chars: text.length,
3855
- });
3856
- persistence.state = {
3857
- ...persistence.state,
3858
- lastCall: {
3859
- exposure: record.seq,
3860
- ordinal: markOrdinal(snapshot),
3861
- contextCalls: curation.contextCalls,
3862
- agentMarks: accounting.agentMarks,
3863
- text,
3864
- },
3865
- };
3866
- };
3867
-
3868
2189
  const applyAutomaticRung = async (
3869
2190
  snapshot: ActiveContextSnapshot,
3870
2191
  ratio: number,
@@ -3872,18 +2193,9 @@ export function registerActiveContext(pi: any, options: {
3872
2193
  toolOnly?: boolean;
3873
2194
  waiverRatio?: number;
3874
2195
  } = {},
3875
- phase = "context",
3876
2196
  ): Promise<Record<string, unknown> | null> => {
3877
2197
  if (!persistence.state || ladder.automaticFailure || ladder.preparing) return null;
3878
- const rungSelectionOptions = {
3879
- toolOnly: rungOptions.toolOnly,
3880
- summarizerAvailable: Boolean(options.summarizeContextSpan),
3881
- failedPreparationIds: ladder.failedPreparations,
3882
- };
3883
- // The ladder decides but does not move bytes. Marks already pending are decisions
3884
- // already made: excluding the evidence they cover makes every eligible turn choose
3885
- // NEW stale content, so marks accumulate with stale growth instead of re-proposing
3886
- // one stale batch.
2198
+ const rungSelectionOptions = { toolOnly: rungOptions.toolOnly };
3887
2199
  const markLadderSelection = (): Record<string, unknown> | null => {
3888
2200
  if (!persistence.state) return null;
3889
2201
  const decision = selectAutomaticRung(snapshot, persistence.state, ratio, {
@@ -3914,246 +2226,25 @@ export function registerActiveContext(pi: any, options: {
3914
2226
  };
3915
2227
  return ladder.lastAutomaticAction;
3916
2228
  };
3917
- let epoch: Record<string, unknown> | null = null;
3918
- let inlineRungs = true;
3919
- // QUIET RUNTIME, AND THE ONE TRIGGER.
3920
- //
3921
- // A commit is an epoch transition: it rewrites the projection, every rewrite risks
3922
- // the whole prefix cache, so the cadence has to be the fewest commits that still
3923
- // keep the window inside its budget. Occupancy reaching maxTarget is the whole
3924
- // automatic condition. Below it the runtime is quiet and marks accumulate free;
3925
- // at it, one commit folds down toward minTarget, and the gap between the two lines
3926
- // is what makes the spacing of events structural rather than hoped for.
3927
- //
3928
- // Two other arms used to reach this line and both are deleted. The eligible-share
3929
- // arm fired 164 commits from ordinal 17 in rep 15 on marks that had not earned a
3930
- // rewrite, and it could fire below maxTarget, which is the quiet law it sat under.
3931
- // The stale-mass AND-condition guarded an ANNOUNCEMENT that no longer exists: a
3932
- // commit is never announced, so a commit with nothing eligible now applies nothing
3933
- // and reports it rather than being suppressed in advance.
3934
- //
3935
- // The trigger decides early and says nothing. Nothing warns that a commit is
3936
- // coming, because a warning has to arrive before the event it warns about and
3937
- // therefore has to break a prefix nothing else was breaking.
3938
- // Evaluated on EVERY pass the ladder runs on, which is where the pressure backstop
3939
- // always sat. Crossing the band top is a property of occupancy, not of which
3940
- // lifecycle hook happened to notice it, and a trigger that waits for the next
3941
- // projection pass is a window that keeps climbing while it waits.
3942
- const noticesChanged = deliverThresholdNotices(snapshot);
3943
- let lastCallChanged = false;
3944
- const commitDue = commitTriggerDue(snapshot, ratio);
3945
- if (commitDue) {
3946
- const verdict = lastCallVerdict(snapshot, rungOptions.waiverRatio ?? ratio, phase);
3947
- if (verdict === "expose") {
3948
- exposeLastCall(snapshot);
3949
- lastCallChanged = true;
3950
- } else if (verdict === "proceed") {
3951
- epoch = await runCommitEpoch(
3952
- snapshot,
3953
- "band-top",
3954
- true,
3955
- rungOptions.waiverRatio ?? ratio,
3956
- );
3957
- // Latch the eligible share this commit left behind, so the next crossing waits
3958
- // for genuinely new foldable mass rather than for the same window to still be
3959
- // full. The band top is a LINE, and a window parked on it is one event.
3960
- if (persistence.state) {
3961
- curation.reopenBaselineShare =
3962
- markAccounting(snapshot, persistence.state).eligibleFreedBudgetShare;
3963
- }
3964
- }
3965
- // "hold": the exposure is out and the round is still the agent's. Marks keep
3966
- // accumulating below; nothing commits and nothing re-exposes.
3967
- } else if (persistence.state.lastCall) {
3968
- // The crossing died without its commit (a user rescue or expiry dropped
3969
- // occupancy back under the trigger), so the exposure lapses: attributed,
3970
- // cleared, and the next crossing is a fresh event with a fresh exposure.
3971
- const capacity = servingCapacity(snapshot.contextWindow);
3972
- if (capacity.usedTokens !== null && capacity.budgetTokens > 0 &&
3973
- capacity.usedTokens / capacity.budgetTokens < thresholds.maxTarget) {
3974
- const lastCall = persistence.state.lastCall;
3975
- const attribution = lastCallAttribution(
3976
- lastCall,
3977
- markAccounting(snapshot, persistence.state).agentMarks,
3978
- );
3979
- emit("context.response", {
3980
- exposure_seq: lastCall.exposure,
3981
- commit_seq: null,
3982
- trigger: null,
3983
- outcome: "lapsed",
3984
- ...attribution,
3985
- });
3986
- clearLastCall();
3987
- lastCallChanged = true;
3988
- }
3989
- }
3990
- // An inline rung is free only INSIDE a rewrite the epoch already paid for. Below
3991
- // the threshold no commit ran, and an epoch that applied NOTHING -- every mark
3992
- // held back by an open turn or by ineligibility -- paid for no rewrite either,
3993
- // so folding inline there is a fresh single-fold rewrite of its own. Measured
3994
- // 2026-08-06 (rep 10): the current-turn guard retained all nine marks every turn
3995
- // while the inline rung folded one batch per turn anyway, 52 single-fold
3996
- // rewrites that left the prefix cache share at zero. Below a paid rewrite the
3997
- // ladder MARKS, so the decisions batch into the first commit that can apply them.
3998
- inlineRungs = Boolean(epoch) && Number(epoch?.appliedMarks ?? 0) > 0;
3999
- if (!inlineRungs) {
4000
- const marked = markLadderSelection();
4001
- if (marked) {
4002
- if (epoch) ladder.lastAutomaticAction = { ...marked, epoch };
4003
- return ladder.lastAutomaticAction;
4004
- }
4005
- // A carrier change is durable state even when no mark and no epoch moved: the
4006
- // exposure and the notices must survive a reload, so the pass returns an action
4007
- // for the transaction to persist. Never a receipt: a carrier reports itself.
4008
- if (!epoch && (lastCallChanged || noticesChanged)) {
4009
- ladder.lastAutomaticAction = { kind: "carrier", foldIds: [], sourceIds: [], sourceBytesSaved: 0 };
4010
- return ladder.lastAutomaticAction;
4011
- }
4012
- }
4013
- // Evidence a pending mark already covers is not the inline rung's to fold: a mark
4014
- // the commit RETAINED (the open turn's own reads) would otherwise be folded here
4015
- // by the very pass that just protected it.
4016
- //
4017
- // The open turn's keys are excluded DIRECTLY, not just via the marks that claim
4018
- // them. Claiming is not protection: once a commit applies every pending mark the
4019
- // claim set is empty, and the inline rung then folds the open turn's oldest read
4020
- // with nothing left to stop it. That is the rep-8 shape, and byte freshness does
4021
- // not reach it -- the first read of a long excursion sits outside the fresh tail
4022
- // while the turn that gathered it is still running. It became reachable when the
4023
- // quiet cadence started landing a commit on the same context pass, which is what
4024
- // turns the inline rung on in the first place.
4025
- const selection = inlineRungs
4026
- ? selectAutomaticRung(snapshot, persistence.state, ratio, {
4027
- ...rungSelectionOptions,
4028
- claimed: new Set([
4029
- ...claimedRefKeys(persistence.state),
4030
- ...currentTurnRefKeys(snapshot),
4031
- ]),
4032
- claimedFoldIds: markedFoldIds(persistence.state),
4033
- })
4034
- : null;
4035
- // Above the commit threshold we are already inside the epoch's rewrite turn, so
4036
- // every rung applies inline: the extra rung costs at most one more invalidation
4037
- // in a turn that has already paid one. Restricting this to prepared chapters made
4038
- // the refold and consolidation rungs unreachable in epoch mode, which drove a
4039
- // session whose reducible bytes sit in expanded folds into the hard fence.
4040
- const applicable = selection;
4041
- if (!applicable || applicable.kind === "chapter-prepare") {
4042
- if (!epoch || !persistence.state) return null;
4043
- ladder.pendingContextNote =
4044
- `A commit epoch applied ${(epoch.applied as unknown[]).length} pending mark(s) in one rewrite; ` +
4045
- "exact evidence remains expandable.";
4046
- ladder.lastAutomaticAction = { kind: "epoch-commit", foldIds: [], sourceIds: [], epoch };
4047
- noteAutomaticReceipt(snapshot, ladder.lastAutomaticAction, epoch);
4048
- return ladder.lastAutomaticAction;
4049
- }
4050
- const projectedBytesBefore = bytes(projectActiveContext(snapshot, persistence.state));
4051
- let action: Record<string, unknown> | null = null;
4052
- if (applicable.kind === "prepared-chapter" && persistence.state.prepared) {
4053
- const error = preparedFoldError({
4054
- prepared: persistence.state.prepared,
4055
- snapshot,
4056
- state: persistence.state,
4057
- generation: lifecycle.generation,
4058
- ratio,
4059
- });
4060
- if (error) {
4061
- persistence.state = clearPrepared(persistence.state);
4062
- } else {
4063
- const id = persistence.state.prepared.id;
4064
- const sourceIds = persistence.state.prepared.sourceRefs.map((ref) => ref.entryId);
4065
- persistence.state = commitPreparedFold({
4066
- prepared: persistence.state.prepared,
4067
- snapshot,
4068
- state: persistence.state,
4069
- generation: lifecycle.generation,
4070
- });
4071
- action = { kind: "chapter-fold", foldIds: [id], sourceIds };
4072
- ladder.pendingContextNote = `A coherent stale chapter was folded under ${id}; exact evidence remains expandable.`;
4073
- }
4074
- } else if (applicable.kind === "tool") {
4075
- cancelPreparation();
4076
- const tool = applicable.candidate;
4077
- const id = await commitDeterministicCandidate(snapshot, tool, automaticToolBrief(snapshot, tool));
4078
- action = {
4079
- kind: "tool-fold",
4080
- foldIds: [id],
4081
- sourceIds: tool.sourceRefs.map((ref) => ref.entryId),
4082
- };
4083
- ladder.pendingContextNote = `${tool.sourceRefs.length} stale completed read-only tool result(s) were folded.`;
4084
- } else if (applicable.kind === "refold") {
4085
- cancelPreparation();
4086
- persistence.state = setFoldProjectionState(persistence.state, applicable.foldId, "folded");
4087
- action = { kind: "refold", foldIds: [applicable.foldId] };
4088
- ladder.pendingContextNote = `Stale expanded fold ${applicable.foldId} returned to its identical placeholder.`;
4089
- } else if (applicable.kind === "consolidation") {
4090
- cancelPreparation();
4091
- const consolidation = applicable.candidate;
4092
- const id = await commitDeterministicCandidate(
4093
- snapshot,
4094
- consolidation,
4095
- deterministicConsolidationBrief(consolidation, persistence.state),
4096
- );
4097
- action = {
4098
- kind: "consolidation",
4099
- foldIds: [id],
4100
- sourceIds: consolidation.sourceRefs.map((ref) => ref.entryId),
4101
- };
4102
- ladder.pendingContextNote =
4103
- `Stale folded chapters were consolidated under ${id}; every child remains expandable.`;
4104
- } else if (applicable.kind === "chapter") {
4105
- const chapter = applicable.candidate;
4106
- // Bite-sized by construction: an oversized coherent chapter becomes sequential
4107
- // bounded folds, each with its own brief, split only at closed unit boundaries.
4108
- const spanChars = candidateSpanChars(snapshot, persistence.state, chapter);
4109
- const parts = splitCandidateBySize(snapshot, persistence.state, chapter);
4110
- const foldIds: string[] = [];
4111
- for (const part of parts) {
4112
- foldIds.push(await commitDeterministicCandidate(
4113
- snapshot,
4114
- part,
4115
- deterministicChapterCandidateBrief(snapshot, part),
4116
- ));
4117
- }
4118
- action = {
4119
- kind: "chapter-fold",
4120
- foldIds,
4121
- sourceIds: chapter.sourceRefs.map((ref) => ref.entryId),
4122
- ...(parts.length > 1 ? { splitFolds: parts.length, splitFromChars: spanChars } : {}),
4123
- };
4124
- if (parts.length > 1) {
4125
- emit("context.split", {
4126
- source: "ladder",
4127
- span_chars: spanChars,
4128
- parts: parts.length,
4129
- cap_chars: MAX_FOLD_SPAN_CHARS,
4130
- fold_ids: foldIds.join(","),
4131
- });
4132
- }
4133
- ladder.pendingContextNote = parts.length > 1
4134
- ? `A ${spanChars}-char stale chapter was folded as ${parts.length} bite-sized folds ` +
4135
- `(${foldIds.join(", ")}); exact evidence remains expandable.`
4136
- : `A coherent stale chapter was folded under ${foldIds[0]}; exact evidence remains expandable.`;
4137
- }
4138
- if ((!action && !epoch) || !persistence.state) return null;
4139
- const projectedBytesAfter = bytes(projectActiveContext(snapshot, persistence.state));
4140
- ladder.lastAutomaticAction = {
4141
- ...(action ?? { kind: "epoch-commit", foldIds: [], sourceIds: [] }),
4142
- ...(epoch ? { epoch } : {}),
4143
- sourceBytesSaved: Math.max(0, projectedBytesBefore - projectedBytesAfter),
4144
- };
4145
- noteAutomaticReceipt(snapshot, ladder.lastAutomaticAction, epoch);
4146
- return ladder.lastAutomaticAction;
2229
+ // MARKING ONLY. Every mutation the rung used to perform inline -- a prepared chapter,
2230
+ // a tool fold, a refold, a consolidation, a chapter split -- now travels as a pending
2231
+ // mark and lands at the boundary, which is the one point the projection changes.
2232
+ // WHAT the rung decides is unchanged; WHEN it takes effect is.
2233
+ return markLadderSelection();
4147
2234
  };
4148
- const runAutomaticRungTransaction = async (
2235
+ /**
2236
+ * The one durable transaction. Whatever it wraps either lands with its state persisted
2237
+ * or leaves the state it entered with, and a failure suspends folding by name rather
2238
+ * than being retried quietly. Marking and committing both go through it, which is why
2239
+ * a commit that vanishes at persistence (gate 122) and a suspension that says nothing
2240
+ * (gate 123) are single properties rather than one per caller.
2241
+ */
2242
+ const runAutomaticTransaction = async (
4149
2243
  snapshot: ActiveContextSnapshot,
4150
2244
  ratio: number,
4151
2245
  ctx: any,
4152
2246
  phase: string,
4153
- rungOptions: {
4154
- toolOnly?: boolean;
4155
- waiverRatio?: number;
4156
- } = {},
2247
+ operation: () => Promise<Record<string, unknown> | null>,
4157
2248
  ): Promise<Record<string, unknown> | null> => {
4158
2249
  if (!persistence.state || !measurements.lastProviderMeasurement ||
4159
2250
  !durableProviderMeasurementMatches(measurements.lastProviderMeasurement)) return null;
@@ -4171,7 +2262,7 @@ export function registerActiveContext(pi: any, options: {
4171
2262
  const transientAtEntry = captureTransient();
4172
2263
  let action: Record<string, unknown> | null = null;
4173
2264
  try {
4174
- action = await applyAutomaticRung(snapshot, ratio, rungOptions, phase);
2265
+ action = await operation();
4175
2266
  if (action) await persist(ctx);
4176
2267
  if (action) ladder.boundaryFailure = null;
4177
2268
  return action;
@@ -4182,17 +2273,24 @@ export function registerActiveContext(pi: any, options: {
4182
2273
  persistence.state = stateAtEntry;
4183
2274
  restoreTransient(transientAtEntry);
4184
2275
  }
4185
- suspendAutomatic(
4186
- error,
4187
- phase,
4188
- ctx,
4189
- key,
4190
- stateCommitted ? "state-committed" : recordOnly ? "record-only" : "none",
4191
- );
2276
+ const disposition = stateCommitted ? "state-committed" : recordOnly ? "record-only" : "none";
2277
+ suspendAutomatic(error, phase, ctx, key, disposition);
4192
2278
  updateStatus(ctx);
4193
2279
  return stateCommitted ? action : null;
4194
2280
  }
4195
2281
  };
2282
+ const queueAutomatic = (
2283
+ snapshot: ActiveContextSnapshot,
2284
+ ratio: number,
2285
+ ctx: any,
2286
+ phase: string,
2287
+ operation: () => Promise<Record<string, unknown> | null>,
2288
+ ): Promise<Record<string, unknown> | null> => {
2289
+ const queued = ladder.actionQueue.then(() =>
2290
+ runAutomaticTransaction(snapshot, ratio, ctx, phase, operation));
2291
+ ladder.actionQueue = queued.catch(() => undefined);
2292
+ return queued;
2293
+ };
4196
2294
  const attemptAutomaticRung = (
4197
2295
  snapshot: ActiveContextSnapshot,
4198
2296
  ratio: number,
@@ -4202,21 +2300,24 @@ export function registerActiveContext(pi: any, options: {
4202
2300
  toolOnly?: boolean;
4203
2301
  waiverRatio?: number;
4204
2302
  } = {},
4205
- ): Promise<Record<string, unknown> | null> => {
4206
- const operation = ladder.actionQueue.then(async () => {
4207
- const action = await runAutomaticRungTransaction(snapshot, ratio, ctx, phase, rungOptions);
4208
- // Where the generator is started from a pass: after the transaction, so the calls
4209
- // sit BETWEEN boundaries. Folds queued by the commit this pass just made are
4210
- // briefed now and land on the next commit, which is the whole shape of the lane.
4211
- // Afterwards each finishing call starts the next, so this is the lane's ignition
4212
- // rather than its pace. Parents waiting on their children are taken up here too:
4213
- // a pass is the other place we know the lane may have room.
4214
- resumeBriefUpgrades(snapshot, ctx);
4215
- return action;
4216
- });
4217
- ladder.actionQueue = operation.catch(() => undefined);
4218
- return operation;
4219
- };
2303
+ ): Promise<Record<string, unknown> | null> => queueAutomatic(
2304
+ snapshot, ratio, ctx, phase, () => applyAutomaticRung(snapshot, ratio, rungOptions),
2305
+ );
2306
+ /**
2307
+ * A COMMIT, THROUGH THE SAME TRANSACTION AND THE SAME QUEUE. Two callers reach it: the
2308
+ * compaction boundary, which is the ordinary one, and the projection fence, which is
2309
+ * the emergency one. The fence cannot wait for a boundary because the request it is
2310
+ * holding does not fit, so it commits in place; that is the one exception, and it is
2311
+ * the exception that already existed.
2312
+ */
2313
+ const attemptAutomaticCommit = (
2314
+ snapshot: ActiveContextSnapshot,
2315
+ ctx: any,
2316
+ trigger: string,
2317
+ waiverRatio: number | null,
2318
+ ): Promise<Record<string, unknown> | null> => queueAutomatic(
2319
+ snapshot, waiverRatio ?? 1, ctx, trigger, () => runCommitEpoch(snapshot, trigger, true, waiverRatio),
2320
+ );
4220
2321
  const projectionCandidates = (ctx: any): Array<Record<string, unknown>> => {
4221
2322
  if (lifecycle.shuttingDown || !persistence.state) return [];
4222
2323
  try {
@@ -4225,12 +2326,6 @@ export function registerActiveContext(pi: any, options: {
4225
2326
  return [];
4226
2327
  }
4227
2328
  };
4228
- // A same-session start/tree reload is a projection-generation mutation.
4229
- // Queue it behind every context authority → preparation → commit →
4230
- // projection transaction, then serialize the actual load with the action
4231
- // queue. Appending to actionQueue only after the context queue drains is
4232
- // deliberate: a running context may itself need actionQueue to commit its
4233
- // final-rung chapter, so capturing both queues up front would deadlock.
4234
2329
  const enqueueLifecycleLoad = async (ctx: any): Promise<void> => {
4235
2330
  const operation = lifecycle.contextQueue.then(() => {
4236
2331
  const loadOperation = ladder.actionQueue.then(async () => {
@@ -4256,11 +2351,6 @@ export function registerActiveContext(pi: any, options: {
4256
2351
  }
4257
2352
  };
4258
2353
 
4259
- /**
4260
- * State the resolved serving budget once, at startup, before anything reads it. A
4261
- * budget nobody can see in the stream is how rep 15 spent a whole run on a 272,000
4262
- * descriptor without a single record saying so.
4263
- */
4264
2354
  const recordResolvedCapacity = (ctx: any): void => {
4265
2355
  const capacity = currentCapacity(ctx);
4266
2356
  emit("context.capacity", {
@@ -4323,14 +2413,10 @@ export function registerActiveContext(pi: any, options: {
4323
2413
  const attributionChanged = async (_event: unknown, ctx: any): Promise<void> => {
4324
2414
  lifecycle.generation += 1;
4325
2415
  cancelPreparation();
4326
- cancelBriefUpgrades();
4327
2416
  if (persistence.state?.prepared) persistence.state = clearPrepared(persistence.state);
4328
2417
  measurements.latestRatio = null;
4329
2418
  measurements.lastProviderMeasurement = null;
4330
2419
  measurements.wallInflowSteps.length = 0;
4331
- // A different model or thinking level is a different tokenizer, so counts taken
4332
- // under the old one describe nothing here. The generation the anchor carries would
4333
- // already refuse it; dropping it releases the projection text it held as well.
4334
2420
  measurements.projectionAnchor = null;
4335
2421
  nativeCompaction.lastThresholdDecision = null;
4336
2422
  updateStatus(ctx);
@@ -4359,7 +2445,6 @@ export function registerActiveContext(pi: any, options: {
4359
2445
  const handleContext = async (event: { messages: unknown[] }, ctx: any) => {
4360
2446
  if (lifecycle.shuttingDown) return { messages: event.messages };
4361
2447
  beginMutationPass();
4362
- clearCommitLatchBelowTrigger();
4363
2448
  if (!persistence.state) persistence.state = emptyActiveContextState(ctx.sessionManager.getSessionId());
4364
2449
  lifecycle.latestSnapshot = null;
4365
2450
  lifecycle.latestSnapshotError = null;
@@ -4399,12 +2484,7 @@ export function registerActiveContext(pi: any, options: {
4399
2484
  measurements.latestRatio = contextUsageRatio(observedMeasurement);
4400
2485
  if (durableProviderMeasurementMatches(observedMeasurement) && measurements.latestRatio !== null) {
4401
2486
  measurementStateChanged = accountAnchoredMeasurement(observedMeasurement);
4402
- // Calibrate BEFORE the new measurement becomes the previous one: the inflow
4403
- // step is the difference between them.
4404
2487
  noteProjectionCalibration(observedMeasurement);
4405
- // Anchor before this pass builds anything: `previousText` is still the
4406
- // projection the provider just counted, and the projection built below is the
4407
- // one that either extends it or does not.
4408
2488
  noteProviderProjectionAnchor(observedMeasurement);
4409
2489
  measurements.lastProviderMeasurement = observedMeasurement;
4410
2490
  startPreparation(snapshot, measurements.latestRatio, ctx);
@@ -4444,27 +2524,14 @@ export function registerActiveContext(pi: any, options: {
4444
2524
  updateStatus(ctx);
4445
2525
  return { messages: event.messages };
4446
2526
  }
4447
- // A projection larger than the serving budget is never transmitted, whatever the
4448
- // last measured ratio says about the request before it.
4449
2527
  const budgeted = await enforceProjectionBudget(snapshot, projected, ctx);
4450
2528
  projected = budgeted.projected;
4451
- // Every projection this process BUILDS is a size reference for the calibration,
4452
- // including one the fence aborted. Recording only sent projections locks an
4453
- // already-large session out of calibrating at all: its first projection aborts
4454
- // under the uncalibrated constant, so nothing is ever sent, so nothing ever
4455
- // measures the ratio, so it aborts forever.
4456
2529
  const reading = projectedTokenReading(projected);
4457
2530
  measurements.lastProjectedChars = reading.chars;
4458
2531
  measurements.lastProjectedEstimate = reading.tokens;
4459
2532
  measurements.lastProjectedEstimateBasis = reading.basis;
4460
2533
  measurements.lastProjectedSizeTokens = Math.ceil(reading.chars / projectionCharsPerToken());
4461
2534
  measurements.lastProjectedEstimateCalibrated = measurements.projectionCalibrations.length > 0;
4462
- // An aborted request still returns the PROJECTION. Handing back the raw branch
4463
- // instead makes the aborted turn the largest message list the session ever
4464
- // produced -- the corpus, folds and all -- which is the exact inverse of what a
4465
- // fence is for, and it is what an abort looked like in rep12: 3,952,934 chars
4466
- // against a 1,322,385-char projection of the same session. It is not noted as a
4467
- // cache observation, because it was never sent.
4468
2535
  if (budgeted.aborted) {
4469
2536
  updateStatus(ctx);
4470
2537
  return { messages: projected };
@@ -4516,8 +2583,6 @@ export function registerActiveContext(pi: any, options: {
4516
2583
  !durableProviderMeasurementMatches(measurement) ||
4517
2584
  measuredRatio === null) return;
4518
2585
  const measurementStateChanged = accountAnchoredMeasurement(measurement);
4519
- // The provider accepted a request: whatever the recovery lane spent belongs to an
4520
- // inflow that is now behind us, and the cap resets for the next one.
4521
2586
  curation.recoveryAttempts = 0;
4522
2587
  curation.pendingRejection = null;
4523
2588
  noteWallInflow(measurement);
@@ -4559,7 +2624,6 @@ export function registerActiveContext(pi: any, options: {
4559
2624
  preservedShare: instrumentation.lastPreservedShare,
4560
2625
  });
4561
2626
  if (observation) {
4562
- // The join key: this is where the stream meets provider-side telemetry.
4563
2627
  emit("context.usage", {
4564
2628
  provider: ownValue(message, "provider") ?? null,
4565
2629
  model: ownValue(message, "model") ?? null,
@@ -4593,18 +2657,9 @@ export function registerActiveContext(pi: any, options: {
4593
2657
  );
4594
2658
  } catch (error) {
4595
2659
  suspendAutomatic(error, "message-end", ctx);
4596
- try { updateStatus(ctx); } catch { /* The provider loop must keep running. */ }
2660
+ try { updateStatus(ctx); } catch { }
4597
2661
  }
4598
2662
  });
4599
- /*
4600
- * There was an `after_provider_response` handler here that treated `status >= 400` as
4601
- * the rejection signal. It could never fire on the case it was written for. Every
4602
- * provider adapter calls `onResponse` exactly once and only AFTER the request promise
4603
- * resolves, so a 4xx rejects the promise and control never reaches that call at all
4604
- * (verified across all seven adapters in pi-ai 0.83.0). `pendingRejection` was
4605
- * therefore never set in production and the recovery branch of the projection budget
4606
- * never ran. It is set by the rollback lane now, from an event that does fire.
4607
- */
4608
2663
  pi.on("turn_end", async (_event: unknown, ctx: any) => {
4609
2664
  beginMutationPass();
4610
2665
  if (lifecycle.shuttingDown || !persistence.state || !persistence.persisted) return;
@@ -4628,7 +2683,7 @@ export function registerActiveContext(pi: any, options: {
4628
2683
  }
4629
2684
  suspendAutomatic(error, "turn-end", ctx);
4630
2685
  }
4631
- try { updateStatus(ctx); } catch { /* turn_end must never stall Pi. */ }
2686
+ try { updateStatus(ctx); } catch { }
4632
2687
  });
4633
2688
  pi.on("session_before_tree", (event: Record<string, unknown>) => {
4634
2689
  const preparation = ownValue(event, "preparation");
@@ -4636,15 +2691,6 @@ export function registerActiveContext(pi: any, options: {
4636
2691
  return ownValue(preparation, "userWantsSummary") === true ? { cancel: true } : undefined;
4637
2692
  });
4638
2693
 
4639
- /**
4640
- * pi's own overflow classifier, borrowed rather than re-implemented.
4641
- *
4642
- * `isContextOverflow` owns the provider-message patterns AND the silent cases (usage
4643
- * past the window with a clean stop, the truncating `length` stop). Re-stating that
4644
- * pattern set here would drift on the first provider that reworded its 400. The
4645
- * bare specifier is tried first, for a deployment where pi-ai is hoisted; the second
4646
- * form reaches pi's own nested copy, which is where a default install puts it.
4647
- */
4648
2694
  const resolveOverflowClassifier = async (): Promise<void> => {
4649
2695
  if (rollback.classifier || rollback.classifierSource === "unresolved") return;
4650
2696
  const host = "@earendil-works/pi-coding-agent";
@@ -4656,7 +2702,7 @@ export function registerActiveContext(pi: any, options: {
4656
2702
  if (at >= 0) {
4657
2703
  specifiers.push(`${entry.slice(0, at + marker.length)}node_modules/@earendil-works/pi-ai/dist/compat.js`);
4658
2704
  }
4659
- } catch { /* An unresolvable host is the same answer as an unresolvable classifier. */ }
2705
+ } catch { }
4660
2706
  for (const specifier of specifiers) {
4661
2707
  try {
4662
2708
  const module = await import(specifier) as Record<string, unknown>;
@@ -4665,7 +2711,7 @@ export function registerActiveContext(pi: any, options: {
4665
2711
  rollback.classifierSource = specifier;
4666
2712
  return;
4667
2713
  }
4668
- } catch { /* Try the next form; the last failure is the answer. */ }
2714
+ } catch { }
4669
2715
  }
4670
2716
  rollback.classifierSource = "unresolved";
4671
2717
  };
@@ -4685,10 +2731,6 @@ export function registerActiveContext(pi: any, options: {
4685
2731
  }
4686
2732
  };
4687
2733
 
4688
- /**
4689
- * The disarmed answer, and the only one: say so on the record and leave the session
4690
- * behaving exactly as it did before the lane existed.
4691
- */
4692
2734
  const refuseRollback = (reason: string, trigger: string, ctx: any): void => {
4693
2735
  emit("context.rollback", {
4694
2736
  trigger,
@@ -4714,22 +2756,6 @@ export function registerActiveContext(pi: any, options: {
4714
2756
  );
4715
2757
  };
4716
2758
 
4717
- /**
4718
- * The fallback trigger, and the honest limit of it.
4719
- *
4720
- * `session_before_compact` never fires for a deployment that turned auto-compaction
4721
- * off, so the primary trigger is deaf there. This is the second detector: pi's own
4722
- * classifier over the assistant message at `message_end`, which is where the error
4723
- * message first becomes visible. It records the episode and, if no compaction event
4724
- * claims it, reports it.
4725
- *
4726
- * It does NOT roll back, and the reason is mechanical rather than cautious. The
4727
- * pre-strip this lane depends on happens INSIDE `_checkCompaction`, which is exactly
4728
- * the code an auto-compaction-disabled deployment never reaches, so on this path
4729
- * agent state still carries the oversized window plus the error message. A bare
4730
- * `branch()` there would leave the tree and agent state disagreeing, which is the
4731
- * failure mode the whole design exists to avoid. Held, and reported as held.
4732
- */
4733
2759
  const noteOverflowAtMessageEnd = (message: unknown, ctx: any): void => {
4734
2760
  if (!rollback.classifier || !message || typeof message !== "object") return;
4735
2761
  const window = budgetWindowFor(ctx) ?? DEFAULT_CONTEXT_WINDOW;
@@ -4740,10 +2766,6 @@ export function registerActiveContext(pi: any, options: {
4740
2766
  rollback.pendingOverflow = { at: currentOrdinal(), entryId: null };
4741
2767
  };
4742
2768
 
4743
- /**
4744
- * An overflow that no compaction event claimed: the auto-compaction-disabled shape.
4745
- * Loud, terminal, and never silent.
4746
- */
4747
2769
  const reportUnclaimedOverflow = (ctx: any): void => {
4748
2770
  if (!rollback.pendingOverflow) return;
4749
2771
  rollback.pendingOverflow = null;
@@ -4756,20 +2778,6 @@ export function registerActiveContext(pi: any, options: {
4756
2778
  );
4757
2779
  };
4758
2780
 
4759
- /**
4760
- * ROLLBACK, COMMIT, REPLAY.
4761
- *
4762
- * pi has already stripped the trailing error message from agent state by the time
4763
- * this fires, so agent state IS the rolled-back window and all that remains is to
4764
- * move the session leaf to match. The label goes on FIRST, because a label appends at
4765
- * the current leaf and advances it, so applied after the branch it would mark the
4766
- * surviving path instead of the abandoned one.
4767
- *
4768
- * The commit deliberately does NOT happen here. The retried request runs its own
4769
- * `context` pass, and that pass folds and commits before the payload is built. A
4770
- * commit here would adjudicate a snapshot taken outside a projection pass and then be
4771
- * evaluated again by the retry, which is two mutations for one episode.
4772
- */
4773
2781
  const rebuiltMessageCount = (manager: Record<string, any>): number | null => {
4774
2782
  try {
4775
2783
  const rebuilt = manager.buildSessionContext?.();
@@ -4794,9 +2802,6 @@ export function registerActiveContext(pi: any, options: {
4794
2802
  return;
4795
2803
  }
4796
2804
  const branchEntries = ownValue(event, "branchEntries");
4797
- // Copied, not aliased. `getBranch()` hands back the live array and the branch call
4798
- // below truncates it in place, so a handler holding the original reference watches
4799
- // the entries it is still reasoning about disappear underneath it.
4800
2805
  const entries = Array.isArray(branchEntries) ? [...branchEntries] : [];
4801
2806
  const errorEntry = findOverflowErrorEntry(entries);
4802
2807
  if (!errorEntry) {
@@ -4808,7 +2813,6 @@ export function registerActiveContext(pi: any, options: {
4808
2813
  const sessionMessagesBefore = rebuiltMessageCount(manager);
4809
2814
  const abandoned = entries.slice(errorEntry.index);
4810
2815
  const rolledBackBytes = bytes(abandoned.flatMap((entry: any) => sessionEntryMessages(entry) ?? []));
4811
- // Lineage first. The abandoned path stays in the tree, and it says why it was left.
4812
2816
  try {
4813
2817
  manager.appendLabelChange(errorEntry.id, `${entryTypePrefix} overflow rollback`);
4814
2818
  } catch (error) {
@@ -4822,8 +2826,6 @@ export function registerActiveContext(pi: any, options: {
4822
2826
  refuseRollback(`the branch failed (${String(error)})`, "session_before_compact", ctx);
4823
2827
  return;
4824
2828
  }
4825
- // The invariant, measured rather than assumed: the rolled-back window has to be
4826
- // exactly the failed entry shorter, or the retry sends something nobody built.
4827
2829
  const errorEntryMessages = (sessionEntryMessages(entries[errorEntry.index]) ?? []).length;
4828
2830
  const sessionMessagesAfter = rebuiltMessageCount(manager);
4829
2831
  const holds = sessionMessagesBefore === null || sessionMessagesAfter === null ||
@@ -4846,8 +2848,6 @@ export function registerActiveContext(pi: any, options: {
4846
2848
  replayed: replaySkipReason === null,
4847
2849
  replaySkipReason,
4848
2850
  });
4849
- // Exactly ONE steered message. Steering drains one at a time at the top of the
4850
- // retried loop, so a second would be silently held to a turn that never comes.
4851
2851
  let replayed = false;
4852
2852
  if (replaySkipReason === null) {
4853
2853
  if (typeof pi.sendMessage !== "function") {
@@ -4892,18 +2892,12 @@ export function registerActiveContext(pi: any, options: {
4892
2892
  noticeChars: notice.length,
4893
2893
  attemptOrdinal: rollback.attempts,
4894
2894
  };
4895
- // The tree moved, so the mapping is rebuilt from it. THEN the fold is armed for the
4896
- // retried pass, in that order: a reload clears the recovery flags, and arming before
4897
- // it would hand the retry a cleared one. The guards are waived in that pass because
4898
- // a request that already did not fit has nothing left to economize.
4899
2895
  load(ctx, true);
4900
2896
  curation.pendingRejection = { status: 400, ordinal: currentOrdinal() };
4901
2897
  };
4902
2898
 
4903
- pi.on("session_before_compact", (event: Record<string, unknown>, ctx: any) => {
2899
+ pi.on("session_before_compact", async (event: Record<string, unknown>, ctx: any) => {
4904
2900
  const reason = ownValue(event, "reason");
4905
- // The overflow reason is a provider rejection pi is prepared to retry, and it is
4906
- // the rollback lane's trigger. Threshold and manual compaction are unchanged.
4907
2901
  if (reason === "overflow" && ownValue(event, "willRetry") === true) {
4908
2902
  nativeCompaction.lastThresholdDecision = {
4909
2903
  handled: true,
@@ -4914,7 +2908,7 @@ export function registerActiveContext(pi: any, options: {
4914
2908
  };
4915
2909
  try { recoverFromOverflow(event, ctx); }
4916
2910
  catch (error) { suspendAutomatic(error, "overflow-rollback", ctx); }
4917
- try { updateStatus(ctx); } catch { /* Recovery must survive presentation failure. */ }
2911
+ try { updateStatus(ctx); } catch { }
4918
2912
  return { cancel: true };
4919
2913
  }
4920
2914
  if (reason === "manual") {
@@ -4924,16 +2918,34 @@ export function registerActiveContext(pi: any, options: {
4924
2918
  reason: "manual native compaction explicitly requested by the user",
4925
2919
  compactionReason: reason,
4926
2920
  };
4927
- try { updateStatus(ctx); } catch { /* Manual rescue must survive presentation failure. */ }
2921
+ try { updateStatus(ctx); } catch { }
4928
2922
  return undefined;
4929
2923
  }
2924
+ let handoff: Record<string, unknown> | null = null;
2925
+ try {
2926
+ const snapshot = authoritativeSnapshotFor(ctx);
2927
+ handoff = await attemptAutomaticCommit(
2928
+ snapshot, ctx, "compaction-boundary", measurements.latestRatio,
2929
+ );
2930
+ } catch (error) {
2931
+ suspendAutomatic(error, "compaction-boundary", ctx);
2932
+ return undefined;
2933
+ }
2934
+ // CANCELLED WHETHER OR NOT ANYTHING WAS HANDED OFF. Letting Pi compact when the
2935
+ // boundary found nothing eligible is a silent fallback to a lossy summary, and
2936
+ // losslessness is the whole claim: a crossing that reclaims nothing is a STARVED
2937
+ // session, and the fence, the abort and the rollback lane already own that case and
2938
+ // say so out loud. The decision record still names which of the two happened.
4930
2939
  nativeCompaction.lastThresholdDecision = {
4931
2940
  handled: true,
4932
2941
  retry: false,
4933
- reason: `blocked stock automatic compaction; ${contextBrand(brandNoun)} folding remains authoritative`,
2942
+ reason: handoff
2943
+ ? `${contextBrand(brandNoun)} handed the prefix off losslessly instead of compacting it`
2944
+ : `${contextBrand(brandNoun)} blocked stock automatic compaction with nothing eligible to hand off`,
4934
2945
  compactionReason: reason,
4935
2946
  nativeCompactionCompleted: false,
4936
2947
  };
2948
+ try { updateStatus(ctx); } catch { }
4937
2949
  return { cancel: true };
4938
2950
  });
4939
2951
  pi.on("agent_settled", async (_event: unknown, ctx: any) => {
@@ -4947,20 +2959,12 @@ export function registerActiveContext(pi: any, options: {
4947
2959
  const snapshot = authoritativeSnapshotFor(ctx);
4948
2960
  startPreparation(snapshot, measurements.latestRatio, ctx);
4949
2961
  } catch {
4950
- // The next authoritative context event will retry mapping.
4951
2962
  }
4952
2963
  try { await recoverNativeReceipts(ctx); }
4953
2964
  catch (error) { safeNotify(ctx, `Native compaction receipt recovery remains pending: ${String(error)}`, "error"); }
4954
2965
  updateStatus(ctx);
4955
2966
  });
4956
2967
 
4957
- /**
4958
- * Admission control. A refusal that names no next action is denial, not governance,
4959
- * so every refusal carries at least one CONSTRUCTIBLE alternative: a bounded slice
4960
- * sized to the headroom we actually have, a child fold that is smaller by
4961
- * construction, and the commit that frees the room. The exact stored size of the
4962
- * target is known, so this is arithmetic, not a guess.
4963
- */
4964
2968
  const admit = (input: {
4965
2969
  action: "peek" | "expand";
4966
2970
  ctx: any;
@@ -4987,8 +2991,6 @@ export function registerActiveContext(pi: any, options: {
4987
2991
  alternatives.push({ action: "peek", id: child });
4988
2992
  }
4989
2993
  if (!alternatives.length) {
4990
- // The floor: folding is always available, and it is the action that creates
4991
- // the room this read needs.
4992
2994
  alternatives.push({ action: "status", detail: "fold_candidates" });
4993
2995
  }
4994
2996
  throw new Error(
@@ -5028,8 +3030,6 @@ export function registerActiveContext(pi: any, options: {
5028
3030
  }
5029
3031
  const statusOffset = boundedInteger(params.offset, 0, 0, 1_000_000, "offset");
5030
3032
  const statusLimit = boundedInteger(params.limit, 40, 1, 100, "limit");
5031
- // Paging is explicit and agent-driven: the full tree is reachable, it just
5032
- // stops riding along on every request that wanted a count.
5033
3033
  const paged = detail === "folds" || detail === "objects";
5034
3034
  const accounting = markAccounting(snapshot, persistence.state);
5035
3035
  return toolPayload(boundStatusPayload({
@@ -5051,23 +3051,14 @@ export function registerActiveContext(pi: any, options: {
5051
3051
  available: true,
5052
3052
  automatic: {
5053
3053
  pressureRatio: measurements.latestRatio,
5054
- // Status is a READ of the slate, never a delivery of one. `status` is a
5055
- // read-only context action and the tool-batch safety scan is built on
5056
- // read-only actions not writing durable state, so asking must not issue a
5057
- // suggestion, spend the precision budget, or move a suppression counter. An
5058
- // agent that asks gets the answer; only the push carriers are metered.
5059
- surfacing: statusSurfacing(snapshot),
5060
3054
  refoldRatio: snapshot.policy.refoldRatio,
5061
3055
  chapterPrepareRatio: snapshot.policy.prepareRatio,
5062
3056
  hardFenceRatio: hardFenceRatio(snapshot),
5063
- // The declared policy, reported. No action reads it back as a setting.
5064
3057
  thresholds: { ...snapshot.thresholds },
5065
3058
  zones: {
5066
3059
  freshBoundary: snapshot.freshBoundary,
5067
3060
  budgetTokens: snapshot.budgetTokens,
5068
3061
  },
5069
- // What THIS runtime withheld, which is nothing once the deployment declared an
5070
- // already-net budget. One number, from the same accounting the fence divides by.
5071
3062
  responseReserve: currentCapacity(ctx).outputReservation,
5072
3063
  windowSource: snapshot.windowSource,
5073
3064
  capacity: {
@@ -5096,13 +3087,11 @@ export function registerActiveContext(pi: any, options: {
5096
3087
  overBudgetReduction: ladder.overBudgetReduction ? clone(ladder.overBudgetReduction) : null,
5097
3088
  curation: {
5098
3089
  occupancyThreshold: thresholds.maxTarget,
5099
- signals: curation.lastSignals ? { ...curation.lastSignals } : null,
5100
3090
  contextCalls: curation.contextCalls,
5101
3091
  receipts: curation.receipts.map((receipt) => ({ ...receipt })),
5102
3092
  },
5103
3093
  recovery: {
5104
3094
  attempts: curation.recoveryAttempts,
5105
- maxAttempts: OVERFLOW_RECOVERY_MAX_ATTEMPTS,
5106
3095
  pendingRejection: curation.pendingRejection ? { ...curation.pendingRejection } : null,
5107
3096
  last: curation.lastRecovery ? clone(curation.lastRecovery) : null,
5108
3097
  rollback: {
@@ -5118,9 +3107,6 @@ export function registerActiveContext(pi: any, options: {
5118
3107
  projectionCharsPerToken: projectionCharsPerToken(),
5119
3108
  projectionEstimatorErrorShare: estimatorErrorShare(),
5120
3109
  projectionExpectedInflowTokens: expectedInflowTokens(),
5121
- // What the fence actually weighed, not a second arithmetic over the same bytes:
5122
- // once occupancy is anchored, re-deriving it here from chars alone would report
5123
- // a number no decision was made on.
5124
3110
  projectionMarginTokens: measurements.lastProjectedEstimate === null
5125
3111
  ? null
5126
3112
  : projectionMarginTokens(measurements.lastProjectedEstimate, currentCapacity(ctx).window),
@@ -5141,7 +3127,6 @@ export function registerActiveContext(pi: any, options: {
5141
3127
  ...ledgerSummary(instrumentation.ledger),
5142
3128
  projectionRecords: clone(instrumentation.ledger.records),
5143
3129
  cacheObservations: clone(instrumentation.ledger.observations),
5144
- // THE stream, as the durable entries carry it. One shape, one convention.
5145
3130
  events: clone(instrumentation.ledger.events),
5146
3131
  },
5147
3132
  peek: {
@@ -5154,32 +3139,20 @@ export function registerActiveContext(pi: any, options: {
5154
3139
  },
5155
3140
  ...(detail === "fold_candidates" ? {
5156
3141
  candidates: foldCandidatesDetail(snapshot, persistence.state, measurements.latestRatio, {
5157
- summarizerAvailable: Boolean(options.summarizeContextSpan),
5158
3142
  generation: lifecycle.generation,
5159
3143
  measurementFresh: Boolean(measurements.lastProviderMeasurement &&
5160
3144
  durableProviderMeasurementMatches(measurements.lastProviderMeasurement)),
5161
3145
  automaticFailure: ladder.automaticFailure !== null,
5162
3146
  preparing: Boolean(ladder.preparing),
5163
- failedPreparationIds: ladder.failedPreparations,
5164
3147
  }),
5165
3148
  } : {}),
5166
3149
  ...(detail === "tree" ? { tree: foldTreeDetail(snapshot, persistence.state).slice(statusOffset) } : {}),
5167
3150
  }, typeof detail === "string" ? detail : null, statusOffset));
5168
3151
  }
5169
- // Peeking or expanding a surfaced fold is the ACTED label, joined to the offer that
5170
- // named it. It stays ephemeral: the ledger rides the next persisted state, never an
5171
- // entry of its own, and the used/ignored grades land when the window closes.
5172
- const noteSurfacingAccept = (id: string): void => {
5173
- if (!persistence.state) return;
5174
- persistence.state = noteSurfacingAction(persistence.state, id, markOrdinal(snapshot));
5175
- };
5176
3152
  if (action === "peek") {
5177
3153
  const id = String(params.id ?? "").trim();
5178
3154
  if (!id) throw new Error("peek requires id");
5179
3155
  const offset = boundedInteger(params.offset, 0, 0, 1_000_000_000, "offset");
5180
- // The DEFAULT is the bounded index view. Widening is an explicit argument, so
5181
- // the default path cannot overfill a window: measured 2026-08-06, 14 raw peek
5182
- // results held 1.9M characters, 82 percent of everything still unfolded.
5183
3156
  const sliceBytes = boundedInteger(
5184
3157
  params.bytes,
5185
3158
  PEEK_DEFAULT_MAX_BYTES,
@@ -5205,7 +3178,6 @@ export function registerActiveContext(pi: any, options: {
5205
3178
  offset,
5206
3179
  toolName,
5207
3180
  }));
5208
- noteSurfacingAccept(id);
5209
3181
  return payload;
5210
3182
  }
5211
3183
  if (action === "rebrief") {
@@ -5228,15 +3200,11 @@ export function registerActiveContext(pi: any, options: {
5228
3200
  brief,
5229
3201
  previousBrief: previous,
5230
3202
  durableRevision: persistence.state.revision,
5231
- activation: "the fold's placeholder, index rows and suggestions now carry your brief; " +
3203
+ activation: "the fold's placeholder and index rows now carry your brief; " +
5232
3204
  "the exact source and its fold record are untouched.",
5233
3205
  });
5234
3206
  }
5235
3207
  if (action === "reboundary") {
5236
- // One verb, both directions. `ids` names the span you want to BE one fold: every
5237
- // fold overlapping it dissolves and the span is re-cut as one, which merges N
5238
- // adjacent folds when the span covers them and splits one fold when the span sits
5239
- // inside it. `id` alone is the plain dissolve, which returns a span to raw.
5240
3208
  if (params.ids !== undefined) {
5241
3209
  const requestedIds = stringIds(params.ids);
5242
3210
  const snapped = snapToFoldBoundaries(snapshot, persistence.state, requestedIds);
@@ -5263,10 +3231,6 @@ export function registerActiveContext(pi: any, options: {
5263
3231
  const created: Array<Record<string, unknown>> = [];
5264
3232
  const correctedBriefs: Record<string, string> = {};
5265
3233
  for (const part of splitCandidateBySize(snapshot, persistence.state, recut)) {
5266
- // A re-cut that lands back on a span this session already folded meets its own
5267
- // immutable record. The record wins -- rewriting it would report a conflicting
5268
- // durable fold and suspend automatic management -- and the supplied brief
5269
- // becomes a correction beside it, which is what `rebrief` writes anyway.
5270
3234
  const durable = persistence.persistedFoldRecords.get(foldIdFor(part.kind, part.parts));
5271
3235
  const { preparedFold, nextState } = await prepareAndCommitExplicit({
5272
3236
  snapshot, candidate: part, brief: durable ? durable.fold.brief : supplied, ctx, signal,
@@ -5341,8 +3305,6 @@ export function registerActiveContext(pi: any, options: {
5341
3305
  if (action === "expand" || action === "refold") {
5342
3306
  const id = String(params.id ?? "").trim();
5343
3307
  if (!id) throw new Error(`${action} requires id`);
5344
- // An expand with marks pending opens the commit epoch: the restore and the
5345
- // batch of folds then cost one rewrite between them instead of two.
5346
3308
  let epochApplied: unknown[] = [];
5347
3309
  if (action === "expand" && pendingMarks(persistence.state).length) {
5348
3310
  const result = await commitPendingMarks({
@@ -5363,7 +3325,6 @@ export function registerActiveContext(pi: any, options: {
5363
3325
  requestedBytes: Math.max(0, expanding.sourceChars - expanding.placeholderChars),
5364
3326
  children: childFoldIds(expanding),
5365
3327
  });
5366
- noteSurfacingAccept(id);
5367
3328
  }
5368
3329
  let next = setFoldProjectionState(persistence.state, id, action === "expand" ? "expanded" : "folded");
5369
3330
  if (action === "expand") next = withExpandLease(next, id);
@@ -5392,9 +3353,6 @@ export function registerActiveContext(pi: any, options: {
5392
3353
  const refsBefore = persistence.state.protected.length;
5393
3354
  const nextProtection = protectEvidence(snapshot, persistence.state, ids, action === "protect");
5394
3355
  if (action === "protect") {
5395
- // The pin ceiling: protect is a promise to hold bytes raw through every fold,
5396
- // and a promise with no mass bound can pin the window solid. The refusal is
5397
- // corrective, not denial: it names the cap and the release valve.
5398
3356
  const capacity = servingCapacity(snapshot.contextWindow);
5399
3357
  const prospectiveShare = capacity.budgetTokens > 0
5400
3358
  ? estimatedTokens(explicitProtectedMass(snapshot, nextProtection).bytes) / capacity.budgetTokens
@@ -5448,9 +3406,6 @@ export function registerActiveContext(pi: any, options: {
5448
3406
  });
5449
3407
  }
5450
3408
  if (action === "fold") {
5451
- // One call, several {span, brief} pairs. Marking is free and committing is not,
5452
- // so the shape that should be cheapest to express is the BATCH: an agent that
5453
- // must spend one call per span curates less than one that spends one call.
5454
3409
  const requested = batchedMarkRequests(params);
5455
3410
  const resolved: Array<{
5456
3411
  candidate: FoldCandidate;
@@ -5493,33 +3448,28 @@ export function registerActiveContext(pi: any, options: {
5493
3448
  }
5494
3449
  }
5495
3450
  const corrections = resolved.flatMap((item) => item.corrections);
5496
- // Resolve every brief now, while the source is in hand, so the commit epoch
5497
- // itself stays deterministic and free of provider calls. A span that is not
5498
- // eligible YET cannot go through preparation at all, so it takes the
5499
- // deterministic brief: the mark is a decision, and refusing to record it
5500
- // because the span is momentarily fresh is exactly the drop being fixed.
5501
3451
  const marks: Array<Record<string, unknown>> = [];
5502
3452
  let staged = persistence.state;
5503
3453
  for (const item of resolved) {
5504
3454
  const { candidate } = item;
5505
- // ACCEPT AND HOLD. A span that is still fresh or protected is not a refusal:
5506
- // the mark is a standing decision, it is recorded now, and it folds at the
5507
- // first commit after the span ages out. Refusal is reserved for a mark that
5508
- // cannot be constructed at all.
5509
- // A REPEATED DECISION IS INERT. The fold id is derived from the span, so a
5510
- // span the ladder already prepared carries that exact id in the forest
5511
- // already, and preparing it a second time throws "Prepared fold already
5512
- // exists" out of the tool call. Under the old cadence commits were frequent
5513
- // enough to drain prepared folds before a second decision could land on one;
5514
- // the quiet runtime commits far less often, so the collision became reachable
5515
- // in ordinary use -- the ladder marks a span, the agent then folds the same
5516
- // span, and the agent's call fails. Marking is a standing decision about a
5517
- // span, and deciding the same thing twice has to be a no-op.
5518
3455
  const alreadyPrepared = staged.folds.some((fold) =>
5519
3456
  fold.id === foldIdFor(candidate.kind, candidate.parts));
5520
3457
  const deferred = refsProtected(candidate.sourceRefs, staged, snapshot) ||
5521
3458
  (candidate.kind === "tool-result" &&
5522
3459
  toolRefsProtected(candidate.sourceRefs, staged, snapshot));
3460
+ const suppliedComplaint = item.brief === undefined
3461
+ ? null
3462
+ : briefContractComplaint(item.brief.trim(), snapshot.policy.maxBriefChars, snapshot.toolName);
3463
+ if (suppliedComplaint !== null) {
3464
+ marks.push({
3465
+ id: foldIdFor(candidate.kind, candidate.parts),
3466
+ kind: candidate.kind,
3467
+ ok: false,
3468
+ deferred: false,
3469
+ reason: `Supplied brief rejected. ${suppliedComplaint}`,
3470
+ });
3471
+ continue;
3472
+ }
5523
3473
  const briefed = !deferred && !alreadyPrepared
5524
3474
  ? await prepareFold({
5525
3475
  candidate,
@@ -5527,7 +3477,6 @@ export function registerActiveContext(pi: any, options: {
5527
3477
  state: staged,
5528
3478
  generation: lifecycle.generation,
5529
3479
  brief: item.brief,
5530
- summarize: observedSummarize,
5531
3480
  ctx,
5532
3481
  signal,
5533
3482
  })
@@ -5564,18 +3513,12 @@ export function registerActiveContext(pi: any, options: {
5564
3513
  await persistManual(staged, action, ctx);
5565
3514
  updateStatus(ctx);
5566
3515
  const accounting = markAccounting(snapshot, persistence.state);
5567
- // MECHANISM 3. The projection is byte-frozen between fold events, so this reply
5568
- // is the only cache-free channel left: it carries the whole picture, not just
5569
- // an acknowledgement of the spans this call named.
5570
3516
  const held = pendingMarks(persistence.state).map((mark) => ({
5571
3517
  id: mark.id,
5572
3518
  kind: mark.kind,
5573
3519
  tokens: estimatedTokens(markFreedBytes(snapshot, persistence.state!, mark)),
5574
3520
  }));
5575
3521
  const remainder = unmarkedRemainder(snapshot, persistence.state, projectionCharsPerToken());
5576
- // The single-span shape is the head of the batched one: one call carrying one
5577
- // span answers exactly as it always did, and a batch adds fields rather than
5578
- // replacing them.
5579
3522
  const only = marks.length === 1 && marks[0].ok === true ? marks[0] : null;
5580
3523
  return toolPayload({
5581
3524
  version: 1,
@@ -5594,7 +3537,6 @@ export function registerActiveContext(pi: any, options: {
5594
3537
  }
5595
3538
  : {}),
5596
3539
  marks,
5597
- // Never silently reinterpreted: a span the runtime moved says so, here.
5598
3540
  corrections,
5599
3541
  argumentsSha256: executionArgumentsSha256,
5600
3542
  durableRevision: persistence.state.revision,
@@ -5610,9 +3552,6 @@ export function registerActiveContext(pi: any, options: {
5610
3552
  unmarkedTokens: remainder.tokens,
5611
3553
  unmarkedShare: remainder.share,
5612
3554
  unmarkedCandidates: remainder.candidates,
5613
- // The acknowledgement rides the tool result, so it PERSISTS in context the way
5614
- // every tool result does. Default on;
5615
- // `guidance.actionResponses: false` returns the accounting without the prose.
5616
3555
  ...(guidance.actionResponses ? {
5617
3556
  awareness: markAwarenessText({ held, remainder, toolName, brandNoun }),
5618
3557
  activation: "accepted as pending marks; no context bytes moved, and nothing else in your " +
@@ -5626,14 +3565,6 @@ export function registerActiveContext(pi: any, options: {
5626
3565
  }
5627
3566
  throw new Error(`Unknown ${toolName} action '${action}'`);
5628
3567
  };
5629
- /**
5630
- * Every context-management call, accepted AND refused, in the durable stream.
5631
- *
5632
- * A rejected call is the more informative of the two: an agent whose spans keep being
5633
- * refused looks identical, from fold records alone, to an agent that never tried to
5634
- * curate at all. The exact validation text is recorded verbatim, because "it failed"
5635
- * is not a finding and "ids must contain 1-64 values" is.
5636
- */
5637
3568
  const requestedMarkCount = (params: Record<string, unknown>): number => {
5638
3569
  const batched = denseOwnArrayValues(params?.marks);
5639
3570
  if (batched) return batched.length;
@@ -5649,23 +3580,17 @@ export function registerActiveContext(pi: any, options: {
5649
3580
  ): Promise<unknown> => {
5650
3581
  const operation = ladder.actionQueue.then(async () => {
5651
3582
  const action = String(params?.action ?? "");
5652
- // The gate's engagement signal, counted BEFORE the call can fail: an agent that
5653
- // reached for a context verb engaged, whether or not the span was valid.
5654
3583
  curation.contextCalls += 1;
5655
3584
  const attempt = (ok: boolean, error: string | null, corrections: Array<Record<string, unknown>>) => {
5656
3585
  const record = emit("context.attempt", {
5657
3586
  action,
5658
3587
  ok,
5659
3588
  error,
5660
- // The join key against the worker's own tool-call log: one logical row per
5661
- // model-emitted invocation, matched by id and never by order or clock.
5662
3589
  tool_call_id: toolCallId,
5663
3590
  marks_requested: requestedMarkCount(params),
5664
3591
  corrections_applied: corrections.length,
5665
3592
  arguments_sha256: sha256Value(params ?? {}),
5666
3593
  });
5667
- // One record per correction, referencing its attempt: nothing nests, and a
5668
- // reader counting corrections never has to unpack an array to do it.
5669
3594
  for (const correction of corrections) {
5670
3595
  const from = denseOwnArrayValues(ownValue(correction, "from")) ?? [];
5671
3596
  const to = denseOwnArrayValues(ownValue(correction, "to")) ?? [];
@@ -5717,15 +3642,6 @@ export function registerActiveContext(pi: any, options: {
5717
3642
  if (!lifecycle.latestSnapshot) lifecycle.latestSnapshot = snapshot;
5718
3643
  const divider = args.indexOf(" -- ");
5719
3644
  const selector = (divider >= 0 ? args.slice(0, divider) : args).trim();
5720
- // THE USER COMMIT. One word, and the only commit verb any caller has: the model
5721
- // tool still has no commit action, because a verb the runtime is entitled to
5722
- // overrule is surface without function. A user is not overruled.
5723
- //
5724
- // Below maxTarget it applies the eligible marks in hand and stops -- no automatic
5725
- // top-up, because the user asked to bank the curation they made, not to have the
5726
- // runtime pick more. At or above maxTarget it is the ordinary event: the planner
5727
- // may top up toward minTarget. Neither path touches freshness, pins, exactness or
5728
- // the provider fence.
5729
3645
  if (selector === "commit") {
5730
3646
  const capacity = servingCapacity(snapshot.contextWindow);
5731
3647
  const occupancy = capacity.usedTokens !== null && capacity.budgetTokens > 0
@@ -5733,7 +3649,16 @@ export function registerActiveContext(pi: any, options: {
5733
3649
  : null;
5734
3650
  const topUp = occupancy !== null && occupancy >= thresholds.maxTarget;
5735
3651
  const committed = await runCommitEpoch(snapshot, "user-command", topUp, measurements.latestRatio, true);
5736
- try { await persist(ctx); } catch { /* The commit already reported its own outcome. */ }
3652
+ // Until this lands the epoch's folds are in the event stream and nowhere else.
3653
+ // Swallowing the failure here announced a commit that does not exist and left the
3654
+ // session computing folds it would keep throwing away, which is the dead session
3655
+ // gate 122 was built for, reached through the user's own command instead.
3656
+ try { await persist(ctx); }
3657
+ catch (error) {
3658
+ suspendAutomatic(error, "user-command", ctx);
3659
+ updateStatus(ctx);
3660
+ throw error;
3661
+ }
5737
3662
  updateStatus(ctx);
5738
3663
  safeNotify(
5739
3664
  ctx,
@@ -5792,7 +3717,7 @@ export function registerActiveContext(pi: any, options: {
5792
3717
  ladder.actionQueue = operation.catch(() => undefined);
5793
3718
  try { await operation; }
5794
3719
  catch (error) {
5795
- safeNotify(ctx, `Context rescue failed: ${error instanceof Error ? error.message : String(error)}`, "error");
3720
+ safeNotify(ctx, `Context command failed: ${error instanceof Error ? error.message : String(error)}`, "error");
5796
3721
  }
5797
3722
  };
5798
3723
 
@@ -5822,12 +3747,11 @@ export function registerActiveContext(pi: any, options: {
5822
3747
  lifecycle.generation += 1;
5823
3748
  lifecycle.shuttingDown = true;
5824
3749
  cancelPreparation();
5825
- cancelBriefUpgrades();
5826
3750
  persistence.state = null;
5827
3751
  persistence.persisted = null;
5828
3752
  lifecycle.latestSnapshot = null;
5829
3753
  curation.receipts = [];
5830
- try { ctx.ui?.setStatus?.(entryTypePrefix, undefined); } catch { /* Shutdown cannot be blocked by UI. */ }
3754
+ try { ctx.ui?.setStatus?.(entryTypePrefix, undefined); } catch { }
5831
3755
  });
5832
3756
 
5833
3757
  return { projectionCandidates };