Skip to content

feat(import): skip connector-synced content in the legacy import - #246

Merged
senamakel merged 2 commits into
mainfrom
legacy-import-skip-external-sync
Oct 9, 2026
Merged

senamakel merged 2 commits into
mainfrom
legacy-import-skip-external-sync

Conversation

@senamakel

@senamakel senamakel commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Summary

Adds LegacyWorkspace::skip_connector_syncs(bool), an opt-in that leaves content synced from Composio connectors (Gmail, Slack, Notion, Linear, GitHub, ClickUp) out of the v1 import. Everything else still migrates: conversations, folder and file memory-source documents, learnings, global, profile, events, lessons, graph and the goals/persona files. The default is off, so current behavior is unchanged.

OpenHuman no longer syncs connectors into memory (#245) and should not carry a user's old connector data into the new engine.

Related issue

None. Follow-up to #245; the OpenHuman host PR turns the option on.

API or behavior changes

New builder method LegacyWorkspace::skip_connector_syncs(self, skip: bool) -> Self. No change unless a caller turns it on. With it on, both counts() and items() skip the same rows, so counts still equal what items() yields, and checkpoints still advance over skipped rows. The rules live in sections/connector.rs, and every one comes from how v1 actually wrote connector data:

Section Skipped when
documents (memory_docs) the resolved logical namespace starts with skill- (v1 SkillDoc Composio sync) or source: (the v1 connector path, stored sanitised as source_…)
chunks source_kind = 'email'; or source_id starts with gmail:, slack:, notion:, linear:, github: or clickup:; or, when owner exists, any chunk's owner LIKE '%-sync:%' ({toolkit}-sync:{conn})
profile facet_id starts with skill- (connector identity facets)
graph a graph_namespace row whose namespace starts with skill-, source: or source_ (graph_global is untouched)

Taint is deliberately not used. v1 also marked the agent's own global notes and flow memory as external_sync, so filtering on taint would drop user data. Folder and file sources (mem_src:*), agent chat (conversations:agent), meetings and vault files are kept.

Validation

  • cargo fmt --all -- --check: pass
  • cargo clippy --workspace --all-targets --all-features -- -D warnings: pass
  • cargo build --all-targets --all-features: covered by the test build
  • cargo test --workspace --all-features: 1259 passed, 0 failed
  • RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps --all-features: pass

Tests

  • tests/legacy_import.rs:
    • connector_syncs_are_imported_unless_skipped
    • skip_connector_syncs_drops_exactly_the_connector_rows: every rule drops its row, the kept counterparts stay (a global row with external_sync taint, a normal facet, graph_global, mem_src:, conversations:agent), and counts() == items().count()
    • skipping_connector_syncs_keeps_resumption_exact: page size 1, resumed from every checkpoint
    • the_owner_rule_needs_the_owner_column
  • Unit tests in sections/connector_tests.rs.

Documentation

src/import/README.md gets a new "Connector syncs" section. It also corrects the old claim that chat chunks are only host-channel transcripts: Composio Slack wrote chat chunks under slack:.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

Summary by CodeRabbit

  • New Features
    • Legacy imports can now optionally skip connector-synced documents, chunks, profile data, and graph rows. By default, imports continue to include all data.
    • Import counts reflect the selected filtering option and remain consistent with the items yielded.

senamakel and others added 2 commits October 9, 2026 01:52
The workspace import logic was reorganised into a sections module with
separate files for graph, memory docs, profile, and connector handling,
plus a dedicated schema module. This keeps each section's parsing and
validation self-contained and makes the connector tests easier to locate.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
A new `LegacyWorkspace::skip_connector_syncs(bool)` option, off by default,
leaves out everything v1 synced from outside services through Composio and the
older connector path, since those connectors re-sync on their own. The skipped
rows yield no item while the checkpoint still advances over them, and counts
exclude exactly the same rows, so resumption stays exact.

Auto-committed-on: macbook
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Tiny Sweeper reviewed this change across 6 lane(s) and found 2 active actionable finding(s). Detailed lane evidence and any incomplete work are listed below.

State: Ready for maintainer review
Priority: medium
Reviewed head: 439cce2a7cfa
Updated: 1791491926 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 8 Active findings 2
Tests 2 Noted findings 0
Documentation 1 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

What changed

The review could not produce a supported behavioral summary; inspect the cited changed surface and lane details below.

Features

None identified with supported citations.

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

  • medium · critique · Keep profiles whose facet ID is NULL — In SQL, `substr(NULL, 1, 6) != 'skill-'` evaluates to `NULL`, not `TRUE`, so a `WHERE` clause using this condition drops every `user_profile` row with a NULL `facet_id` even though (crates/tinymemory\-integrations/src/import/sections/connector\.rs:54)
  • medium · e2e · No end-to-end test drives the skip_connector_syncs import behaviour — `skip_connector_syncs` is a new public flag on `LegacyWorkspace` that changes what a legacy import yields across documents, chunks, profile and graph sections. No end-to-end harnes (crates/tinymemory\-integrations/src/import/workspace/mod\.rs:164)

Before merge

None.

Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 11 files; 3 findings. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/import/sections/connector\.rs — Keep profiles whose facet ID is NULL

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 10 files; 0 findings. 1 file was not security-reviewed: crates/tinymemory-integrations/src/import/README.md (prose or tabular data). _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The change adds an opt-in `skip_connector_syncs` filter across the four import sections, and the test suite pins the exact rows kept and dropped, the counts staying aligned with the stream, resumption with skipped rows advancing the checkpoint, and the owner-rule's dependence on the `owner` column. Behaviour is covered and the change looks safe to merge. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The diff matches the description: it adds an opt-in `LegacyWorkspace::skip_connector_syncs` that filters connector-synced rows out of the documents, chunks, profile and graph sections, keeps counts equal to `items()`, and is fully off by default; the new predicates, README section, and tests are all as described. The description even documents the notable design choices (taint not used, owner-column dependency) that the tests verify. I found no mismatch between what the PR claims and what it does, and the code follows the repository's stated conventions (rustdoc on the new public method, `#[cfg(test)]`/`connector_tests.rs` pattern, module docs, no unwrap in library paths). _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

e2e

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This change adds an opt-in `skip_connector_syncs` filter to the legacy v1 import across four sections, with thorough integration-test coverage in `tests/legacy_import.rs`. No end-to-end harness reaches it: the only e2e harness in the tree is the cortexdb integration setup, which drives the running service and never touches the legacy-import path, and there is no e2e workflow in the tree at all. The behavioural change is therefore verified only by in-crate integration tests, not by a test driving the running system. _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinymemory\-integrations/src/import/workspace/mod\.rs — No end-to-end test drives the skip_connector_syncs import behaviour
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.040027
  • Tokens: 411579 input · 22455 output · 71888 cached · 0 embedding
Head State Pass summary
439cce2a7cfa ready for maintainer review 2 active finding(s), 0 resolved finding(s) (at 1791491926)

tinysweeper 0.1.0

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T20:39:02.778114Z 439cce2 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bc28f6e0-791b-4f79-9a47-2c665d62f488
📥 Commits

Reviewing files that changed from the base of the PR and between 0047630 and 439cce2.

📒 Files selected for processing (11)
  • crates/tinymemory-integrations/src/import/README.md
  • crates/tinymemory-integrations/src/import/sections/chunks.rs
  • crates/tinymemory-integrations/src/import/sections/connector.rs
  • crates/tinymemory-integrations/src/import/sections/connector_tests.rs
  • crates/tinymemory-integrations/src/import/sections/graph.rs
  • crates/tinymemory-integrations/src/import/sections/memory_docs.rs
  • crates/tinymemory-integrations/src/import/sections/mod.rs
  • crates/tinymemory-integrations/src/import/sections/profile.rs
  • crates/tinymemory-integrations/src/import/workspace/mod.rs
  • crates/tinymemory-integrations/src/import/workspace/schema.rs
  • crates/tinymemory-integrations/tests/legacy_import.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Legacy imports now support opt-in filtering of connector-synced documents, chunks, profile facets, and namespaced graph rows. The same filters apply to item counts. Filtering defaults to off.

Changes

Connector-sync import filtering

Layer / File(s) Summary
Filtering option and connector classification
crates/tinymemory-integrations/src/import/workspace/mod.rs, crates/tinymemory-integrations/src/import/workspace/schema.rs, crates/tinymemory-integrations/src/import/sections/connector.rs, crates/tinymemory-integrations/src/import/sections/connector_tests.rs, crates/tinymemory-integrations/src/import/sections/mod.rs, crates/tinymemory-integrations/src/import/README.md
LegacyWorkspace::skip_connector_syncs(bool) adds a default-off option. Connector predicates classify namespaces and chunk sources. ChunkStore records whether mem_tree_chunks.owner exists.
Filtering import items and counts
crates/tinymemory-integrations/src/import/sections/chunks.rs, crates/tinymemory-integrations/src/import/sections/graph.rs, crates/tinymemory-integrations/src/import/sections/memory_docs.rs, crates/tinymemory-integrations/src/import/sections/profile.rs, crates/tinymemory-integrations/tests/legacy_import.rs, crates/tinymemory-integrations/src/import/README.md
When enabled, import sections omit matching rows and exclude them from counts. Tests cover default inclusion, filtered results, checkpoint resumption, page size, and a chunk table without an owner column. The README documents the filters and count behavior.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Suggested reviewers: m3ga-mind

Merge Risk: ⚪ Minimal · up to 439cc

This adds an opt-in import filter that is off by default, so existing behavior is unchanged. No merge-blocking risk was identified in the supplied context.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 439cc

The option narrows imported content and leaves default behavior unchanged. Changing the setting during a resumed migration can produce inconsistent exclusions, and the calling application's rollout behavior remains unverified.

Retained concerns

  • Low · security · inferred: Resume checkpoints are not bound to the connector-exclusion policy. If a host changes skip_connector_syncs from true to false, connector records skipped before a later persisted cursor remain omitted despite becoming eligible. Changing false to true only filters subsequent reads; it does not remove connector data already stored, including a partially stored failed batch. A migration can therefore finish with a destination reflecting mixed policies. Stable-policy retries are supported; whether the external host permits policy changes is unverified.
Security review details

Security Blast Radius

  • inferred — The demonstrated effect is limited to the selected legacy workspace/store and the destination engine supplied by the caller. The option narrows item selection without granting additional import authority. Tenant-wide or deployment-wide exposure cannot be established without the external host integration.

Trust Boundaries and Controls

  • inferred — This is a migration-selection policy, not an access-control or deletion boundary. The importer still opens the legacy stores, recognizes records through metadata conventions, and forwards retained items to the existing writer. Completeness against all historical connector writers is unverified.

Resilience and Maintainability Implications

  • inferred — Holding the policy constant preserves ordinary recovery: skipped rows advance the scan, failed storage retains the last committed checkpoint, and replay handles partially stored batches. Cross-run policy changes are the unresolved control-drift case rather than a failure of stable-policy recovery.

Hardening Proposals

  • proposed — Bind persisted migration state to the chosen exclusion policy, or explicitly require that policy to remain unchanged across retries. Define a separate reconciliation procedure for intentional policy changes, including records already written to the destination.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding support to skip connector-synced content during legacy import.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 28 functions across 10 files. (1 skipped: 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

A rabbit checks the import queue
And hops through rows in tidy view
Sync-marked chunks are left behind
Counts keep pace with what we find
Then carrots crown the filtered day

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 439cce2a7c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


/// Whether a `memory_docs` logical namespace is a connector sync.
pub(crate) fn is_connector_namespace(logical: &str) -> bool {
logical.starts_with("skill-") || logical.starts_with("source:")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve non-connector source documents

When skip_connector_syncs(true) is enabled for a workspace containing folder, file, RSS, web, or GitHub-repository sources, this predicate drops their memory_docs too. The legacy MemorySourceSink::accept_source_items used source:{source_id} for every source kind, not only Composio, so the namespace prefix alone cannot identify connector content; inspect the persisted source kind/metadata before skipping these rows or the migration silently omits user source documents.

Useful? React with 👍 / 👎.

Comment on lines +49 to +50
OR substr(COALESCE(namespace, ''), 1, 7) = 'source:' \
OR substr(COALESCE(namespace, ''), 1, 7) = 'source_')";

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 Badge Retain graphs extracted from non-connector sources

When the option is enabled after a non-Composio source was ingested, this filter also removes that source's graph relations. The legacy ingestion path extracted graphs under the same sanitized namespace as its document, so generic source:{source_id} namespaces appear here as source_<source_id> for folders, files, RSS, web pages, and repository sources as well as connectors; blanket-filtering both prefixes contradicts the promise that those sources remain migrated.

Useful? React with 👍 / 👎.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

tinysweeper found nothing blocking. Approving.

             $0.0400 · 411,579 in / 22,455 out · 71,888 cached (17%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0218 · 208,926 in / 11,618 out · 51,806 cached (25%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0177 · 154,636 in / 6,646 out  · 20,082 cached (13%) · gpt-5.6-luna
tests:       $0.0001 · 11,737 in  / 80 out     · 0 cached (0%)       · glm-5.3-flash
description: $0.0001 · 11,842 in  / 154 out    · 0 cached (0%)       · glm-5.3-flash
e2e:         $0.0001 · 12,827 in  / 809 out    · 0 cached (0%)       · glm-5.3-flash


/// SQL condition true for a `user_profile` row that is NOT a Composio
/// identity facet (`facet_id` starting `skill-`).
pub(crate) const PROFILE_KEPT: &str = "substr(facet_id, 1, 6) != 'skill-'";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium critique uncertain

Keep profiles whose facet ID is NULL

In SQL, substr(NULL, 1, 6) != 'skill-' evaluates to NULL, not TRUE, so a WHERE clause using this condition drops every user_profile row with a NULL facet_id even though it is not a Composio identity facet. I could not verify the schema nullability from the supplied context; if facet_id is nullable, this loses profiles during import. Use COALESCE (or an explicit IS NULL branch) so only IDs beginning with skill- are excluded.

Suggested change
pub(crate) const PROFILE_KEPT: &str = "substr(facet_id, 1, 6) != 'skill-'";
pub(crate) const PROFILE_KEPT: &str = "substr(COALESCE(facet_id, ''), 1, 6) != 'skill-'";

[RULE] null-filtering ·

/// / `source_*` graph namespaces. [`Self::counts`] excludes the same rows.
/// Off by default. See the module README for the exact rules.
#[must_use]
pub fn skip_connector_syncs(mut self, skip: bool) -> Self {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

priority medium e2e uncertain

No end-to-end test drives the skip_connector_syncs import behaviour

skip_connector_syncs is a new public flag on LegacyWorkspace that changes what a legacy import yields across documents, chunks, profile and graph sections. No end-to-end harness reaches it: the repository's e2e harness (integration/cortexdb) runs the cortexdb service with flag environments and a mock inference server, and never opens a legacy v1 workspace or runs an import; the candidate coverage lines above are lexical matches on unrelated words (object, document, items()). An end-to-end test would have to boot the host with a real v1 workspace containing connector-synced rows, run the import with the flag set, and observe the resulting store contents/counts — none does. Coverage currently rests entirely on crates/tinymemory-integrations/tests/legacy_import.rs, which is an integration test of the library API, not the e2e lane.

[RULE] e2e-uncovered ·

@tinysweeper tinysweeper Bot added the priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. label Oct 8, 2026
@senamakel
senamakel merged commit fc4c2b0 into main Oct 9, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant