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
-
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.
-
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).
-
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
- Run a session in
transform_mode: "rust" until the module row is initialized and has materialized a boundary.
- Switch the project back to TS and keep working until the historian publishes and the compaction marker moves past the module's boundary.
- 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.
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
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. Seecrates/mc-store/src/lib.rs:10931-10935: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.
That retained boundary is no longer in the live array. OpenCode's
filterCompactedcuts 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 armspending_rewriteand serves raw (crates/mc-module/src/transform.rs:3691-3698and:3803).The transform clears
pending_rewritein 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.dbmc_cache_staterow for the session (row_version 175, last activity 2026-09-19T09:58:11Z):armed_at_msis 2026-08-30 ~20:16Z. The boundary was last seen live at 2026-08-28.Host
transform_decisionsfor the same session, by hour:After it was armed, no pass was served from the transform.
Module stderr on the two later flips:
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
transform_mode: "rust"until the module row is initialized and has materialized a boundary.retained materialized boundary … over state-sync seed …. Every later pass then logspending_rewrite raw pass-throughand recordsdecision=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.