Skip to content

Commit 7286090

Browse files
committed
Merge commit 'af0b120d7a180920e7f46e6ca49177db4cd9731d'
# Conflicts: # ARCHITECTURE.md # STRUCTURE.md # crates/mc-module/src/historian.rs # crates/mc-module/src/lib.rs # crates/mc-module/src/selection.rs # crates/mc-module/src/transform.rs # crates/mc-store/src/lib.rs # packages/dashboard/src/components/shared/CacheTimeline.tsx # packages/plugin/scripts/bench-synapse-vs-local.ts # packages/plugin/scripts/clone-session.test.ts # packages/plugin/scripts/clone-session.ts # packages/plugin/scripts/test-synapse-embed.ts # packages/plugin/src/config/transform-mode.test.ts # packages/plugin/src/config/transform-mode.ts # packages/plugin/src/features/magic-context/memory/embedding-synapse.test.ts # packages/plugin/src/features/magic-context/memory/embedding-synapse.ts # packages/plugin/src/features/magic-context/migrations-v53.test.ts # packages/plugin/src/features/magic-context/project-embedding-registry.test.ts # packages/plugin/src/hooks/magic-context/compaction-marker-manager.ts # packages/plugin/src/hooks/magic-context/rust-mode-transform.test.ts # packages/plugin/src/hooks/magic-context/rust-mode-transform.ts # packages/plugin/src/hooks/magic-context/shadow-sender.test.ts # packages/plugin/src/hooks/magic-context/shadow-sender.ts # packages/plugin/src/hooks/magic-context/tag-messages.ts # packages/plugin/src/hooks/magic-context/transform-postprocess-phase.test.ts # packages/plugin/src/hooks/magic-context/transform-postprocess-phase.ts # packages/plugin/src/hooks/magic-context/transform.ts # packages/plugin/src/plugin/rpc-handlers.test.ts # packages/plugin/src/plugin/rpc-handlers.ts # packages/plugin/src/plugin/tool-registry.ts
2 parents c7568d1 + af0b120 commit 7286090

57 files changed

Lines changed: 3557 additions & 518 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.alfonso/release-notes/v0.32.3.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# v0.32.3
2+
3+
Patch release focused on prompt-cache cost around history compaction boundaries.
4+
5+
## Cache stability
6+
7+
- Fixed a double cache bust that occurred when the compaction boundary advanced on large sessions: the pass that moved the boundary and the following pass could serve different renderings of the summary marker, paying an avoidable full-prefix re-read (typically 100K+ tokens) on every boundary move. The marker representation is now reconciled deterministically on every pass, so a boundary move costs exactly one bust.
8+
- Marker rows are now written with deterministic identifiers, making retries after interrupted writes converge on the same rows instead of duplicating them.
9+
- Concurrent processes sharing a session (for example a TUI attached alongside a running server) now serve identical marker renderings instead of briefly diverging.
10+
11+
## Fixes
12+
13+
- The synthetic history head is identified structurally rather than by metadata, preventing mispositioned summary markers next to system-delivered notices.
14+
- Sessions without a frozen ctx_reduce availability verdict no longer render a tagged summary marker that could change once the verdict settles.

ARCHITECTURE.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ Magic Context is an `@opencode-ai/plugin` (entry `src/index.ts`) that rewrites t
1313
- **Runtime SQLite backend** (`src/shared/sqlite.ts`): `bun:sqlite` under Bun, `node:sqlite` (`DatabaseSync`) under Node (Pi) and Electron (Desktop). The non-Bun branch adds a savepoint-aware `transaction()` shim and `readonly``readOnly` mapping; otherwise identical. No native module, no prebuild.
1414
- **Pi parity:** `packages/pi-plugin/` mirrors OpenCode semantics, importing shared core from `@magic-context/core`. Intentional divergences are tracked in `packages/pi-plugin/PARITY.md`. Provider prefixes are translated between canonical (OpenCode) and Pi configuration models via `src/shared/harness-provider-map.ts` at configuration read/write edges to keep shared model configurations portable. Pi implements session state inheritance on branch clone forks by copying filtered tags, compartments, and pending marker states, whereas OpenCode `/fork` does not yet inherit context state.
1515
- **Rust module / subc integration.** A harness-agnostic Rust workspace in `crates/` re-implements the cache-stability transform and autonomous historian to run under the subconscious daemon (`subc`), communicating via the `@cortexkit/subc-client` library on the TypeScript side and wire v2 protocols on the Rust side.
16+
- **Experimental Rust runtime mode.** Gated by `transform_mode: "rust"`, routes the entire Magic Context transform pipeline for a project through the ck-mc Rust module over subc. The TypeScript layer serves as a coordinator that manages state sync, ordinal tracking, and Last Known Good (LKG) fallbacks.
1617

1718
## Layers
1819

19-
- **Bootstrap** (`src/index.ts`): load config, register hidden agents + hooks + tools, start RPC server, dream-timer, auto-update checker; detect conflicting plugins (DCP / OMO / OpenCode auto-compaction) and disable the runtime if any is active.
20-
- **Adapters** (`src/plugin/`): hook wrappers, tool registry, RPC handlers, dream-timer lifecycle, per-session hook construction.
21-
- **Runtime** (`src/hooks/magic-context/`): the transform pipeline, postprocess phase, event/command handlers, system-prompt injection, compartment runners, decay rendering, strip-and-replay, nudges, m[0]/m[1] injection, and the shadow-transform sender (a flag-gated dev lane that mirrors transform passes to the Rust subc module using the `@cortexkit/subc-client` library, paging large cold-start state_sync seeds into batches under 512KiB to stay under transport limits).
20+
- **Bootstrap** (`src/index.ts`): load config, register hidden agents + hooks + tools, start RPC server, dream-timer, auto-update checker; detect conflicting plugins (DCP / OMO / OpenCode auto-compaction) and disable the runtime if any is active. Begins the boot quiet period (`packages/plugin/src/plugin/boot-quiet.ts`) to defer background maintenance, and runs asynchronous startup database opens and schema migration retries (`openDatabaseAsync`).
21+
- **Adapters** (`src/plugin/`): hook wrappers, tool registry, RPC handlers, dream-timer lifecycle, per-session hook construction, and the `rustToolBackends` tool-routing layer when running in Rust mode.
22+
- **Runtime** (`src/hooks/magic-context/`): the transform pipeline, postprocess phase, event/command handlers, system-prompt injection, compartment runners, decay rendering, strip-and-replay, nudges, m[0]/m[1] injection, and the shadow-transform sender (a flag-gated dev lane that mirrors transform passes to the Rust subc module using the `@cortexkit/subc-client` library, paging large cold-start state_sync seeds into batches under 512KiB to stay under transport limits). When `transform_mode` is set to `"rust"`, delegates execution to `rust-mode-transform.ts` which synchronizes database state via `module-state-sync.ts`, maps message ordinals via `module-wire.ts`, and falls back to LKG (Last Known Good) transform state replays via `lkg-slot.ts` and `lkg-replay.ts` on failures.
2223
- **Feature services** (`src/features/magic-context/`): storage, scheduler, tagger, memory, dreamer, sidekick, git-commit + message FTS indexes, unified search, overflow detection, session-project mapping and backfill, migrations, clone-state copy helpers (`src/features/magic-context/storage-clone.ts`), project identity resolution (resolves `git:<sha>` or fallback `dir:<md5-12>` identifiers, caching directory fallbacks, and utilizing a cooldown period for transient git errors).
2324
- **Tools** (`src/tools/`): `ctx_reduce`, `ctx_expand`, `ctx_note`, `ctx_memory`, `ctx_search`. Gating: when `memory.enabled` is false, `ctx_memory` is not registered (on Pi, it registers but refuses queries for memory-off projects), and all memory-related guidance is stripped from the system prompt.
2425
- **Config + shared** (`src/config/`, `src/shared/`): Zod config (deep-merge raw JSONC before validation; invalid leaves fall back to defaults with warnings, never disable the plugin). **Project-tier trust boundaries** (`src/config/project-security.ts`) strip unsafe fields from untrusted repository configs before merge — preventing escalation via `sqlite` PRAGMAs, hidden-agent reprogramming (`prompt`, `tools`), `embedding` destinations, or developer-only shadow transform settings. Project-level compaction thresholds are raise-only to prevent cloned repos from forcing extra historian cost. Also includes logger, data paths, SQLite selector, harness id, RPC transport, conflict detector, tag-transcript primitive (shared with Pi), provider-id translation map (`src/shared/harness-provider-map.ts`), and exit-abort listener coordinator (`src/shared/exit-abort-registry.ts`).
@@ -143,7 +144,7 @@ Background maintenance (V2: per-task cron scheduling). A process-wide 15-min tim
143144

144145
## Storage & migrations
145146

146-
`storage-db.ts` creates the schema and runs versioned migrations (`migrations.ts`, currently v1–v52). `LATEST_SUPPORTED_VERSION` is a schema fence — it MUST be bumped with every new migration (a unit test asserts it equals the highest migration), and a stale value makes the DB refuse to open after the migration applies. Schema helpers `ensureColumn()` + `healAllNullColumns()` (defined in `storage-schema-helpers.ts` to prevent cycles between `storage-db` and `migrations`) backfill upgraded DBs even if a migration row is lost. New session-scoped tables must be added to `clearSession()`. A bulletproof `MAGIC_CONTEXT_TEST_DATA_DIR` guard keeps the test suite off the live DB (running `bun test` once migrated a live DB and fail-closed running binaries). SQLite binds must use SPREAD positional args, never the array form (`bun:sqlite` binds a lone array positionally; `node:sqlite` reads it as named params and throws). For branch forks in Pi, copy durable session state (compartments, tags, pending operations, and session metadata) to the new session via `copySessionStateForClone()` in `src/features/magic-context/storage-clone.ts`. Run this copy inside an immediate SQLite transaction, filtering and mapping message ordinals and tag composite keys to the copied branch entries, and clearing cached cache bytes to trigger fresh rematerialization.
147+
`storage-db.ts` creates the schema and runs versioned migrations (`migrations.ts`, currently v1–v53). `LATEST_SUPPORTED_VERSION` is a schema fence — it MUST be bumped with every new migration (a unit test asserts it equals the highest migration), and a stale value makes the DB refuse to open after the migration applies. Schema helpers `ensureColumn()` + `healAllNullColumns()` (defined in `storage-schema-helpers.ts` to prevent cycles between `storage-db` and `migrations`) backfill upgraded DBs even if a migration row is lost. New session-scoped tables must be added to `clearSession()`. A bulletproof `MAGIC_CONTEXT_TEST_DATA_DIR` guard keeps the test suite off the live DB (running `bun test` once migrated a live DB and fail-closed running binaries). SQLite binds must use SPREAD positional args, never the array form (`bun:sqlite` binds a lone array positionally; `node:sqlite` reads it as named params and throws). For branch forks in Pi, copy durable session state (compartments, tags, pending operations, and session metadata) to the new session via `copySessionStateForClone()` in `src/features/magic-context/storage-clone.ts`. Run this copy inside an immediate SQLite transaction, filtering and mapping message ordinals and tag composite keys to the copied branch entries, and clearing cached cache bytes to trigger fresh rematerialization.
147148

148149
## Session modes
149150

STRUCTURE.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,17 @@ All paths below are relative to `packages/plugin/` — the published OpenCode np
4949
**`src/config/`:**
5050
- Purpose: Parse and validate plugin configuration.
5151
- Contains: Config loaders, re-exports, and Zod schemas.
52-
- Key files: `src/config/index.ts`, `src/config/schema/magic-context.ts`, `src/config/schema/agent-overrides.ts`, `src/config/project-security.ts`
52+
- Key files: `src/config/index.ts`, `src/config/schema/magic-context.ts`, `src/config/schema/agent-overrides.ts`, `src/config/project-security.ts`, `src/config/transform-mode.ts`
5353

5454
**`src/plugin/`:**
5555
- Purpose: Adapt internal services to OpenCode plugin interfaces.
56-
- Contains: Hook wrappers, tool registry setup, RPC handlers, dream-timer lifecycle, conflict-warning delivery, per-session hook construction.
57-
- Key files: `src/plugin/messages-transform.ts`, `src/plugin/event.ts`, `src/plugin/tool-registry.ts`, `src/plugin/hooks/create-session-hooks.ts`, `src/plugin/rpc-handlers.ts`, `src/plugin/dream-timer.ts`, `src/plugin/conflict-warning-hook.ts`
56+
- Contains: Hook wrappers, tool registry setup, RPC handlers, dream-timer lifecycle, conflict-warning delivery, per-session hook construction, boot quiet period enforcement, and tool backend overrides for Rust mode.
57+
- Key files: `src/plugin/messages-transform.ts`, `src/plugin/event.ts`, `src/plugin/tool-registry.ts`, `src/plugin/hooks/create-session-hooks.ts`, `src/plugin/rpc-handlers.ts`, `src/plugin/dream-timer.ts`, `src/plugin/conflict-warning-hook.ts`, `src/plugin/boot-quiet.ts`, `src/plugin/rust-tool-backends.ts`
5858

5959
**`src/hooks/`:**
6060
- Purpose: Hold hook implementations and hook-specific helpers.
61-
- Contains: The `magic-context` runtime and the auto-update checker.
62-
- Key files: `src/hooks/magic-context/hook.ts`, `src/hooks/magic-context/transform.ts`, `src/hooks/magic-context/transform-postprocess-phase.ts`, `src/hooks/magic-context/strip-content.ts`, `src/hooks/auto-update-checker/checker.ts`
61+
- Contains: The `magic-context` runtime, the auto-update checker, and the Rust-mode execution adapter.
62+
- Key files: `src/hooks/magic-context/hook.ts`, `src/hooks/magic-context/transform.ts`, `src/hooks/magic-context/transform-postprocess-phase.ts`, `src/hooks/magic-context/strip-content.ts`, `src/hooks/auto-update-checker/checker.ts`, `src/hooks/magic-context/rust-mode-transform.ts`, `src/hooks/magic-context/module-state-sync.ts`, `src/hooks/magic-context/module-wire.ts`
6363

6464
**`src/tui/`:**
6565
- Purpose: Render Magic Context sidebar and `/ctx-status` / `/ctx-recomp` dialogs inside OpenCode's TUI.
@@ -121,6 +121,7 @@ Unless specified otherwise, TypeScript paths are relative to `packages/plugin/`
121121
- `src/config/index.ts`: Load and merge config files with field-level fallback for invalid leaves; collect warnings rather than disable the plugin.
122122
- `src/config/schema/magic-context.ts`: Define defaults and schema rules.
123123
- `src/config/schema/agent-overrides.ts`: Define overridable built-in agents.
124+
- `src/config/transform-mode.ts`: Resolve transform mode (TS vs Rust) based on configuration and system capabilities.
124125
- `assets/magic-context.schema.json`: Generated JSON schema, kept in sync via `scripts/build-schema.ts` and `scripts/release.sh`.
125126

126127
**Core Logic:**
@@ -133,6 +134,14 @@ Unless specified otherwise, TypeScript paths are relative to `packages/plugin/`
133134
- `src/hooks/magic-context/supersession-reclaim.ts`: Select superseded spent control-plane tool outputs (oldest todowrite, ctx_reduce, zero-value meta calls) and older edit/write calls for the same file under the `smart_drops` configuration flag.
134135
- `src/hooks/magic-context/edit-marker.ts`: Implement `edit_marker` mode to compress superseded edits, keeping the `filePath` and a region-hint prefix while dropping the bulky output content.
135136
- `src/hooks/magic-context/shadow-sender.ts`: Mirror finalized transform passes, inputs, and decisions to the Rust module over the subc protocol using the `@cortexkit/subc-client` library (wire v2 protocol via `SubcClient` and `RouteHandle`) under the `shadow_transform` configuration flag. Pages large cold-start state_sync seeds into batches under 512KiB to stay under transport limits.
137+
- `src/hooks/magic-context/rust-mode-transform.ts`: Orchestrate the experimental Rust transform mode, coordinating state sync and LKG (Last Known Good) fallback/replay logic.
138+
- `src/hooks/magic-context/module-state-sync.ts`: Synchronize database state (memories, commits, tags, markers) between host (TS SQLite) and subc (Rust).
139+
- `src/hooks/magic-context/module-wire.ts`: Translate wire messages, ordinals, and normalizations between host and Rust formats.
140+
- `src/hooks/magic-context/lkg-slot.ts` and `src/hooks/magic-context/lkg-replay.ts`: Capture and replay the Last Known Good (LKG) transformed state on failure/parking.
141+
- `src/hooks/magic-context/pass-outcome.ts`: Track the outcome of transform passes.
142+
- `src/hooks/magic-context/emergency-fail-closed.ts`: Handle fail-closed cases under emergency context limit situations.
143+
- `src/plugin/boot-quiet.ts`: Quiet background maintenance logging on startup.
144+
- `src/plugin/rust-tool-backends.ts`: Define overrides for tool backends (`ctx_reduce`, `ctx_memory`) when running in Rust mode.
136145
- `src/hooks/magic-context/inject-compartments.ts`: m[0]/m[1] history layout — `renderM0`/`renderM1`/`materializeM0`/`mustMaterialize` (mirrored in Pi's `inject-compartments-pi.ts`).
137146
- `src/hooks/magic-context/decay-curve.ts`: Council-validated deterministic tier-decay math (half-life, log-cost tier boundaries, budget pressure).
138147
- `src/hooks/magic-context/decay-render.ts`: Shared OpenCode+Pi compartment renderer built on the decay curve (replaces the removed LLM compressor).

crates/mc-module/src/decay_render.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ pub fn extract_m0_block(m0_text: &str, tag: &str) -> Option<String> {
367367
mod tests {
368368
use super::*;
369369
use serde::Deserialize;
370+
use sha2::{Digest, Sha256};
370371

371372
fn comp(
372373
start: i64,
@@ -657,6 +658,130 @@ mod tests {
657658
}
658659
}
659660

661+
#[test]
662+
fn redacted_store_shape_matches_ts_at_real_history_budgets() {
663+
#[derive(Deserialize)]
664+
struct ShapeFixture {
665+
compartments: Vec<RawComp>,
666+
}
667+
#[derive(Deserialize)]
668+
struct DifferentialCase {
669+
budget: f64,
670+
#[serde(rename = "tsCost")]
671+
ts_cost: usize,
672+
#[serde(rename = "tsTierCounts")]
673+
ts_tier_counts: [usize; 5],
674+
#[serde(rename = "bodySha256")]
675+
body_sha256: String,
676+
}
677+
#[derive(Deserialize)]
678+
struct DifferentialFixture {
679+
cases: Vec<DifferentialCase>,
680+
}
681+
682+
let shape: ShapeFixture =
683+
serde_json::from_str(include_str!("../testdata/decay-store-shape.json"))
684+
.expect("parse redacted store shape");
685+
assert_eq!(
686+
shape.compartments.len(),
687+
388,
688+
"fixture must preserve the store shape"
689+
);
690+
let compartments: Vec<DecayRenderCompartment> = shape
691+
.compartments
692+
.iter()
693+
.map(|raw| DecayRenderCompartment {
694+
start_message: raw.start,
695+
end_message: raw.end,
696+
title: raw.title.clone(),
697+
content: raw.content.clone(),
698+
start_date: raw.start_date.clone(),
699+
end_date: raw.end_date.clone(),
700+
p1: raw.p1.clone(),
701+
p2: raw.p2.clone(),
702+
p3: raw.p3.clone(),
703+
p4: raw.p4.clone(),
704+
importance: raw.importance,
705+
legacy: raw.legacy,
706+
})
707+
.collect();
708+
let differential: DifferentialFixture =
709+
serde_json::from_str(include_str!("../testdata/decay-store-differential.json"))
710+
.expect("parse TS differential table");
711+
assert_eq!(differential.cases.len(), 4);
712+
713+
let mut previous_cost = None;
714+
for case in &differential.cases {
715+
let body = render_decayed_compartments(
716+
&compartments,
717+
case.budget,
718+
mc_tokenizer::estimate_tokens,
719+
);
720+
let rust_cost = mc_tokenizer::estimate_tokens(&body);
721+
assert_eq!(
722+
rust_cost, case.ts_cost,
723+
"token cost drift at budget {}",
724+
case.budget
725+
);
726+
assert!(
727+
rust_cost as f64 <= case.budget || body.is_empty(),
728+
"render exceeded budget {} with {} tokens",
729+
case.budget,
730+
rust_cost
731+
);
732+
if let Some(previous) = previous_cost {
733+
assert!(
734+
rust_cost > previous,
735+
"shrinking budget must not grow rendered cost: previous {previous}, current {rust_cost}"
736+
);
737+
}
738+
previous_cost = Some(rust_cost);
739+
740+
let digest = Sha256::digest(body.as_bytes());
741+
let rust_hash = digest
742+
.iter()
743+
.map(|byte| format!("{byte:02x}"))
744+
.collect::<String>();
745+
assert_eq!(
746+
rust_hash, case.body_sha256,
747+
"byte drift at budget {}",
748+
case.budget
749+
);
750+
751+
let sections = if body.is_empty() {
752+
Vec::new()
753+
} else {
754+
body.split("\n\n").collect::<Vec<_>>()
755+
};
756+
let mut tier_counts = [0usize; 5];
757+
for compartment in &compartments {
758+
let heading = format!(
759+
"## {}-{}",
760+
compartment.start_message, compartment.end_message
761+
);
762+
let section = sections
763+
.iter()
764+
.find(|section| section.starts_with(&heading))
765+
.copied();
766+
let mut selected = 5usize;
767+
for tier in 1..=5u8 {
768+
if render_compartment_at_tier(compartment, tier).as_str()
769+
== section.unwrap_or("")
770+
{
771+
selected = tier as usize;
772+
break;
773+
}
774+
}
775+
tier_counts[selected - 1] += 1;
776+
}
777+
assert_eq!(
778+
tier_counts, case.ts_tier_counts,
779+
"tier drift at budget {}",
780+
case.budget
781+
);
782+
}
783+
}
784+
660785
#[test]
661786
fn render_tight_golden_matches_reference_with_real_estimator() {
662787
// The budget GUARD path: these cases use budgets tight enough that the TS

0 commit comments

Comments
 (0)