fix: plan-mode reminder ignored-flag is stale on cross-turn model switch (experimental flag)

Open
#890 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Quiet
Tech stack
typescript
Domain
backend

Research direction

Start in packages/opencode/src/session/prompt.ts at the experimental insertReminders branch, then trace the ignored gate in packages/opencode/src/session/message-v2.ts. Reproduce model switches under OPENCODE_EXPERIMENTAL_PLAN_MODE=true and add the GPT→Claude, Claude→GPT, and Gemini→GPT cases. Done means persisted reminders are evaluated for the active turn's model without changing the default path.

Written by the indexing model from the issue text.

Description

Found during v0.8.3 release review (Chaos Gremlin / prompt-injection red-team persona). Deferred because it needs a design change to the J2 persisted-flag ownership contract and a cross-vendor test matrix (>30 min).

Context

Under OPENCODE_EXPERIMENTAL_PLAN_MODE=true, insertReminders (in packages/opencode/src/session/prompt.ts) stamps ignored: true onto persisted reminder parts at insertion time, computed from the inserting turn's model via isAnthropicLikeModel. The flag is then persisted via Session.updatePart.

Bug

If the user switches models with /model between turns, the persisted ignored flag reflects the old turn's model, not the current one:

  • GPT-5.x (turn 1) → Claude (turn 2): the turn-1 reminder persisted with ignored: true. On turn 2 it's suppressed from Claude's user role by toModelMessages (gates on !part.ignored) and it's not in turn-2's freshly-built trustedReminderParts, so it isn't hoisted either → Claude silently loses that plan-mode constraint for the turn (degradation).
  • Claude (turn 1) → GPT-5.x (turn 2): the turn-1 reminder persisted with ignored unset. On the GPT turn it slips back into the user role as a <system-reminder> block → re-triggers the original #887 refusal class.

Both directions are flag-gated (default path unaffected, since default-path reminders are in-memory only and rebuilt each turn) and the GPT→Claude case is degradation-only, so this is not a default-path regression. But the experimental path ships a latent turn-ordering bug.

Suggested fix

Compute the hoist/ignored decision at read time per turn from the current turn's model, rather than baking it into the persisted row at insert time; or re-evaluate persisted reminder parts each turn against the active model. Add tests across the switch matrix (GPT→Claude, Claude→GPT, Gemini→GPT) under the experimental flag.

Scope

packages/opencode/src/session/prompt.ts (insertReminders experimental branch), packages/opencode/src/session/message-v2.ts (toModelMessages ignored-gate).

Dominant language
TypeScript
Stars
813
Forks
134
Avg merge
2d 5h
Merged PRs (30d)
62

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from AltimateAI/altimate-code

All issues in AltimateAI/altimate-code

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.