- Remove loopHookActive flag, skipAfterTurn param, and the conditional skip in finalizeAttemptContextEngineTurn
- The finalize afterTurn must run to ingest the final assistant message which is appended after the last transformContext call
- lossless-claw deduplicates internally so the overlap with the loop hook's earlier ingestion is benign
- Compare assembled.messages !== sourceMessages instead of length, so engines that rewrite content without changing array count are respected
- Add test for same-count-different-reference assembly
- Return the last assembled view on unchanged iterations instead of falling back to raw source messages, so API retries use the compacted context
- Add skipAfterTurn param to finalizeAttemptContextEngineTurn so the end-of-attempt path skips ingestion when the loop hook already handled it during the tool loop
- Set loopHookActive flag at install site and pass it through to finalize
- Add test verifying cached view is returned on retry
- Decouple lastSeenLength advancement from afterTurn existence so engines without afterTurn still advance the fence and trigger assemble on new messages
- Use hasNewMessages flag instead of didCallAfterTurn for the assemble gate
- Add test verifying assemble fires on every iteration with new messages when engine lacks afterTurn
- Initialise lastSeenLength lazily from a caller-supplied getPrePromptMessageCount so the first afterTurn call uses the same fence as finalizeAttemptContextEngineTurn
- Skip engine.assemble on iterations where no new messages arrived and a previous assemble already happened
- Hoist prePromptMessageCount in runEmbeddedAttempt so the install site can pass a getter that resolves the correct value after heartbeat filtering
- Add 6 unit tests covering fence initialisation, lazy getter evaluation, fallback to 0, and assemble throttling
- Add unit coverage for the new per-iteration ingest and assemble hook
- Verify afterTurn is called once per delta with the correct prePromptMessageCount, and skipped when no new messages have been appended
- Verify the assembled view is returned only when its length differs from the source, and the source array is never mutated
- Verify the hook tolerates engines that do not implement afterTurn, and falls through to source messages when afterTurn or assemble throws
- Verify dispose restores the previous transformContext
- Add `installContextEngineLoopHook` to call `afterTurn` and return `assemble()` from `transformContext` on every LLM iteration
- Skip the built-in tool-result guard and preemptive overflow precheck when `info.ownsCompaction === true`
- Lets long-running subagents compact mid tool loop instead of only at end of attempt
- Sessions without a context engine, or where the engine does not own compaction, behave exactly as before