Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ async-trait = "0.1"
# tinycortex's major — which `links = "git2"` turns into a hard cargo error
# rather than a warning.
# `store/factories.rs` exposes a tiny health router for the embedded provider.
axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio", "query", "ws", "macros"] }
chrono = { version = "0.4", features = ["serde"] }
# `tinycortex/persona.rs` resolves the user's home directory for the obsidian
# vault default.
Expand All @@ -55,7 +54,6 @@ parking_lot = "0.12"
rand = "0.8"
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] }
tracing = "0.1"
regex = "1.10"
rusqlite = { version = "=0.40.0", features = ["bundled"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand All @@ -74,6 +72,12 @@ tinymemory-api = { path = "../api", features = ["test-support"] }
# hold this crate's own store to the same contract the adapters are held to.
# No cycle — `tinymemory-conformance` depends on `tinymemory-api` alone.
tinymemory-conformance = { path = "../conformance" }
# Test-only. `store::factories`' tests stand up a throwaway HTTP server to
# exercise the embedder's failure paths — the four `axum` references in this
# crate are all inside `mod tests`. It was declared as a normal dependency,
# which put a web framework in the normal graph of every build linking this
# crate (#18 §D2).
axum = { version = "0.8", default-features = false, features = ["http1", "json", "tokio", "query", "ws", "macros"] }
tempfile = "3"
tokio = { version = "1", features = ["test-util"] }

Expand Down
11 changes: 10 additions & 1 deletion core/src/engine/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ use crate::sources::{MemorySourceEntry, SourceKind};
use crate::store::MemoryClientRef;
use crate::Config;

pub const HOST_SYNC_STATE_NAMESPACE: &str = "composio-sync-state";
/// The KV namespace Composio sync state is persisted under.
///
/// Re-exported from the engine rather than re-declared. It was a second
/// `const` holding the same literal as
/// `tinycortex::memory::sync::state::STATE_NAMESPACE`, so the host and the
/// engine agreed only by coincidence of the string: change either and the two
/// would silently read and write *different* namespaces, stranding every
/// persisted sync cursor with no error anywhere. A duplicated literal is a
/// drift hazard precisely when the thing it names is durable (#18 §B2).
pub use tinycortex::memory::sync::state::STATE_NAMESPACE as HOST_SYNC_STATE_NAMESPACE;
pub use tinycortex::memory::sync::{
RawCoverage, RawFileRef, RealCostAccumulator, RebuildOutcome, SyncAuditEntry,
};
Expand Down
22 changes: 22 additions & 0 deletions core/src/sync/composio/providers/sync_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,25 @@ pub fn extract_item_id(item: &serde_json::Value, paths: &[&str]) -> Option<Strin
.map(str::to_owned)
})
}

#[cfg(test)]
mod tests {
/// The namespace is durable, so changing it is a data migration.
///
/// `KV_NAMESPACE` now re-exports the engine's constant, which makes host
/// and engine agree by construction — they previously agreed only because
/// two separate `const`s happened to hold the same literal. This pins the
/// *value* as well: every persisted Composio sync cursor lives under this
/// string, so a change upstream silently strands all of them. Failing here
/// turns that into a deliberate decision with a migration attached rather
/// than a quiet loss discovered when a sync re-runs from the beginning.
#[test]
fn the_state_namespace_is_pinned() {
assert_eq!(
super::KV_NAMESPACE,
"composio-sync-state",
"the Composio sync-state KV namespace changed; every persisted \
cursor is stored under the old value and needs migrating"
);
}
}
Loading