fix(memory-sync): migrate Linear provider to memory_tree (#2885)#3018
Conversation
📝 WalkthroughWalkthroughAdds a Linear-to-memory-tree ingest module, updates the LinearProvider sync to ingest each issue into the memory-tree (replacing prior single-document persistence), registers ChangesLinear provider migration to memory-tree ingest
Playwright core-mode test helpers
Sequence Diagram(s)sequenceDiagram
participant LinearProvider
participant ingest_issue_into_memory_tree
participant ChunkStore
participant IngestPipeline
participant MemoryTree
LinearProvider->>ingest_issue_into_memory_tree: call(issue_id, title, updated_time, issue JSON)
ingest_issue_into_memory_tree->>ChunkStore: query existing chunks by source_id
ChunkStore-->>ingest_issue_into_memory_tree: existing chunk metadata / none
ingest_issue_into_memory_tree->>ChunkStore: delete existing chunks (if found)
ingest_issue_into_memory_tree->>IngestPipeline: ingest DocumentInput (provider,title,body,modified_at,tags,source)
IngestPipeline->>MemoryTree: create document and chunks
MemoryTree-->>IngestPipeline: upsert_count
IngestPipeline-->>ingest_issue_into_memory_tree: Result<usize>
ingest_issue_into_memory_tree-->>LinearProvider: return chunk count / error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
oxoxDev
left a comment
There was a problem hiding this comment.
Approve. Clean Linear → memory_tree migration. Reviewed all 4 files:
ingest.rs: stablelinear:{conn}:{issue}source id; edit re-ingest deletes prior chunks viais_source_ingestedguard beforedelete_chunks_by_source, theningest_document. The blocking sqlite calls are correctly wrapped inspawn_blocking, and the error path preserves the anyhow chain ({err:#}).provider.rs:persist_single_item→ingest_issue_into_memory_treeswap with correct arg order (title,updated.as_deref(),issue); failed ingest keeps the cursor for retry (parity preserved).source.rs:("linear", "document")alias + scope-match test sosource_kind=documentselects Linear trees.- Tests cover stable-id, timestamp parse (valid/invalid/missing), body render, first ingest writes chunks, and edited re-ingest replaces rather than appends.
All real gates green; CI red is only the unrelated Gmail-E2E flake.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/test/core-rpc-playwright-helper.test.ts (1)
12-13: ⚡ Quick winUse an
interfacefor the init-script argument shape.The inline object shape for
argsshould be extracted to aninterfaceto match the TS guideline.Proposed refactor
+interface SeedBrowserCoreModeArgs { + rpcUrl: string; + token: string; +} + const page = { async addInitScript( - script: (args: { rpcUrl: string; token: string }) => void, - args: { rpcUrl: string; token: string } + script: (args: SeedBrowserCoreModeArgs) => void, + args: SeedBrowserCoreModeArgs ) { script(args); }, } as unknown as Page;As per coding guidelines, "Prefer interface for defining object shapes in TypeScript" and "Use
interfaceovertypefor defining object shapes in TypeScript".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/test/core-rpc-playwright-helper.test.ts` around lines 12 - 13, Extract the inline object type for the init script into a named interface (e.g., RpcInitArgs) and replace both occurrences of the inline shape in the function signature and parameter list—specifically where "script: (args: { rpcUrl: string; token: string }) => void" and "args: { rpcUrl: string; token: string }" appear—so the signature becomes "script: (args: RpcInitArgs) => void" and the parameter uses "args: RpcInitArgs"; ensure the interface exports/exists in the same module and includes rpcUrl and token string properties.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@app/test/core-rpc-playwright-helper.test.ts`:
- Around line 12-13: Extract the inline object type for the init script into a
named interface (e.g., RpcInitArgs) and replace both occurrences of the inline
shape in the function signature and parameter list—specifically where "script:
(args: { rpcUrl: string; token: string }) => void" and "args: { rpcUrl: string;
token: string }" appear—so the signature becomes "script: (args: RpcInitArgs) =>
void" and the parameter uses "args: RpcInitArgs"; ensure the interface
exports/exists in the same module and includes rpcUrl and token string
properties.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1e8e5e96-a6c3-40d4-8aec-01644e00760e
📒 Files selected for processing (2)
app/test/core-rpc-playwright-helper.test.tsapp/test/playwright/helpers/core-rpc.ts
✅ Files skipped from review due to trivial changes (1)
- app/test/playwright/helpers/core-rpc.ts
|
f**k yeah love linear. |
Summary
linear:{connection_id}:{issue_id}source ids.persist_single_itempath withingest_document-backed memory_tree writes.linear:*source trees visible to document-kind retrieval filters.Problem
UnifiedMemory/memory_docswhile modern retrieval reads memory_tree.persist_single_item, so synced Linear issues could be invisible tomemory.search,tree.read_chunk,tree.browse, and related memory_tree retrieval surfaces.source_kind=documentscans unlesslinear:*scopes are classified as document-like source trees.Solution
linear::ingestto render one Linear issue payload into aDocumentInputand callmemory::ingest_pipeline::ingest_document.SyncStatebehavior for cursoring, edit-aware deduplication, daily budget, pagination, and KV persistence.linearto retrieval's document platform aliases sosource_kind=documentselects Linear source trees.Submission Checklist
diff-cover) meet the gate enforced by.github/workflows/pr-ci.yml. Runpnpm test:coverageandpnpm test:rustlocally; PRs below 80% on changed lines will not merge. N/A locally: targeted Rust coverage added andpnpm debug rust linearrun; full coverage is left to CI for this Rust-only narrow change.## Related— N/A: no matrix feature ID applies.docs/RELEASE-MANUAL-SMOKE.md) — N/A: internal provider memory persistence path only.Closes #NNNin the## Relatedsection — N/A: this PR references feat(memory-sync): migrate Notion/ClickUp/Linear/GitHub Composio providers off UnifiedMemory #2885 but does not close it because ClickUp remains and GitHub is covered separately by feat(composio): migrate GitHub provider to memory_tree pipeline (#2885) #2889.Impact
SyncState; new/edited Linear issues now write memory_tree chunks.Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/2885-linear-memory-tree5ca76a9b9b082717bd605851e80949bc1f5fe890Validation Run
pnpm --filter openhuman-app test:unit test/core-rpc-playwright-helper.test.ts— passed; includes RED/GREEN regression for walkthrough completion storage.pnpm --filter openhuman-app compile— passed.pnpm --filter openhuman-app exec eslint test/core-rpc-playwright-helper.test.ts test/playwright/helpers/core-rpc.ts— passed.pnpm --filter openhuman-app exec prettier --check test/core-rpc-playwright-helper.test.ts test/playwright/helpers/core-rpc.ts— passed.GGML_NATIVE=OFF pnpm --filter openhuman-app test:e2e:web:build— passed locally; initial run withoutGGML_NATIVE=OFFhit the known macOS Apple Siliconwhisper-rs-mcpu=nativeissue documented in AGENTS.md.bash app/scripts/e2e-web-session.sh ... -g "shows expired-auth state without logging out|connected Gmail exposes management affordances|renders the memory workspace and actions toolbar|mcp tab shows the placeholder panel"— reproduced that the Gmail management click path now passes; remaining local failures were auth/default-tab related, not Joyride click interception.app/dist-web/app/test-results; covered format check, lint (0 errors, existing warnings), compile, Tauri/Rust check.pnpm debug rust linear— 45 passed;pnpm debug rust scope_prefix_matching_known_platforms— 1 passed.Validation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
memory_docspersistence path.Parity Contract
linear:*scopes are selected by document-kind retrieval.Duplicate / Superseded PR Handling
Summary by CodeRabbit
New Features
Tests