Skip to content

rust mode: a session that ran under TS after an earlier rust run is served raw on every later rust pass (retained boundary never reappears, so pending_rewrite never clears) #527

Description

@iceteaSA

Summary

Suppose a long-lived OpenCode session ran in rust mode, went back to TS authority, and then went back to rust mode. From that point the module serves it raw on every pass. It keeps doing so no matter how many times the session is flipped. The host records each of these passes as decision=passthrough. The module applies no m[0]/m[1], no drops and no fold.

Source cited is v0.43.0 (092473b32). The live evidence below was recorded under earlier module binaries, but the code paths involved are unchanged in v0.43.0.

Mechanism

  1. When the session returns to rust mode, state sync seeds the host's current boundary. The module row is already initialized, so the store keeps its own older boundary and ignores the seed. See crates/mc-store/src/lib.rs:10931-10935:

    mc-store: retained materialized boundary {:?} over state-sync seed {:?}

    The comment there assumes the TypeScript mirror is lagging behind the module. After a period under TS authority it is the other way round: the host is ahead, and the module's boundary is weeks old.

  2. That retained boundary is no longer in the live array. OpenCode's filterCompacted cuts the input at the host's compaction marker, which TS mode has moved far past the old boundary. The transform treats this as a share-nothing boundary absence on a session with held lineage. It arms pending_rewrite and serves raw (crates/mc-module/src/transform.rs:3691-3698 and :3803).

  3. The transform clears pending_rewrite in one place only, clear_pending_rewrite_on_present (transform.rs:4668), and only when the absent boundary shows up again in the live array. After the compaction marker has passed it, it never shows up again. The other clearing site in the store, lib.rs:10942, runs only for a row that is not yet initialized.

So for an initialized session there is no path back.

Live evidence (one session, 08-28 → 09-19)

store.db mc_cache_state row for the session (row_version 175, last activity 2026-09-19T09:58:11Z):

pending_rewrite = {"armed_at_ms":1788120961447, "absent_request_count":1, "last_present_at_ms":1787943345479, ...}

armed_at_ms is 2026-08-30 ~20:16Z. The boundary was last seen live at 2026-08-28.

Host transform_decisions for the same session, by hour:

2026-08-30 20Z  passthrough  6    (armed during this flip)
2026-09-14 13Z  passthrough  53
2026-09-18 15Z  passthrough  21
2026-09-19 09Z  passthrough  37

After it was armed, no pass was served from the transform.

Module stderr on the two later flips:

mc-store: retained materialized boundary "msg_04925fa28001…#1" over state-sync seed "msg_09ffd5a47001…#2" for session ses_14a5…
mc-store: retained materialized boundary "msg_04925fa28001…#1" over state-sync seed "msg_0b48f8adf001…#2" for session ses_14a5…

Each was followed by one mc-module: pending_rewrite raw pass-through for ses_14a5… fingerprint … line per pass: 58 lines, which is 21 + 37. The retained boundary message was created 2026-08-28T16:13:40Z. The seeds it overrode are from 2026-09-14 and 2026-09-18, and 1,811 messages of the session sit between the retained boundary and the later seed.

Repro outline

  1. Run a session in transform_mode: "rust" until the module row is initialized and has materialized a boundary.
  2. Switch the project back to TS and keep working until the historian publishes and the compaction marker moves past the module's boundary.
  3. Switch back to rust. The first pass logs retained materialized boundary … over state-sync seed …. Every later pass then logs pending_rewrite raw pass-through and records decision=passthrough, and it never recovers.

Expected

A state-sync seed that is strictly newer than the module's boundary should be adopted, or should at least clear pending_rewrite. That way a TS-then-rust round trip resumes transforming instead of serving raw for good. If keeping the boundary is deliberate, the session should say so (in health or status), because right now rust mode just looks like it is running.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions