<!-- generated by workspace-docs. source: pi-compaction-model revision 8. do not edit; author with workspace-docs checkout. -->

# Pi compaction model: selection and summary contract

## Contents

- [Scope](#scope)
- [Contract](#contract)
- [Limits](#limits)
- [Shared behavior release](#shared-behavior-release)


## Scope {#scope}

This package selects a separate model for manual and automatic Pi compaction. It does not change the conversation model or branch summaries.

The implementation uses Pi's public `compact()` helper and the `pi-advisor` model picker pattern. Configuration belongs to the current Pi agent directory.

No model is selected at installation. The user selects the model and its provider. Selection can send session contents to that provider during later compaction.

The package does not install itself, change live settings, or make model calls during validation.

## Contract {#contract}


<a id="REQ-1"></a>

**REQ-1**

The extension MUST register the user-only `/compaction-model` command. With UI, the bare command MUST open a searchable model picker. It MUST list available physical chat models and mark the current selection. In RPC, it MUST use the supported select dialog. Without UI, the bare command MUST show the selection and usage.

The command MUST accept `show`, `reset`, and `<provider> <model>` arguments. Invalid arguments, unavailable models, and picker cancellation MUST leave settings unchanged. Selecting a model MUST save `{ "model": { "provider": "...", "model": "..." } }` in `<agentDir>/compaction-model.json`. Reset MUST save `{}` and restore Pi's default behavior. Settings MUST persist across extension reloads and sessions in that agent directory. Commands MUST NOT make model calls or change the conversation model.


<a id="AC-1"></a>

**AC-1**

Changed behavior. Registration, picker, RPC, and direct-command tests MUST confirm selection, persistence after reload, cancellation, show, reset, invalid-input rejection, and no model calls. The TUI check MUST exercise fuzzy search, current selection, focus forwarding, and narrow rendering.


- #REQ-1 verified-by: [#AC-1](#AC-1)


<a id="REQ-2"></a>

**REQ-2**

When settings select a model, `session_before_compact` MUST call Pi's public `compact()` with that physical model. It MUST use the configured model registry for provider dispatch and authentication. It MUST preserve the prepared kept boundary, summary format, custom instructions, previous summary, split-turn behavior, and usage accounting. It MUST preserve cumulative file lists across this extension's compactions. It MUST NOT add retries or inherit the conversation's thinking level.

An in-progress compaction MUST keep its selected model even if settings change. The extension MUST use Pi's existing output allowance and disable prompt-cache writes through the helper. It MUST reject requests when Pi's estimated input tokens plus the requested output allowance exceed the selected model's context window.


<a id="AC-2"></a>

**AC-2**

Changed behavior. Mocked provider tests MUST confirm selected-model dispatch for manual, threshold, and overflow events. They MUST inspect native summary prompts, retained boundaries, instructions, previous context, split-turn requests, usage, file lists, and absence of inherited reasoning or extra calls. A settings change during a split compaction MUST NOT change its model. Inclusive context-boundary tests MUST permit an estimate equal to the window and reject one token above it.


- #REQ-2 verified-by: [#AC-2](#AC-2)


<a id="REQ-3"></a>

**REQ-3**

If configured compaction fails, the hook MUST return `cancel: true` and report an error. Missing models, unavailable authentication, invalid settings, context overflow, provider errors, abnormal stops, empty summaries, and cancellation MUST NOT fall back to Pi's conversation model. A provider result returned after cancellation MUST NOT become a summary. Error reports MUST NOT expose raw provider messages or session contents.

If UI or message reporting fails, the extension MUST report a fixed error on stderr and still return explicit cancellation.


<a id="AC-3"></a>

**AC-3**

Changed behavior. Fault-injection tests MUST confirm explicit cancellation without a compaction result for each specified failure. They MUST confirm no retry, no default-model dispatch, no late summary, and no private error text in reports. A reporting failure MUST NOT prevent cancellation or expose its raw error.


- #REQ-3 verified-by: [#AC-3](#AC-3)


<a id="REQ-4"></a>

**REQ-4**

The settings reader MUST accept only a missing file, `{}`, or an object with one valid model selection. The reader MUST reject unknown fields, invalid JSON, symlinks, non-regular files, and files above 16384 bytes. Writes MUST use an owned temporary file and atomic replacement. In-process writes MUST use Pi's file mutation queue. A failed write MUST NOT replace valid settings. Reset MUST permit recovery from malformed regular-file contents, but MUST NOT follow a symlink.


<a id="AC-4"></a>

**AC-4**

Changed behavior. Temporary-file tests MUST cover strict parsing, the inclusive 16384-byte boundary, symlink and directory refusal, malformed-file reset, successful atomic replacement, failed-write preservation, concurrent writes, and owned temporary-file cleanup.


- #REQ-4 verified-by: [#AC-4](#AC-4)


<a id="REQ-5"></a>

**REQ-5**

Without a configured selection, the hook MUST return no override and make no model call. The package MUST load through installed Pi without a provider call. It MUST declare host-provided peer dependencies, not runtime copies of Pi packages.


<a id="AC-5"></a>

**AC-5**

Preserved behavior. A baseline no-selection check MUST confirm no override and no generation. It MUST still pass after implementation.


<a id="AC-6"></a>

**AC-6**

Changed behavior. Installed-Pi loader tests MUST discover exactly one command and the compaction hook without errors or generation. Package inspection MUST confirm host-provided peers and no runtime Pi dependencies.


- #REQ-5 verified-by: [#AC-5](#AC-5)


- #REQ-5 verified-by: [#AC-6](#AC-6)


<a id="REQ-6"></a>

**REQ-6**

The release manifest MUST omit `private` or set it to `false`. It MUST set `publishConfig.access` to `public`. The three Pi peer dependencies MUST use `^1.1.0`. This range excludes versions below 1.1.0 and versions at or above 2.0.0. The README MUST document `pi install npm:@neruok/pi-compaction-model` and identify 1.1.0 as the tested Pi version.

The manifest MUST set `prepublishOnly` to `npm run verify`. The hook MUST return zero when verification succeeds and nonzero when verification fails. Verification MUST NOT install packages, publish, or make live compaction-provider calls. Release preparation does not authorize a commit or registry publication.


<a id="AC-7"></a>

**AC-7**

Changed behavior. Manifest and README checks MUST confirm public-release metadata, the specified Pi peer ranges, and the npm installation command. Existing package-loader checks MUST continue to confirm host-provided peers without runtime Pi copies.


<a id="AC-8"></a>

**AC-8**

Changed behavior. Isolated npm lifecycle checks MUST exercise the actual `prepublishOnly` script with a test `verify` command. The check MUST confirm that verification runs, success returns zero, and failure returns nonzero. The check MUST NOT invoke npm publication or recurse into the package test suite.


- #REQ-6 verified-by: [#AC-7](#AC-7)


- #REQ-6 verified-by: [#AC-8](#AC-8)


<a id="REQ-7"></a>

**REQ-7**

For each failed compaction, the extension MUST report one safe category. It MUST use only these categories: `settings`, `model-unavailable`, `authentication-unavailable`, `context-window`, `provider-error`, `output-limit`, `aborted`, `unexpected-stop`, `tool-call`, `empty-summary`, and `summary-error`.

Settings-read failures MUST use `settings`. Model lookup failures and virtual models MUST use `model-unavailable`. Authentication-check failures MUST use `authentication-unavailable`. Local context rejection MUST use `context-window`. Provider exceptions and error responses MUST use `provider-error`. Length stops MUST use `output-limit`. Aborted responses and an observed aborted signal MUST use `aborted`. Other non-stop responses MUST use `unexpected-stop`. A normal stop with tool calls MUST use `tool-call`. A normal stop without nonempty text MUST use `empty-summary`. Other native-summary failures MUST use `summary-error`.

An observed aborted signal MUST take precedence over other categories after settings select a model. Response validation MUST check stop reason before content. It MUST check tool calls before empty text. The extension MUST NOT infer categories from exception names or messages.

Each report MUST show the estimated input tokens, requested output allowance, and model context window for the most recent summary request in that compaction. Before a summary request exists, all three values MUST show `unknown`. A non-finite, negative, or non-integer value MUST show `unknown`. The report MUST identify the input count as an estimate. Split-turn reports MUST use the failed request's values, not an earlier request's values.

Reports MUST use fixed text, safe categories, and numeric token values only. Reports MUST NOT expose exception text, provider messages, model identifiers, prompts, or summary contents. Failure MUST still cancel without retries or default-model fallback. Reporting faults MUST retain the fixed stderr fallback.


<a id="AC-9"></a>

**AC-9**

Changed behavior. Fault-injection tests MUST check every REQ-7 category in UI and non-UI reports. Tests MUST check abort precedence, unknown stop reasons, and tool-call precedence over empty text. Reports MUST show exact per-request estimated input, output allowance, and context window values. Tests MUST check local overflow before dispatch, split-turn failure on the second request, invalid numeric values, and unknown budgets before request preparation. A later compaction failure MUST NOT reuse an earlier compaction's budget. Private sentinel values in exceptions, model identifiers, prompts, and responses MUST never appear in reports.

Preserved behavior uses AC-3 and AC-5 baselines. Existing fault and installed-session tests MUST continue to confirm cancellation, no retries, no default-model dispatch, fixed stderr fallback, and unchanged no-selection behavior.


- #REQ-7 verified-by: [#AC-9](#AC-9)


<a id="REQ-8"></a>

**REQ-8**

The extension MUST accept `/compaction-model reasoning [level]` for the saved compaction model. With no model selected, it MUST report an error without writing settings.

With UI and no level argument, the command MUST open Pi's supported select dialog. The dialog MUST show the current level and offer `default` plus Pi's `getSupportedThinkingLevels(model)` values. Without UI, it MUST report those choices without writing settings. Cancellation MUST leave settings unchanged.

The model selection MAY contain an optional `reasoning` field. Its valid values are `default`, `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. The reader MUST reject other values, including null and empty strings. Omission and `default` MUST retain legacy provider behavior. Selecting a model MUST reset reasoning to omission. Reset MUST remove the model and reasoning.

An explicit level other than `default` MUST appear in Pi's advertised levels for the selected model. Unsupported levels MUST leave command settings unchanged. If persisted settings become unsupported, compaction MUST cancel before provider dispatch with category `settings`. Abort precedence from REQ-7 still applies.

Compaction MUST pass the saved level to Pi's native helper. `default` and omission MUST pass no thinking level. `off` MUST retain Pi's native helper behavior, which omits the reasoning option. Both split-turn requests MUST keep the level loaded at hook entry, even if settings change.

Commands MUST NOT make model calls or change the conversation model or thinking level. The extension MUST NOT clamp unsupported effort or change Pi's output allowance.


<a id="AC-10"></a>

**AC-10**

Changed behavior. Command tests MUST confirm UI selection with current-level display, RPC selection, cancellation, no-UI choice listing, direct levels, show, and persistence after reload. Tests MUST confirm unsupported and invalid levels leave bytes unchanged. No-selection reasoning commands MUST NOT create settings. Model selection and reset MUST clear saved reasoning. Commands MUST make no provider call or conversation-setting change.

Settings tests MUST round-trip every REQ-8 value and reject invalid fields without replacing valid settings. Provider tests MUST confirm each supported non-off level on manual, threshold, and overflow compaction. Both split-turn requests MUST keep the initial level after a settings write. Unsupported persisted levels MUST cancel before dispatch with a safe `settings` report.

Preserved behavior. Existing AC-1 through AC-9 checks MUST pass before and after this change. Additional checks MUST confirm omission, `default`, and `off` omit reasoning, non-reasoning models permit only `default` and `off`, and output allowances remain unchanged.


- #REQ-8 verified-by: [#AC-10](#AC-10)


## Limits {#limits}

Input-token checks use Pi's estimator, not a provider tokenizer. They can reject a request that would fit remotely.

The extension cannot guarantee lower bills or summary quality. Provider billing and retention rules still apply.

Other extensions can also override compaction. Load only one compaction override when these guarantees matter.

## Shared behavior release {#shared-behavior-release}

The 0.3.0 release uses @neruok/pi-common@0.1.0 as an exact runtime dependency.
A clean checkout installs the library from npm. It does not need a sibling library repository.
Host SDKs remain peer dependencies. The release adds no provider call, command, domain schema, or spending default.

The library owns model selection, reasoning discovery, settings transactions, command reporting, and text sanitization.
Advisor and magic8ball also share completion mechanics. Domain model eligibility, trust, paths, budgets, and result schemas remain local.

Magic8ball RPC labels use provider/model without slash spacing. Safe settings reports reach non-UI sessions without starting a turn.
Compaction settings now refuse foreign locks and immediate-parent symlinks. Explicit reset still repairs malformed regular files.
Shared writes do not reclaim stale locks or guarantee power-loss durability. Inspect a failed save before retry.
Transcript viewing retains UI-only delivery. Captured transcript text does not enter custom session messages.

Release checks use independent clean installs and Pi's package manager. Registry availability and integrity require separate verification after upload.

<a id="COMMON-REQ-1"></a>

**COMMON-REQ-1**

The release MUST declare @neruok/pi-common as its sole runtime dependency, pinned to 0.1.0 without a file or workspace path.
Host SDKs MUST remain peers and MUST NOT be bundled.
The extension MUST use the common behavior governed by pi-common CC-REQ-1 through CC-REQ-5.
Domain command grammar, model eligibility, scope authority, spending defaults, result schemas, and transcript privacy MUST remain local.
Release checks MUST install the published common dependency without a sibling checkout and load the consumer through its tested Pi host.


<a id="COMMON-AC-1"></a>

**COMMON-AC-1**

Changed behavior. The release dependency check fails for the earlier local file dependency and passes for exact registry 0.1.0.
The source and lockfile identify the same release version and common dependency. The lock records registry resolution and verified integrity without a source link.
Clean clone verification, packed npm installation, and isolated Pi package installation pass without sibling sources or provider calls.
The installed extension registers its expected tools and command. Safe show and cancellation operations use the shared behavior without model generation.
Registry metadata and the downloaded release tarball agree with the inspected artifact and remote source commit.


- #COMMON-REQ-1 verified-by: [#COMMON-AC-1](#COMMON-AC-1)


- #COMMON-REQ-1 depends-on: [pi-common#CC-REQ-1](../../../../pi-common/worktrees/main/docs/pi-common.md#CC-REQ-1)
