Skip to content

editor: slide activity rows to the newest window instead of the oldest - #501

Merged
sandersonstabo merged 1 commit into
masterfrom
activity-window
Sep 28, 2026
Merged

sandersonstabo merged 1 commit into
masterfrom
activity-window

Conversation

@sandersonstabo

@sandersonstabo sandersonstabo commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

Why

In a long thread (VeriGuard, 381 activity items), tool calls stopped appearing after the first few commands of the live turn while prose kept streaming. project_activities sorted every retained row oldest-first and truncated to MAX_PROJECTED_FACTS = 256, so each replay re-picked the same oldest rows and the newest were never projected. The Forge had stored and delivered all of them (132 commands in the live run).

What

  • activity_window(snapshot) = SCENE_MAX_ITEMS - snapshot.items().len(). The projection keeps the newest facts that fit and reports the rest as evicted.
  • Replay removes registered derived facts that slid out of the window before upserting, so their room goes to live work instead of hitting the scene bound (which also swallowed errors).
  • Fact ordinals count every projectable row, evicted ones included. A fact keeps its ordinal while the window slides; positional ordinals would collide (SceneConflict) and drop the newest row.
  • ConversationStateController::derived_fact_ids / ConversationHost::derived_fact_ids expose the derived facts for that removal.

Tests

activity_slides_to_the_newest_window_and_frees_room_for_live_work fills a turn past the window, checks the oldest rows slid out and the newest are kept, then adds live work and checks it takes the freed room. It fails against the old projection.

cargo test -p artisan-frontend --test conversation_observation_projection: 21 passed.
--lib: 775 passed, 3 failed. work_group_header_row_paints_without_a_disclosure_wrapper, send_has_stable_identity… and harness_switch_animation_settles_without_rebuilding_catalog fail identically on master.

Follow-up, not in this PR: snapshots whose own durable items exceed SCENE_MAX_ITEMS are still refused, and older turns are never range-loaded.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes activity projection so the newest tool calls appear in long threads instead of being stuck behind the oldest retained rows.

  • The projection now keeps the newest activity facts that fit the scene window and evicts the oldest.
  • Replay removes derived facts that slid out before upserting, freeing room for live work.
  • Fact ordinals count every projectable row, so a fact keeps its place as the window slides.

Written for commit 088d84a. Summary will update on new commits.

Review in cubic

A thread with more activity than one projection kept (256 facts, oldest
first) stopped showing new tool calls: every replay re-picked the same
oldest rows, so the live turn's commands never projected while its prose
kept streaming.

Activity now slides like the loaded conversation: a projection keeps the
newest facts that fit beside the snapshot's durable items, and replay
removes derived facts that slid out before upserting, so their room goes
to live work instead of stalling at the scene bound. Ordinals count every
projectable row, so a fact keeps its place while the window moves.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@sandersonstabo
sandersonstabo merged commit 44c7a42 into master Sep 28, 2026
20 of 30 checks passed
@sandersonstabo
sandersonstabo deleted the activity-window branch September 28, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant