- core/compaction.ts: compactionCutIndex (backwards ~20k-token walk, NEVER
separates a tool result from its call — the cut extends to the call's
assistant message; a pending pose always survives), estimateTokens
(chars/4, pi's method), newCompactionMarker (header + summary; details
carry firstKeptMessageId/tokensBefore/model/at), serializeForSummary
(labeled text, tool results truncated ~2k), planTreeToText (verbatim
tree with transcript-derived statuses), buildCompactionPrompt (the four
ruled sections: learner understanding + evolution, teaching arc, plan
tree verbatim, current moment)
- toLlmMessages honors the cut: the ACTIVE (newest) marker renders ONCE
as the head; everything before firstKeptMessageId drops; corrupt cut
degrades honestly (everything renders, never throw)
- constants: KEEP_RECENT 20k, RESERVE 16k, DEFAULT_THRESHOLD 150k
- 16 test pins
* The summarizer prompt. The summary's REQUIRED SHAPE (owner rulings):
* the learner's understanding AND its evolution, the teaching arc, the
* plan tree verbatim, and the current moment — in that order of stress.
* The summarizer is the session's own model (owner ruling), writing for
* its own future self: the summary replaces everything before the cut.
*/
exportfunctionbuildCompactionPrompt(input:{
/** The span to summarize, pre-serialized (serializeForSummary). */
spanText: string;
/** The plan tree rendered (planTreeToText) or null. */
planTreeText: string|null;
/** The session kind (wording: tutor vs practice agent). */
kind:"teach"|"practice"|"probe";
}):string{
constplanSection=
input.planTreeText??"No plan tree exists in this session (nothing was persisted).";
return`You are compacting the earlier part of a tutoring session — writing the summary your future self will read INSTEAD of that transcript. Everything before the cut is replaced by what you write; everything after stays verbatim. The learner's transcript below labels the learner as [LEARNER], the tutoring agent as [TUTOR], tool traffic as [RESULT …]/[SYSTEM NOTE].
Write the summary with EXACTLY these sections, in this order:
## The learner's understanding
The most detailed picture you can give of what this learner knows and how that EVOLVED across the session: what they answered and how well (quiz outcomes, correct reasoning, mistakes), their stated or displayed confidence, misconceptions that surfaced, which were corrected and which still stand. This section carries the most weight — future teaching decisions hang on it.
## The teaching arc
How the session progressed: what was covered and in what order, which explanations landed and which didn't, how the learner responded, where the momentum went. Include probe-phase findings if present.
## The plan dependency tree
Reproduce the session's current plan tree verbatim from the structure below — do not drop nodes, edges, or statuses.
${planSection}
## The current moment
What is happening RIGHT NOW at the cut: any question or problem awaiting the learner's answer, any commitment the agent has made that a later turn must honor, and the immediate next step.
Rules: no praise, no filler, no speculation beyond the transcript. Every claim about the learner must be traceable to what they actually said or answered. Keep every identifier (proposition ids, node ids, file paths) exact.
"Problem concluded — the composer is free; pose the next problem or wrap up.";
/** The compaction marker's model-facing header (owner round 14,
* 2026-10-05). The marker's content is this header + the summary — the
* single text the provider sees in place of the dropped span. Wording
* law: it must tell the model (a) a cut happened and is routine, (b) the
* summary replaces everything before it, (c) what follows is verbatim
* recent transcript — so the model neither re-asks covered ground nor
* distrusts the seam. */
exportconstCOMPACTED_HISTORY_HEADER=
"[SESSION HISTORY COMPACTED] The transcript before this point was summarized to fit the context window; the summary below replaces it. Everything after this message is the verbatim recent transcript.";
exportinterfacePlanBlockData{
/** Only "full" survives (the 2026-09-11 pivot): the plan renders IN
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.