refactor(memory_sync): generic Composio sync orchestrator + convert Notion (Refs #3333) (#3852)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
sanil-23
2026-06-21 13:25:22 -07:00
committed by GitHub
co-authored by Claude
parent b9d2cdd735
commit 7758148c2c
6 changed files with 1570 additions and 754 deletions
@@ -1102,6 +1102,87 @@ async fn notion_sync_max_items_caps_ingest_to_exact_count() {
server.abort();
}
// ─────────────────────────────────────────────────────────────────────────
// Notion sync_depth_days enforcement (via the shared orchestrator)
//
// Proves the generic orchestrator's depth window actually drops items older
// than the floor end-to-end through the real Notion provider. The mock returns
// 2 recent pages (far-future `last_edited_time`, always inside the window) and
// 3 ancient pages (year-2000, always outside it), in the descending order the
// provider requests. With sync_depth_days=7 only the 2 recent pages persist —
// the orchestrator truncates the page at the first item below the floor.
// ─────────────────────────────────────────────────────────────────────────
/// Build `recent` + `old` Notion pages in descending `last_edited_time` order.
/// Recent pages use a far-future timestamp (always within any depth window);
/// old pages use a year-2000 timestamp (always outside it).
fn notion_depth_pages(recent: usize, old: usize) -> Vec<Value> {
let mut pages = Vec::new();
for i in 0..recent {
pages.push(json!({
"id": format!("notion-recent-{i:04}"),
"object": "page",
"last_edited_time": format!("2099-12-{:02}T10:00:00.000Z", 28 - i),
"properties": { "Name": { "type": "title", "title": [{ "plain_text": format!("Recent {i}") }] } }
}));
}
for i in 0..old {
pages.push(json!({
"id": format!("notion-old-{i:04}"),
"object": "page",
"last_edited_time": format!("2000-01-{:02}T10:00:00.000Z", 3 - i),
"properties": { "Name": { "type": "title", "title": [{ "plain_text": format!("Old {i}") }] } }
}));
}
pages
}
#[tokio::test]
async fn notion_sync_depth_days_filters_old_pages() {
let _guard = env_lock();
let tmp = TempDir::new().expect("tempdir");
let _workspace = EnvGuard::set_path("OPENHUMAN_WORKSPACE", tmp.path());
let _home = EnvGuard::set_path("HOME", tmp.path());
let _backend = EnvGuard::unset("BACKEND_URL");
// One page: 2 recent + 3 ancient. With a 7-day window only the 2 recent
// pages must be ingested.
let requests: Arc<Mutex<Vec<Value>>> = Arc::new(Mutex::new(Vec::new()));
let (base, server) = loopback_router(notion_cap_router(
notion_depth_pages(2, 3),
Arc::clone(&requests),
))
.await;
let mut config = config_in(&tmp);
config.api_url = Some(base);
persist_config(&config).await;
store_session(&config);
memory_global::init(config.workspace_dir.clone()).expect("init global memory");
let ctx = ProviderContext {
config: Arc::new(config),
toolkit: "notion".to_string(),
connection_id: Some("conn-notion-depth".to_string()),
usage: Default::default(),
max_items: None,
// 7-day window: drops the year-2000 pages, keeps the far-future ones.
sync_depth_days: Some(7),
};
let outcome = NotionProvider::new()
.sync(&ctx, SyncReason::ConnectionCreated)
.await
.expect("notion depth sync");
assert_eq!(
outcome.items_ingested, 2,
"sync_depth_days=7 must drop the 3 year-2000 pages and keep the 2 recent ones"
);
server.abort();
}
// ─────────────────────────────────────────────────────────────────────────
// Linear cap enforcement
//