Skip to content

Epoch view leaves room to grow at turnover (Atlas: shared prefix 3% to 89% on replay) - #5304

Merged
joelteply merged 3 commits into
canaryfrom
fable/epoch-growth-reserve
Oct 23, 2026
Merged

joelteply merged 3 commits into
canaryfrom
fable/epoch-growth-reserve

Conversation

@joelteply

Copy link
Copy Markdown
Contributor

This is plan line 2: a mind's context as an append-only epoch.

Problem. At a turnover, fit_view restarted every fully granted source whole, so the new epoch had no headroom. In a busy room, the next act's appends pushed the view past its grant and it turned over again. Each new epoch starts at a different oldest turn, so the whole prefix changed every act. View::appended_per_act was meant to provide this reserve, and the core never called it.

Change. In prompt/epoch.rs, fit_view and the new start_grants:

  • Grounding (above the lowest priority) starts whole.
  • The growing sources (conversation, results, thoughts) start at min((A-G)/2, A-G-per_act), where A is the view's grant plus room and G is grounding.
  • Allocation. flex_allocate spends the start, collapsing the oldest items first. The newest turn is always kept whole.
  • Why half. If the growing sources start at S and keep a reserve R, the epoch lives R/a acts, so re-prefilling costs S·a/R per act. Holding that to at most one act's appends needs R ≥ S, and the measured append rate a cancels out of the bound.
  • Before any act is measured, the start is half.

Replay validator. continuum-context/examples/replay.rs was extended to model the window budget and the turnover rule, with the core's measured characters per token. Using the old rule, it reproduces Atlas's live 3% exactly.

Resident / room Turnovers Shared prefix, mean / median Prefill per act, median chars
Atlas 11c1a7ac, before 6 5% / 3% 263,680
Atlas 11c1a7ac, after 1 75% / 89% 26,611
Aris 3be59578 (quiet), before / after 1 / 1 59% / 58% unchanged
Aris 11c1a7ac, before 6 46% / 26% 194,690
Aris 11c1a7ac, after 2 62% / 77% 53,847

Tests. Two new tests:

  • A sliding room used to turn over 30 times in 30 acts; it now turns over at most 2 times.
  • At a turnover, grounding stays whole, the oldest turn collapses, and the newest stays whole.

Core: 6,133 passed. continuum-context: 13 passed. Ratchets are unchanged.

Not fixed here (follow-ups, owner Fable):

  1. fit_view measures raw tokens while the final fit measures calibrated ones, roughly 3.5% apart. The final fit then cuts the oldest 96–99 messages from the view's head (Benchy). That is a head clip, which goal 7 forbids.
  2. Act and deliberation calls share one view with different grants, so switching between them turns the view over.

Live receipt: after deploy, a 15-minute read on the M5 of prefix reuse and act time. Owner Fable; this PR stays open until it is posted.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo

…etween turnovers

Serves the residents' minds directly (plan line 2, a mind's context as an append-only
epoch; gate: live prefix reuse >= 80%).

Cause, read on the M5's own probes (2026-10-22): at a turnover a source granted all it
wants restarted whole, so the start filled its grant. Atlas in 11c1a7ac started at
~259k chars against 87.6k tokens granted with 1,902 tokens of room, appended ~9.4k chars
(~3.2k tokens) per act, and turned over on every act (epochs 7..15, delib.view.sized);
3-11% of consecutive prompts shared.

Fix, at the one owner (prompt/epoch.rs, `start_grants`, called by `fit_view`): the
grounding blocks (above the lowest priority) start whole at their grant; the growing
sources (conversation, results, thoughts) start at most half of what is left, and at most
that less one act's appends (`View::appended_per_act`, converted at the claims' own
chars-per-token). Derivation in the doc comment: holding the growing sources' re-prefill
to one act's appends over the epoch's life gives reserve >= start, so the measured rate
cancels; it binds only when one act appends more than half of what they may hold. The
one allocator (`flex_allocate`) spends it: higher priorities ask for their whole grant as
their minimum, the lowest shares the rest, oldest items collapse first. The turnover
trigger is unchanged.

Replay (continuum-context examples/replay.rs) now models the core: room turns are her
conversation source, sources render in the core's order and priorities, the window is the
recorded context_window less the reply runaway at the core's own chars/token, and both
rules are replayed. Atlas 11c1a7ac: 6 turnovers -> 1, shared prefix mean 5% -> 75%
(median 3% -> 89%), view prefill median 263,680 -> 26,611 chars per act. Aris 3be59578
(quiet): mean 59% -> 58%, median 85% -> 84%, 1 turnover each.

Tests: two in tests/prompt_shaping/a_busy_room_keeps_its_prefix.rs (a sliding room turns
over every act restarting whole, at most twice in 30 acts with the reserve; grounding
stays whole and the newest turn whole at a turnover). continuum-core lib 6133 passed;
continuum-context 13 passed; ratchets unchanged.

Removed: the inline half-grant allocate closure in fit_view (15 lines); added
start_grants (~65 lines with its derivation), 2 tests, replay model (+~170).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
joelteply and others added 2 commits October 22, 2026 22:57
…d tokens)

fit_view compared the view's raw token estimate with grants in charged tokens. A view near
its grant passed, then the final fit (which converts its budget back to raw) cut the oldest
96-99 view messages from the front with no turnover: a head clip (Benchy, the M5,
2026-10-23, delib.fill.history_dropped). Charging the view through the same calibration makes
an over-grant view turn over (a deliberate re-prefill with a growth reserve) instead.

Measured after deploy (owner Fable): delib.fill.history_dropped no longer fires on view
messages, and live prefix reuse on the M5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoTjvf5j3Ez13g6k8mRkFo
@joelteply

Copy link
Copy Markdown
Contributor Author

I removed the unit-mismatch commit (ae895ff) from this PR. It failed provider_context_feedback_bounds_replay_and_scales_next_turn (window_feedback.rs:566), and my first explanation of that failure didn't hold up. It now lives on its own branch, fable/epoch-unit-charge, and will come back as a separate PR once that test passes. This PR is the growth reserve only: head = 5cac179 plus a revert that restores the tree exactly.

@joelteply
joelteply merged commit bb91bcf into canary Oct 23, 2026
9 checks passed
@joelteply
joelteply deleted the fable/epoch-growth-reserve branch October 23, 2026 05:00
@joelteply

Copy link
Copy Markdown
Contributor Author

Live receipt, M5, bb91bcf, 05:09–06:40Z. Prefix reuse on warm acts: 88–94%: Aiko 108,972/115,845; Aris 70,392/77,551 and 70,392/80,448. It was 0% before the deploy. Engine prefill on those warm acts was 133–251 s. Acts are still long because of slot waits of 812–2,084 s: every resident went cold at the restart, and each cold prefill of 100k+ tokens held a slot for 1,386–2,611 s. The remaining cost is admission and restart coldness, not the epoch view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant