Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions STRUCTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ Unless specified otherwise, TypeScript paths are relative to `packages/plugin/`
- `src/hooks/magic-context/compaction-off-transition.ts`: Reconcile per-session compaction mode records and process off/on mode transitions.
- `src/hooks/magic-context/child-session-spawn.ts`: Enforce child session spawn choke point with schema fence validation.
- `src/shared/escalation-bands.ts`: Derive context limit escalation bands and threshold bounds.
- `src/features/magic-context/migrations.ts`: Versioned schema migrations v1–v78 (`LATEST_SUPPORTED_VERSION` in `storage-db.ts` must track the highest; `schema-version-fence.test.ts` asserts they stay in lockstep).
- `src/features/magic-context/migrations.ts`: Versioned schema migrations v1–v79 (`LATEST_SUPPORTED_VERSION` in `storage-db.ts` must track the highest; `schema-version-fence.test.ts` asserts they stay in lockstep). v79 adds content-bound memory episode evidence.
- `src/features/magic-context/message-index.ts`: FTS-backed raw-message index for `ctx_search`.
- `src/features/magic-context/search.ts`: Unified retrieval over memories, raw messages, git commits, and session/smart notes.
- `src/features/magic-context/session-project-storage.ts`: Persist session-to-project bindings and repair mis-scoped compartment chunk embeddings.
Expand All @@ -200,7 +200,7 @@ Unless specified otherwise, TypeScript paths are relative to `packages/plugin/`
- `crates/mc-module/src/session_resolver.rs`: Resolves incoming MCP facade requests to their backing project and session.
- `crates/mc-module/src/lib.rs`: Route subc client requests, implement MCP tool facade routing (supporting `agent_drops.append` queue drops with server-side range parsing and command-id idempotency checks), serve prompt guidance, manage durable pass tracing for transform passes, orchestrate `session.status`, `session.wrapup`, and `session.delete` operations (utilizing structured status fields, machine-readable dispositions, and process-local per-session latches under a `MAX_WRAPUP_REQUEST_BUDGET` deadline, with `session.delete` atomically removing session-owned rows from SQLite tables), track transform dispatch health metrics and heartbeat reporting, manage LRU-bounded `InFlight` snapshot caching, and coordinate bootstrap state imports using `StateImportCoordinator`.
- `crates/mc-module/src/historian_producer.rs`: Implement the Rust subc historian producer client using the wire v2 protocol with `OpenedRoute` targeting (channel and epoch routing).
- `crates/mc-store/src/lib.rs`: Define durable session schemas and migrations (including the `mc_reduce_command_ledger` table in migration 16 for idempotency, `mc_project_mural_artifacts` in migration 49 for project mural artifacts, and `raw_messages_deflate` in migration 50 on `mc_chunk_transcripts` for durable `ctx_expand` recovery), handle metadata, and run CAS transitions.
- `crates/mc-store/src/lib.rs`: Define durable session schemas and migrations (including the `mc_reduce_command_ledger` table in migration 16 for idempotency, `mc_project_mural_artifacts` in migration 49 for project mural artifacts, `raw_messages_deflate` in migration 50 on `mc_chunk_transcripts` for durable `ctx_expand` recovery, and content-bound memory evidence in migration 51), handle metadata, and run CAS transitions.
- `crates/mc-module/src/codec/`: Decode harness-specific JSON messages (OpenCode, Pi) into canonical `CkIngressMessage` values and encode them back using harness model codecs.
- `crates/mc-module/src/caveman.rs`: Age-tier caveman text compression ported to Rust.
- `crates/mc-module/src/divergence.rs`: Per-pass transform output divergence tracking and attribution.
Expand Down
65 changes: 64 additions & 1 deletion crates/mc-module/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ use mc_store::TagNumberRow;
use mc_store::{
canonical_root, validate_state_import_compartments, AuthoritySeedRow, DeferredExecuteState,
FacadeMutationOutcome, HistorianPhase, InsertMemoryInput, MappingUpdate, McStore, McStoreError,
ModuleDropSeedRow, ModuleMemoryMutationRow, ModuleMemoryRow, ModuleStateSyncError,
ModuleDropSeedRow, ModuleMemoryEvidenceRow, ModuleMemoryMutationRow, ModuleMemoryRow,
ModuleStateSyncError,
ModuleStateSyncRequest, ModuleStripSeedRow, ModuleWorkspaceMemberRow, ModuleWorkspaceRow,
NoteCasOutcome, NoteEvaluationInput, NoteInput, NoteNudgeAnchorSeed, NoteWriteInput,
PendingAgentDrop, PendingAgentDropSeedRow, PendingCompactionMarkerState,
Expand Down Expand Up @@ -1697,6 +1698,18 @@ struct ModuleMemoryWire {
mural_cue_at: Option<i64>,
#[serde(default)]
mural_cue_rejection_count: i64,
#[serde(default)]
evidence: Vec<ModuleMemoryEvidenceWire>,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When a state-sync memory contains evidence: null, this field becomes None, so into_row treats it as omitted and preserves stale evidence instead of rejecting the malformed snapshot. Reject explicit null while accepting only an omitted field or an array, matching the cross-runtime contract.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/mc-module/src/lib.rs, line 1702:

<comment>When a state-sync memory contains `evidence: null`, this field becomes `None`, so `into_row` treats it as omitted and preserves stale evidence instead of rejecting the malformed snapshot. Reject explicit `null` while accepting only an omitted field or an array, matching the cross-runtime contract.</comment>

<file context>
@@ -1699,7 +1699,7 @@ struct ModuleMemoryWire {
     mural_cue_rejection_count: i64,
     #[serde(default)]
-    evidence: Vec<ModuleMemoryEvidenceWire>,
+    evidence: Option<Vec<ModuleMemoryEvidenceWire>>,
 }
 
</file context>

}

#[derive(Debug, Clone, Deserialize)]
struct ModuleMemoryEvidenceWire {
content_hash: String,
source_session_id: String,
#[serde(default)]
source_message_id: Option<String>,
source_type: String,
observed_at: i64,
}

#[derive(Debug, Clone, Deserialize)]
Expand Down Expand Up @@ -1804,6 +1817,17 @@ impl ModuleMemoryWire {
mural_cue_hash: self.mural_cue_hash,
mural_cue_at: self.mural_cue_at,
mural_cue_rejection_count: self.mural_cue_rejection_count,
evidence: self
.evidence
.into_iter()
.map(|row| ModuleMemoryEvidenceRow {
content_hash: row.content_hash,
source_session_id: row.source_session_id,
source_message_id: row.source_message_id,
source_type: row.source_type,
observed_at: row.observed_at,
})
.collect(),
}
}
}
Expand Down Expand Up @@ -10423,6 +10447,7 @@ impl McHandler {
category,
content,
source_session_id: Some(conversation_key),
source_message_id: None,
source_type: Some("agent"),
importance: Some(50),
expires_at: None,
Expand Down Expand Up @@ -10464,6 +10489,24 @@ impl McHandler {
.update_memory_content(memory_project, id, content, now_ms())
.map_err(|error| error.to_string())?
.ok_or_else(|| format!("memory {id} was not found"))?;
tx.record_memory_evidence(
memory.id,
InsertMemoryInput {
project_path: memory_project,
route_project_root: Some(
facade_scope.route_project_root.as_str(),
),
category: &memory.category,
content,
source_session_id: Some(conversation_key),
source_message_id: None,
source_type: Some("agent"),
importance: memory.importance,
expires_at: memory.expires_at,
metadata_json: memory.metadata_json.as_deref(),
now_ms: now_ms(),
},
)?;
facade_text_response(
format!(
"Updated memory [ID: {}] in {}.",
Expand Down Expand Up @@ -10545,6 +10588,24 @@ impl McHandler {
)
.map_err(|error| error.to_string())?
.ok_or_else(|| format!("memory {target_id} was not found"))?;
tx.record_memory_evidence(
memory.id,
InsertMemoryInput {
project_path: memory_project,
route_project_root: Some(
facade_scope.route_project_root.as_str(),
),
category: &memory.category,
content,
source_session_id: Some(conversation_key),
source_message_id: None,
source_type: Some("agent"),
importance: memory.importance,
expires_at: memory.expires_at,
metadata_json: memory.metadata_json.as_deref(),
now_ms: now_ms(),
},
)?;
facade_text_response(
format!(
"Merged memories into [ID: {}] in {}; superseded [{}].",
Expand Down Expand Up @@ -16700,6 +16761,7 @@ mod tests {
category,
content,
source_session_id: Some(project),
source_message_id: None,
source_type: Some("test"),
importance: Some(50),
expires_at: None,
Expand Down Expand Up @@ -22330,6 +22392,7 @@ mod tests {
.any(|memory| memory.content == "second shared fact"));
let first = store.get_memory_full(project_rows[0].id).unwrap().unwrap();
assert_eq!(first.source_session_id.as_deref(), Some(key_a));
assert_eq!(first.source_type.as_deref(), Some("agent"));
assert!(store
.load_active_memories(key_a, now_ms())
.unwrap()
Expand Down
1 change: 1 addition & 0 deletions crates/mc-module/src/m0_compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,7 @@ mod tests {
category: "CONSTRAINTS",
content: "must stay hidden",
source_session_id: None,
source_message_id: None,
source_type: Some("agent"),
importance: Some(50),
expires_at: None,
Expand Down
1 change: 1 addition & 0 deletions crates/mc-module/src/m1_compose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ mod tests {
category,
content,
source_session_id: None,
source_message_id: None,
source_type: Some("tool"),
importance: Some(70),
expires_at: None,
Expand Down
1 change: 1 addition & 0 deletions crates/mc-module/src/memory_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ mod tests {
category,
content,
source_session_id: None,
source_message_id: None,
source_type: Some("tool"),
importance: Some(50),
expires_at: None,
Expand Down
1 change: 1 addition & 0 deletions crates/mc-module/src/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13984,6 +13984,7 @@ pub(crate) mod tests {
category,
content,
source_session_id: None,
source_message_id: None,
source_type: Some("tool"),
importance: Some(70),
expires_at: None,
Expand Down
Loading
Loading