Skip to content

Moved session: stale history boundary → MC-H04 blocks every request #702

Closed

Description

@JKratto

Short description

A session moved to another project directory gets every request blocked with MC-H04: the cached history boundary exists but no longer sorts before the first live message, and /ctx-recomp cannot repair it from the old project's instance.

What happened?

Environment at incident time: MC 0.47.0, OpenCode v2.0.26, macOS arm64. Verified against 0.49.0 dist: classifyAbsentBoundary and the re-anchor path are byte-identical — still reproduces.

Case 1 (main): session moved between projects

Session moved once via OpenCode 2 session_move (previous directory ~/Ansible, new ~/Programming/trainings/ai-class, one location-switched row in session_message).

  • The boundary row msg_12a9337e30012hQvQHjukAWwcW exists in session_message (seq 144), but in the moved session's view the first live message is msg_12a938311002ikUeRMPynNWKFG — the boundary does not sort before it. boundaryPrecedesWindow is false, so classification goes to refused:
[2026-10-11T16:23:33] prefix trim: boundary msg_12a9337e30012hQvQHjukAWwcW absent from current messages; pass=priced; no in-pass trim applied (degraded pass N; boundary does not sort before the first live message msg_12a938311002ikUeRMPynNWKFG; whole window served until a cache-busting pass moves the boundary into the window)
[2026-10-11T16:23:33] history boundary unresolved: prefix trim refused and the untrimmed request estimate 188048 (trusted=true) exceeds the context limit 187500; not sending it
[2026-10-11T16:23:33] v2 refusal: ... UnresolvedHistoryBoundaryError: ... (MC-H04)
  • 9 refusals over ~15 h (degraded pass reached 235). User-visible MC-H04 text says the boundary "is missing from the OpenCode store" — it isn't: select count(*) from session_message where id='msg_12a9337e...' = 1. The misleading text sends the user to /ctx-recomp, which then fails:
[2026-10-12T07:39:36] historian prompt failed: HiddenCompletionRefusal message="hidden_prompt_unrecognized: hidden child ses_ed0f27f2fffemAIRqjii0mfhc3 is bound to ~/Programming/trainings/ai-class, not to this instance's ~/Ansible" code=hidden_prompt_unrecognized

So the instance that would advance the boundary refuses the repair, and the instance whose directory matches isn't asked.

Recovery: reopening the session in its new directory triggered historian recovery on load from the matching instance (child bound correctly, publish completed, new boundary), healthy since:

[2026-10-12T08:12:36] transform: historian recovery triggered on session load after 2 failure(s)
[2026-10-12T08:13:17] historian publish completed: compartments=1 range=20-25
[2026-10-12T08:39:32] prefix trim: boundary msg_12ae31746001HSzXX7cLUrFeID precedes the first remaining message ...; nothing to cut

doctor still records the failure reason on the session (historian_runs: 8 total, 6 success, 2 failed, lastFailureReason: ... hidden_prompt_unrecognized ...).

Case 2: same refusal arm without a move

Same day, a never-moved session hit the identical refusal (estimate 344916 vs limit 187500): rows were deleted out of session_message (sparse seq gaps), so the first live message ended up older than the boundary — same refused arm, self-healed after historian recovery advanced the boundary.

Diagnostics

Plugin version

0.47.0 at incident time (current 0.49.6; logic byte-identical in 0.49.0)

OpenCode version

v2.0.26 at incident time (current v2.0.31)

Platform

macOS 27.0.1 arm64

Client

OpenCode TUI (CLI)

Log output (optional)

[2026-10-11T16:23:33] prefix trim: boundary msg_12a9337e30012hQvQHjukAWwcW absent from current messages; pass=priced; no in-pass trim applied (degraded pass 235; boundary does not sort before the first live message msg_12a938311002ikUeRMPynNWKFG; whole window served until a cache-busting pass moves the boundary into the window)
[2026-10-11T16:23:33] history boundary unresolved: prefix trim refused and the untrimmed request estimate 188048 (trusted=true) exceeds the context limit 187500; not sending it
[2026-10-12T07:39:36] historian prompt failed: HiddenCompletionRefusal message="hidden_prompt_unrecognized: hidden child ses_ed0f27f2fffemAIRqjii0mfhc3 is bound to ~/Programming/trainings/ai-class, not to this instance's ~/Ansible" code=hidden_prompt_unrecognized
[2026-10-12T08:12:36] transform: historian recovery triggered on session load after 2 failure(s)
[2026-10-12T08:13:17] historian publish completed: compartments=1 range=20-25

Activity

  1. magic-alfonso commented on Oct 16, 2026

    @magic-alfonso

    Thanks for the detailed report, including the store check and the recovery log. That's enough to start without more data from you.

    We see two problems here, and are looking at both:

    1. After the move, the saved history boundary still exists, but it no longer sorts before the first message the session now loads. That lands in the refused case rather than the re-anchor added for deleted boundaries, and every request stops with MC-H04. The MC-H04 text then wrongly says the boundary is missing from the store, which points you to /ctx-recomp.
    2. /ctx-recomp from the old project's instance can't repair it, because the hidden historian child belongs to the session's new directory.

    Your second case, with rows deleted out of session_message in a session that never moved, hits the same refused path, so the fix needs to cover that too. We'll reproduce both on a real OpenCode 2 host and post here when a fix is ready.

  2. magic-alfonso commented on Oct 17, 2026

    @magic-alfonso

    Fixed in v0.49.8. When a session's summarized-history boundary still exists in the OpenCode database but falls outside the loaded message window (a moved session, or deleted old rows), Magic Context now places it using its stored order instead of refusing the turn. Recovery commands (/ctx-recomp, /ctx-wrapup) also reach the plugin instance for the session's current folder. Both of your scenarios go through on a real OpenCode 2.0.31 host.

    One upgrade note: some OpenCode 2 sessions see a one-time change in the cached request prefix after updating, because previously dropped host instruction updates are now kept. Thanks for the detailed evidence.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions