Files
learnharness/docs/compaction-accounting.md
T

5.2 KiB

Compaction and usage accounting

Retention

src/core/compaction.ts locally ports the cutoff-selection behavior and relevant message-size heuristic from @earendil-works/pi-coding-agent 1.4.0. There is no coding-agent dependency. Upgrade this port deliberately; the native golden fixtures are in tests/compaction-native-parity.test.ts.

Walk backward to the approximately 20,000-token retained-tail budget, then select the nearest valid user/assistant boundary at or after the crossing. Never start at a tool result. If trailing results alone exceed the budget, keep the preceding assistant call. Preserve adjacent context-invisible metadata. LearnHarness adapts its visible custom markers to user-like entries, excludes UI-only markers, and uses the active compaction's retained history rather than discarded messages.

Text, visible thinking, tool-call names/arguments use characters divided by four; images receive the native fixed 1,200-token allowance. Encrypted signatures are not measured or stripped. Whole-message boundaries can overshoot. This does not guarantee a measured 20k tail or a fixed post-compaction request size.

Only cutoff selection is ported. LearnHarness retains its educational summary prompt, plan continuity, persistence, threshold, scheduling, and authorization lifecycle. It does not adopt Pi's coding summary or separate split-turn summary calls. A cut that drops no active history does not launch a summarizer.

When the active cutoff is applied, conversation requests carry the latest summary once, followed by the retained transcript without older compaction markers. When a subsequent compaction supplies that prior summary separately, it includes it once, plus the newly superseded transcript without summary markers. All markers and original messages remain stored. The existing full-history fallback for an unresolved cutoff is unchanged, including its summary text.

A provider response stopped at its output limit (length) is an incomplete summary, not a successful checkpoint. Compaction fails without changing the existing history or prior summary; a later attempt can retry normally.

Conversation meter

The numerator is the latest qualifying completed conversation response's native Pi input + output + cacheRead + cacheWrite. Reasoning is already inside output; totalTokens is not an override. Partial stream updates, errors, aborts, invalid counts, and all-zero usage do not replace the last measurement. A successful compaction marker invalidates earlier measurements: show ? / maximum until a new qualifying response completes. Summarizer usage never supplies this meter.

The denominator follows the selected model's catalog limit, independently of the last numeric measurement. Changing models preserves that numerator. No catalog limit means no invented denominator; no percentage display is added.

Spending

src/server/pricing.ts uses Pi AI's full, key-independent catalog and public calculateCost on a new usage object. The browser receives derived costs, not a second calculator/rate table. Totals are estimates using the currently shipped catalog, not provider invoices; catalog updates can reprice history.

Saved input is Pi-normalized fresh input, disjoint from cache buckets. Never subtract cached reads from it again or migrate old logs as raw inclusive prompt tokens. New captures preserve the one-hour subset of cache writes and individual background-job calls. Older write-bearing records with a lost retention split, and tier-priced multi-call jobs with only aggregate usage, remain unpriced when the lost detail can change the answer. They are not reconstructed from totals. Flat-rate historical jobs with sufficient counts remain priceable. Missing models or required usage stay unpriced; ChatGPT subscriptions remain plan usage, not API dollars. Summarizer costs continue to count toward session spending.

Upstream attribution

The cutoff/estimator port adapts MIT-licensed code from @earendil-works/pi-coding-agent 1.4.0, author Mario Zechner (published package metadata). The inspected dist/core/compaction/compaction.js SHA-256 is f51e78ef1da66b5803fc91e185f07b968f8f989ab9326b7744958416aad3f6f6.

MIT License

Copyright (c) Mario Zechner

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.