What happened?
This consolidates V2-specific findings against current source. It separates reproducible defects, missing V2 capabilities, and known host differences. It is not a request to transplant V1 internals or to fix unrelated MC bugs.
Related: #488 (V2 umbrella), #489 / #477 (store recognition), #481 (hidden-session lifecycle). Their already-merged fixes are accounted for below.
Revisions and test scope
- MC operational inventory:
00e7e5c17913ae252430eff56ac441adbd3f7bc2.
- OpenCode V2:
58fcad77a8a2e4abcbe985c395e7192801003857 (2.0.11 lineage).
- Main boundary and tool-state reproductions: MC
e35736c7d19b48781aa75b16da30a599bcd3428d; subsequent changes through 00e7e5c1 do not alter those paths (TUI sidebar, parity documentation, Cargo lockfile).
- Contributor branch reviewed:
blasphemy/magic-context:v2-fixes-updates at 31634ea3. Proposed implementations there are distinguished from merged support; its full host behavior was not independently accepted.
Tests use isolated source checkouts and synthetic SQLite data. No live migration, installed configuration changes, or provider calls were used. Reproducers and the detailed coverage matrix accompany this issue.
Findings at a glance
| # |
V2-specific finding |
Evidence / affected scope |
| 1 |
Existing MC state is not reconciled with converted V2 messages/parts |
Reproduced wrong compartment ranges, stale search coordinates, and broadened queued reductions; affects existing history |
| 2 |
Ten of twelve canonical Dreamer tasks are filtered out |
Registry, V2 admission, executor wiring and focused tests; affects fresh V2 projects too |
| 3 |
Command surface is partial |
Four V1 commands lack V2 registration; three others have TUI entry points, not equivalent server/CLI registration |
| 4 |
Per-context tool transforms accumulate and contaminate full guidance |
Actual MC hook + native host tool state/request preparation; affects fresh V2 sessions too |
| 5 |
Hidden-session deletion discovers a default service rather than its owner |
Actual helper reproduction with synthetic registrations/intercepted HTTP; follow-up to lifecycle work |
| 6 |
Explicit experimental Rust mode is not wired through V2 |
Configuration and execution-path evidence; default TypeScript mode is unaffected |
| 7 |
Tool-definition telemetry is missing |
V2 lacks measurements and supplies an empty tool-set hash; sidebar attribution, not a demonstrated provider-budget failure |
1. Existing compartment boundaries drift after native conversion
The importer can split synthetic content into a separate row or replace a completed compaction pair with a native compaction record. MC's canonical conversational ordinals therefore change even when endpoint message IDs survive.
The reproducible cases derive the old coordinates through MC's actual V1 reader, persist ordinary compartment rows, run OpenCode's native projection, and read through MC's actual V2 reader:
- Synthetic split: saved endpoint
a2 moves from ordinal 4 to 5. The saved end remains 4. ctx_expand range recovery omits a2 and treats ordinal 5 as live tail. Direct message: 5 recovery succeeds.
- Completed compaction: saved endpoint
a2 moves from 5 to 4. The saved end remains 5. Range recovery includes u3, which was outside the saved compartment.
The mismatch persists after reopening the fixture. This demonstrates incorrect range selection, not deletion of source text.
Relevant source: MC hooks/magic-context/read-session-raw.ts, v2/hooks/store.ts, features/magic-context/compartment-storage.ts, tools/ctx-expand/tools.ts; OpenCode core/src/database/v1-migration.ts.
Acceptance: before existing MC state is consumed against V2 history, preserve the relationship between saved endpoint IDs and canonical ordinals; handle removed endpoints explicitly and make normalization restart-safe. Equivalent hand-authored V1/V2 fixtures are not sufficient coverage.
Other coordinate-bearing state must be checked as part of the same transition: search source/FTS ordinals and watermarks, protected-tail floors, compression depth, note/provenance anchors, compartment-chunk ranges, and persisted recomp staging. Merely having a callable reset/rebase helper does not establish that migration invokes it. These are acceptance cases, not independently asserted corruptions.
Attachment: repro/ and migration-issue.md contain the complete reproduction and scope limits.
Additional existing-state consequences, reproduced separately
Search index: seed the entire six-message V1 index before conversion. After a synthetic split produces seven canonical V2 messages, the real reconciliation scheduler advances its watermark to 7 and clears the dirty floor, but keeps a2 indexed at its old ordinal 4 instead of 5 and never inserts the new synthetic row at 4. Existing entries before the old watermark were not revisited. A completed reconciliation is therefore insufficient to validate an index across a host-representation change. Explicit clear/reindex rebuilds correctly, but its availability does not prove migration invokes it.
Queued reduction / multipart identity: use the real V1 tagger to persist two authored user fragments as separate tags and queue a drop only for the first fragment. Native conversion merges them into one V2 user text. The real V2 tagger and pending-operation application reuse the first tag for the merged target, dropping both fragments. Per-fragment original source snapshots survive. The defect is that the old operation's target became broader, not loss of the original stored text.
Attachment: extended-state-repro/, executed at MC 00e7e5c1. It exercises native APIs directly, not full plugin startup. The shortened-index rebuild is a passing manual control, not an additional empty-index bug. Depth/recomp persistence and Historian telemetry are recorded for acceptance coverage; they are not independently proven consumer failures.
Additional acceptance: rebuild or reconcile pre-watermark search coordinates when representation changes, and define safe handling of merged/split message-part tags before replaying old queued reductions. Do not equate a surviving part-like ID with unchanged target content.
2. Dreamer task transport/admission is incomplete
The canonical registry contains twelve tasks. The V2 executor advertises no tool support, and the scheduled/manual selectors filter on that capability:
| Task |
Current V2 admission / missing capability |
classify-memories |
Admitted; zero-tool path |
compress-cues |
Admitted; useful work additionally requires mural.enabled |
map-memories |
Filtered; read-only investigation transport missing |
verify |
Filtered; read-only investigation transport missing |
verify-broad |
Filtered; read-only investigation transport missing |
curate |
Filtered; memory-tool loop missing |
retrospective |
Filtered; search/investigation loop missing |
maintain-docs |
Filtered; file-tool loop missing |
evaluate-smart-notes |
Filtered by requiresTools, although evaluator is described as no-tool; hidden transport also needs wiring |
review-user-memories |
Filtered by requiresTools, although reviewer is JSON/prompt-only; transport needs wiring |
promote-primers |
Filtered by requiresTools, although promotion is host-side DB work |
refresh-primers |
Filtered; read-only investigation transport missing |
Source: features/magic-context/dreamer/task-registry.ts:13–48, v2/hooks/dream-manual.ts:34–58, dreamer/task-executor.ts, v2/hooks/hidden-child.ts.
V2 currently registers only deny-all historian and dreamer-classifier carriers and strips hidden request tools. Additional task capabilities need appropriate permission ownership, not simply a global tools: true switch or a literal copy of every V1 agent name.
The contributor branch already proposes substantial work here (including bc4c93a2, b873a1be, 7cb472be, deed524d, 741c2d32, 17824f95, 7d277a34, ef5b570c). Please reconcile that work rather than reimplement it independently.
Acceptance: account for every task above; execute the runnable tasks on the pinned real host with their intended tool restrictions and continuation behavior. Tool-free and host-only tasks should not require an unrelated tool loop.
3. V2 command entry points are incomplete
The V1 command registry contains seven commands. Current V2 TUI code directly exposes ctx-status, ctx-recomp, and ctx-dream. It does not register the V1 command definitions with the V2 host.
The other four are:
ctx-wrapup
ctx-session-upgrade
ctx-flush
ctx-embed
This is not inherently a missing host API: V2 provides context.command.transform. MC's V2 context does not expose/use that domain, and the V1 config hook is not the V2 registration path.
Source: features/builtin-commands/commands.ts, v2/tui/index.ts, v2/hooks/types.ts; OpenCode core/src/plugin/host.ts:250–254, plugin/src/promise/command.ts, plugin/src/promise/adapter.ts:307–323.
Acceptance: provide V2-native entry points for the required behaviors, or explicitly document deliberate unsupported/replaced behavior. A TUI action alone should not be presented as server/CLI command parity. Some command semantics can still depend on separate host limitations; registering a name alone is not enough.
4. Shared tool transforms accumulate and leak light guidance
The V2 context callback already edits the request's tool descriptions, but also registers a persistent context.tool.transform() on every pass. Native host state retains and replays those registrations.
Reproduction using actual MC context registration and native OpenCode State/hooks/request preparation:
- Setup plus seven context passes leaves eight persistent registrations.
- Clean concurrent light/full requests both get the correct descriptions.
- After the shared baseline has been shortened by a light-preset request, later full-preset requests—including another session—still send light descriptions.
Source: v2/hooks/context.ts:552–565, shared/prompt-surface-runtime.ts; OpenCode core/src/tool.ts and State.
Acceptance: stable registered baseline, per-request model-specific guidance, no registration growth with context passes, and light→full/mixed-session regression coverage. The existing request-local mechanism is the first fix boundary to evaluate.
Attachment: tool-guidance-repro/. It uses a facade for unrelated host services but the real MC callback, native state, and native request preparation. No measured latency/memory regression is claimed.
5. Retired-child cleanup is tied to default service discovery
MC's v2/host-service.ts reads only opencode/service.json. OpenCode supports channel-specific registrations such as service-local.json; standalone hosts may have no registration.
The actual helper was tested with synthetic registrations and intercepted HTTP:
- Local-channel registration only: no discovery; deletion rejects without a request.
- Local and unrelated default registrations: helper selects the default service; its 404 is accepted as success without verifying ownership.
The executor then prunes retirement bookkeeping after successful removal. A 404 is meaningful only from the owning host. Existing settled-error reuse and deferred deletion fixes are present; this is a narrower follow-up to #481/#488.
Acceptance: bind cleanup to the creating host, or retain an explicit retriable limitation when no owner-bound deletion path exists. Do not probe arbitrary registrations and equate any 404 with successful cleanup.
Attachment: repro-host-service.ts / hidden-cleanup-follow-up.md. No actual wrong-server deletion was attempted.
6. Explicit Rust runtime configuration is ignored by the V2 path
transform_mode is a real experimental setting with "ts" as the default. V1 constructs SubcModuleTransport for "rust"; V2 constructs the TypeScript transform and passes rustModeModuleClient: undefined to RPC handlers. Rust recomp therefore reports unavailable.
Source: config/schema/magic-context.ts:1060–1065, V1 src/index.ts:289–317, V2 v2/hooks/context.ts, plugin/rpc-handlers.ts:1484–1490.
Acceptance: honor explicit Rust mode through the V2 owner, or fail/document it as unsupported rather than silently executing another mode. This does not block users of the default TypeScript implementation.
7. Tool-definition measurements / tool-set attribution are absent
V1 records tool-schema measurements through tool.definition. V2 does not populate the equivalent measurements and passes toolSetHash: "" to materialization. The sidebar's local tool-definition breakdown is consequently zero rather than a measured catalog cost.
Source: V1 src/index.ts:870–887; V2 v2/hooks/context.ts:495–497; plugin/rpc-handlers.ts:483–518,581–593.
This is a telemetry/attribution gap. The shared materializer treats tool-set changes as attribution rather than hard-fold triggers; no provider input-budget overflow or mandatory-compaction defect was demonstrated.
Acceptance: measure through the V2 tool surface or explicitly mark this component unavailable instead of displaying zero as if measured.
Existing support and exclusions
The following are present and should not be reported again as missing: current Promise/Effect entry compatibility, ordinary ctx_* tool registration, text-only Historian transport, native fold integration, model-limit/usage handling, mixed-store recognition, harness relabeling, hidden-child retry/settled-error reuse, and the newly merged V1 sidebar component on V2's TUI slot.
Known upstream host differences are documented in packages/plugin/PARITY.md, including MC-initiated compaction constraints, transcript cleanup for model-echoed tags, and the sidebar's hidden-by-default behavior. Native V2 replacements are acceptable; exact V1 internals are not the goal.
Two candidate claims were excluded after checking native ownership:
- Foreign-project event delivery: OpenCode's bus scopes subscriptions through ambient
Location.Service, preserved by the Promise adapter.
- Mandatory cancellation of every task on plugin disposal: no concrete escaped-work/hang reproduction established; intentional draining cannot be called a bug merely because a local abort is absent.
Completion criteria and evidence limits
Use the attached coverage matrix to record each capability as supported, intentionally replaced, unsupported by the host, or still requiring work. Passing a narrow reader fixture is not full migration acceptance, and preserving a SQLite row is not proof that its coordinates retain their meaning.
Real-host acceptance still needs an isolated old-state startup/import → resumed conversation → compaction/restart/cleanup lifecycle, plus task-specific provider/tool-loop checks. The provider-free fixtures establish the listed behaviors without risking a user's live databases. No finite source audit proves that no other bugs exist.
What happened?
This consolidates V2-specific findings against current source. It separates reproducible defects, missing V2 capabilities, and known host differences. It is not a request to transplant V1 internals or to fix unrelated MC bugs.
Related: #488 (V2 umbrella), #489 / #477 (store recognition), #481 (hidden-session lifecycle). Their already-merged fixes are accounted for below.
Revisions and test scope
00e7e5c17913ae252430eff56ac441adbd3f7bc2.58fcad77a8a2e4abcbe985c395e7192801003857(2.0.11 lineage).e35736c7d19b48781aa75b16da30a599bcd3428d; subsequent changes through00e7e5c1do not alter those paths (TUI sidebar, parity documentation, Cargo lockfile).blasphemy/magic-context:v2-fixes-updatesat31634ea3. Proposed implementations there are distinguished from merged support; its full host behavior was not independently accepted.Tests use isolated source checkouts and synthetic SQLite data. No live migration, installed configuration changes, or provider calls were used. Reproducers and the detailed coverage matrix accompany this issue.
Findings at a glance
1. Existing compartment boundaries drift after native conversion
The importer can split synthetic content into a separate row or replace a completed compaction pair with a native compaction record. MC's canonical conversational ordinals therefore change even when endpoint message IDs survive.
The reproducible cases derive the old coordinates through MC's actual V1 reader, persist ordinary compartment rows, run OpenCode's native projection, and read through MC's actual V2 reader:
a2moves from ordinal 4 to 5. The saved end remains 4.ctx_expandrange recovery omits a2 and treats ordinal 5 as live tail. Directmessage: 5recovery succeeds.a2moves from 5 to 4. The saved end remains 5. Range recovery includesu3, which was outside the saved compartment.The mismatch persists after reopening the fixture. This demonstrates incorrect range selection, not deletion of source text.
Relevant source: MC
hooks/magic-context/read-session-raw.ts,v2/hooks/store.ts,features/magic-context/compartment-storage.ts,tools/ctx-expand/tools.ts; OpenCodecore/src/database/v1-migration.ts.Acceptance: before existing MC state is consumed against V2 history, preserve the relationship between saved endpoint IDs and canonical ordinals; handle removed endpoints explicitly and make normalization restart-safe. Equivalent hand-authored V1/V2 fixtures are not sufficient coverage.
Other coordinate-bearing state must be checked as part of the same transition: search source/FTS ordinals and watermarks, protected-tail floors, compression depth, note/provenance anchors, compartment-chunk ranges, and persisted recomp staging. Merely having a callable reset/rebase helper does not establish that migration invokes it. These are acceptance cases, not independently asserted corruptions.
Attachment:
repro/andmigration-issue.mdcontain the complete reproduction and scope limits.Additional existing-state consequences, reproduced separately
Search index: seed the entire six-message V1 index before conversion. After a synthetic split produces seven canonical V2 messages, the real reconciliation scheduler advances its watermark to 7 and clears the dirty floor, but keeps
a2indexed at its old ordinal 4 instead of 5 and never inserts the new synthetic row at 4. Existing entries before the old watermark were not revisited. A completed reconciliation is therefore insufficient to validate an index across a host-representation change. Explicit clear/reindex rebuilds correctly, but its availability does not prove migration invokes it.Queued reduction / multipart identity: use the real V1 tagger to persist two authored user fragments as separate tags and queue a drop only for the first fragment. Native conversion merges them into one V2 user text. The real V2 tagger and pending-operation application reuse the first tag for the merged target, dropping both fragments. Per-fragment original source snapshots survive. The defect is that the old operation's target became broader, not loss of the original stored text.
Attachment:
extended-state-repro/, executed at MC00e7e5c1. It exercises native APIs directly, not full plugin startup. The shortened-index rebuild is a passing manual control, not an additional empty-index bug. Depth/recomp persistence and Historian telemetry are recorded for acceptance coverage; they are not independently proven consumer failures.Additional acceptance: rebuild or reconcile pre-watermark search coordinates when representation changes, and define safe handling of merged/split message-part tags before replaying old queued reductions. Do not equate a surviving part-like ID with unchanged target content.
2. Dreamer task transport/admission is incomplete
The canonical registry contains twelve tasks. The V2 executor advertises no tool support, and the scheduled/manual selectors filter on that capability:
classify-memoriescompress-cuesmural.enabledmap-memoriesverifyverify-broadcurateretrospectivemaintain-docsevaluate-smart-notesrequiresTools, although evaluator is described as no-tool; hidden transport also needs wiringreview-user-memoriesrequiresTools, although reviewer is JSON/prompt-only; transport needs wiringpromote-primersrequiresTools, although promotion is host-side DB workrefresh-primersSource:
features/magic-context/dreamer/task-registry.ts:13–48,v2/hooks/dream-manual.ts:34–58,dreamer/task-executor.ts,v2/hooks/hidden-child.ts.V2 currently registers only deny-all
historiananddreamer-classifiercarriers and strips hidden request tools. Additional task capabilities need appropriate permission ownership, not simply a globaltools: trueswitch or a literal copy of every V1 agent name.The contributor branch already proposes substantial work here (including
bc4c93a2,b873a1be,7cb472be,deed524d,741c2d32,17824f95,7d277a34,ef5b570c). Please reconcile that work rather than reimplement it independently.Acceptance: account for every task above; execute the runnable tasks on the pinned real host with their intended tool restrictions and continuation behavior. Tool-free and host-only tasks should not require an unrelated tool loop.
3. V2 command entry points are incomplete
The V1 command registry contains seven commands. Current V2 TUI code directly exposes
ctx-status,ctx-recomp, andctx-dream. It does not register the V1 command definitions with the V2 host.The other four are:
ctx-wrapupctx-session-upgradectx-flushctx-embedThis is not inherently a missing host API: V2 provides
context.command.transform. MC's V2 context does not expose/use that domain, and the V1 config hook is not the V2 registration path.Source:
features/builtin-commands/commands.ts,v2/tui/index.ts,v2/hooks/types.ts; OpenCodecore/src/plugin/host.ts:250–254,plugin/src/promise/command.ts,plugin/src/promise/adapter.ts:307–323.Acceptance: provide V2-native entry points for the required behaviors, or explicitly document deliberate unsupported/replaced behavior. A TUI action alone should not be presented as server/CLI command parity. Some command semantics can still depend on separate host limitations; registering a name alone is not enough.
4. Shared tool transforms accumulate and leak light guidance
The V2 context callback already edits the request's tool descriptions, but also registers a persistent
context.tool.transform()on every pass. Native host state retains and replays those registrations.Reproduction using actual MC context registration and native OpenCode State/hooks/request preparation:
Source:
v2/hooks/context.ts:552–565,shared/prompt-surface-runtime.ts; OpenCodecore/src/tool.tsand State.Acceptance: stable registered baseline, per-request model-specific guidance, no registration growth with context passes, and light→full/mixed-session regression coverage. The existing request-local mechanism is the first fix boundary to evaluate.
Attachment:
tool-guidance-repro/. It uses a facade for unrelated host services but the real MC callback, native state, and native request preparation. No measured latency/memory regression is claimed.5. Retired-child cleanup is tied to default service discovery
MC's
v2/host-service.tsreads onlyopencode/service.json. OpenCode supports channel-specific registrations such asservice-local.json; standalone hosts may have no registration.The actual helper was tested with synthetic registrations and intercepted HTTP:
The executor then prunes retirement bookkeeping after successful removal. A 404 is meaningful only from the owning host. Existing settled-error reuse and deferred deletion fixes are present; this is a narrower follow-up to #481/#488.
Acceptance: bind cleanup to the creating host, or retain an explicit retriable limitation when no owner-bound deletion path exists. Do not probe arbitrary registrations and equate any 404 with successful cleanup.
Attachment:
repro-host-service.ts/hidden-cleanup-follow-up.md. No actual wrong-server deletion was attempted.6. Explicit Rust runtime configuration is ignored by the V2 path
transform_modeis a real experimental setting with"ts"as the default. V1 constructsSubcModuleTransportfor"rust"; V2 constructs the TypeScript transform and passesrustModeModuleClient: undefinedto RPC handlers. Rust recomp therefore reports unavailable.Source:
config/schema/magic-context.ts:1060–1065, V1src/index.ts:289–317, V2v2/hooks/context.ts,plugin/rpc-handlers.ts:1484–1490.Acceptance: honor explicit Rust mode through the V2 owner, or fail/document it as unsupported rather than silently executing another mode. This does not block users of the default TypeScript implementation.
7. Tool-definition measurements / tool-set attribution are absent
V1 records tool-schema measurements through
tool.definition. V2 does not populate the equivalent measurements and passestoolSetHash: ""to materialization. The sidebar's local tool-definition breakdown is consequently zero rather than a measured catalog cost.Source: V1
src/index.ts:870–887; V2v2/hooks/context.ts:495–497;plugin/rpc-handlers.ts:483–518,581–593.This is a telemetry/attribution gap. The shared materializer treats tool-set changes as attribution rather than hard-fold triggers; no provider input-budget overflow or mandatory-compaction defect was demonstrated.
Acceptance: measure through the V2 tool surface or explicitly mark this component unavailable instead of displaying zero as if measured.
Existing support and exclusions
The following are present and should not be reported again as missing: current Promise/Effect entry compatibility, ordinary
ctx_*tool registration, text-only Historian transport, native fold integration, model-limit/usage handling, mixed-store recognition, harness relabeling, hidden-child retry/settled-error reuse, and the newly merged V1 sidebar component on V2's TUI slot.Known upstream host differences are documented in
packages/plugin/PARITY.md, including MC-initiated compaction constraints, transcript cleanup for model-echoed tags, and the sidebar's hidden-by-default behavior. Native V2 replacements are acceptable; exact V1 internals are not the goal.Two candidate claims were excluded after checking native ownership:
Location.Service, preserved by the Promise adapter.Completion criteria and evidence limits
Use the attached coverage matrix to record each capability as supported, intentionally replaced, unsupported by the host, or still requiring work. Passing a narrow reader fixture is not full migration acceptance, and preserving a SQLite row is not proof that its coordinates retain their meaning.
Real-host acceptance still needs an isolated old-state startup/import → resumed conversation → compaction/restart/cleanup lifecycle, plus task-specific provider/tool-loop checks. The provider-free fixtures establish the listed behaviors without risking a user's live databases. No finite source audit proves that no other bugs exist.