Skip to content

fix(goals): stop the generic memory table from re-surfacing phantom goals in the VFS#225

Merged
khustup2 merged 2 commits into
mainfrom
fix/goals-vfs-skew
Jun 2, 2026
Merged

fix(goals): stop the generic memory table from re-surfacing phantom goals in the VFS#225
khustup2 merged 2 commits into
mainfrom
fix/goals-vfs-skew

Conversation

@khustup2
Copy link
Copy Markdown
Contributor

@khustup2 khustup2 commented Jun 2, 2026

Problem

VFS↔goals-table version skew. Pre-routing hook versions (<=0.7.4) wrote goals as plain files into the generic memory table. The VFS bootstrap (memoryBootstrap in deeplake-fs.ts) loads every memory path, so those goal-shaped rows reappear under /goal/<owner>/<status>/... even though they were never in hivemind_goals.

Result: a goal is visible in ls /goal/... but absent from hivemind goal list (the CLI reads only the structured table) — and vice-versa. Confirmed live: a phantom goal surfaced in the VFS that hivemind goal get reported as not found.

Fix

memoryBootstrap now skips goal/kpi-shaped paths when the dedicated table is configured, so that namespace is sourced solely from hivemind_goals / hivemind_kpis and the VFS and CLI agree. When routing is off (no dedicated table) the rows are the only copy, so they are kept.

Verification (against rebuilt bundle)

  • Phantom goal no longer appears in VFS — VFS and CLI now agree ✅
  • VFS write → reaches hivemind_goals
  • CLI create → visible in VFS ls
  • VFS mv opened→closed → table status updates, no dual-listing ✅
  • 2 regression tests added; full deeplake-fs suite (74) green; tsc --noEmit clean

Fixes the open goal "Fix Hivemind VFS to goals-table version skew".

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where legacy goal and KPI entries would incorrectly appear in listings when dedicated goal/KPI tables are configured, ensuring proper namespace isolation between generic and structured storage.

… in the VFS

VFS↔goals-table version skew: pre-routing hook versions (<=0.7.4) wrote goals as
plain files into the generic memory table. The VFS bootstrap loaded every memory
path, so those goal-shaped rows reappeared under /goal/<owner>/<status>/ even
though they were never in hivemind_goals — visible in `ls /goal/...` but absent
from `hivemind goal list` (which reads only the structured table), and vice
versa. memoryBootstrap now skips goal/kpi-shaped paths when the dedicated table
is configured, so that namespace is sourced solely from hivemind_goals/_kpis and
the VFS and CLI agree. Falls back to keeping the rows when routing is off (no
dedicated table = those rows are the only copy). Adds regression tests.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6cff65ac-d507-4c6b-bb1f-c6b9413fcdc1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR prevents "phantom" goal/KPI entries from polluting the goal namespace by filtering goal/KPI-shaped paths from the memory table during bootstrap when dedicated structured tables are configured. Implementation adds path classification logic with regression tests covering both enabled and disabled routing scenarios.

Changes

Goal/KPI Namespace Isolation

Layer / File(s) Summary
Goal/KPI path filtering in memory table bootstrap
src/shell/deeplake-fs.ts
During DeeplakeFs.create() memory table bootstrap, goal/KPI-shaped paths are classified using classifyPath() and skipped from cache when the corresponding dedicated goalsTable or kpisTable are configured.
Regression tests for goal/KPI namespace isolation
tests/claude-code/deeplake-fs.test.ts
Test suite with makeSkewClient mock simulating version-skew between memory and structured tables. Two tests verify: goal-shaped legacy rows are excluded when goalsTable/kpisTable routing is enabled, and preserved when routing is disabled.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • efenocchi

Poem

🐰 A phantom problem solved with care,
Goals and KPIs now route with flair,
Bootstrap filters out the "memory sprawl,"
Namespace isolated—clean for all!
Tests ensure no ghosts appear,
The goals stay pure, crystal clear! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description comprehensively covers the problem, fix, and verification, but is missing the required version bump and test plan checkboxes from the template. Add the Version Bump section with the updated version number in package.json and complete the Test plan checklist to align with the repository template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically identifies the main fix: preventing phantom goals from re-surfacing in the VFS by addressing the generic memory table issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/goals-vfs-skew

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.

❤️ Share

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

@coderabbitai coderabbitai Bot requested a review from efenocchi June 2, 2026 14:24
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 2, 2026

Coverage Report

Scope: files changed in this PR. Enforced threshold: 90% per metric (per file via vitest.config.ts).

Status Category Percentage Covered / Total
🟢 Lines 99.26% (🎯 90%) 534 / 538
🟢 Statements 97.56% (🎯 90%) 639 / 655
🟢 Functions 97.50% (🎯 90%) 78 / 80
🟢 Branches 91.39% (🎯 90%) 446 / 488
File Coverage — 2 files changed
File Stmts Branches Functions Lines
src/notifications/sources/resume-brief.ts 🟢 100.0% 🟢 91.5% 🟢 100.0% 🟢 100.0%
src/shell/deeplake-fs.ts 🟢 97.0% 🟢 91.4% 🟢 97.0% 🟢 99.1%

Generated for commit a9d8b7a.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/claude-code/deeplake-fs.test.ts (1)

253-281: ⚡ Quick win

Well-structured regression tests verify namespace isolation.

Both test cases correctly validate the fix: legacy goal-shaped memory rows are filtered when dedicated tables are configured, and preserved when routing is disabled. The assertions directly address the phantom-goal bug described in the PR objectives.


Optional: Consider adding KPI coverage

Since the filtering logic is symmetric for goals and KPIs, you could add a parallel test case for KPI paths to ensure completeness:

+ it("excludes legacy kpi-shaped rows from the memory table when kpisTable is set", async () => {
+   const client = makeSkewClient({
+     memoryPaths: ["/kpi/goal-uuid/legacy-kpi.md", "/notes/hello.md"],
+     goals: [],
+   });
+   const fs = await DeeplakeFs.create(client as never, "memory", "/", "sessions", {
+     goalsTable: "goals",
+     kpisTable: "kpis",
+   });
+   expect(await fs.readdir("/notes")).toContain("hello.md");
+   const kpiDir = await fs.readdir("/kpi");
+   expect(kpiDir).not.toContain("goal-uuid"); // legacy KPI path hidden
+ });

However, this is optional since the implementation uses identical logic for both cases.

🤖 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 `@tests/claude-code/deeplake-fs.test.ts` around lines 253 - 281, Add a parallel
KPI-focused test mirroring the two goal tests to ensure namespace isolation is
symmetric: create a test near "DeeplakeFs goal/kpi namespace isolation" that
uses makeSkewClient with memoryPaths like "/kpi/alice/active/legacy.md" and a
kpis array with a structured KPI (e.g., kpi_id "real") and assert
DeeplakeFs.create(..., { kpisTable: "kpis", goalsTable: "goals" }) hides the
legacy memory-row while the structured KPI surfaces, and another test that omits
kpisTable to assert the legacy memory-row is preserved; use the same helpers
(makeSkewClient, DeeplakeFs.create) and mirror the existing assertions for
consistency.
🤖 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 `@tests/claude-code/deeplake-fs.test.ts`:
- Around line 253-281: Add a parallel KPI-focused test mirroring the two goal
tests to ensure namespace isolation is symmetric: create a test near "DeeplakeFs
goal/kpi namespace isolation" that uses makeSkewClient with memoryPaths like
"/kpi/alice/active/legacy.md" and a kpis array with a structured KPI (e.g.,
kpi_id "real") and assert DeeplakeFs.create(..., { kpisTable: "kpis",
goalsTable: "goals" }) hides the legacy memory-row while the structured KPI
surfaces, and another test that omits kpisTable to assert the legacy memory-row
is preserved; use the same helpers (makeSkewClient, DeeplakeFs.create) and
mirror the existing assertions for consistency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 50ca9d00-9a88-4655-b0c6-c2849f5ad860

📥 Commits

Reviewing files that changed from the base of the PR and between 39fc31c and 86e9b99.

📒 Files selected for processing (2)
  • src/shell/deeplake-fs.ts
  • tests/claude-code/deeplake-fs.test.ts

…meout

Coverage: src/shell/deeplake-fs.ts was unenforced and surfaced as a red
PR coverage comment (~82% lines / 72% branches) because the file as a
whole was graded against 90% even though the goals-skew change touched
only a few lines. Add deeplake-fs-coverage.test.ts exercising the
previously-untested paths against a stateful mock DeeplakeApi: goal/kpi
structured-table routing (bootstrap, upsert INSERT/UPDATE, rm soft-close,
mv status-transition + guards), the /graph/* VFS bridge, session-backed
reads, the embeddings-disabled flush path, flush re-queue, and the
virtual-index sessions section. File now at 97/91/97/99; pin a 90/90/90/90
per-file threshold in vitest.config.ts so regressions fail the gate.

resume-brief: raise QUERY_TIMEOUT_MS from 1.5s to 3s so a cold backend
(~1.9s) no longer silently loses the race and degrades the pickup to a
plain welcome; still inside the 5s SessionStart hook budget.
Comment thread vitest.config.ts
// session concat path, and the rm/mv goal flows against a stateful
// mock DeeplakeApi, bringing it to 97/91/97/99. Floor set at 90 to
// catch regressions on these paths going forward.
"src/shell/deeplake-fs.ts": { statements: 90, branches: 90, functions: 90, lines: 90 },
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@CodeRabbit why did we add this?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@efenocchi This entry was added for two reasons:

  1. deeplake-fs.ts previously had no enforced coverage floor. The file sat at roughly 82% lines / 72% branches, which showed up as a red coverage comment on PRs but was never actually enforced — so regressions could slip through unnoticed.

  2. This PR adds substantial new tests. deeplake-fs-coverage.test.ts exercises the structured-table dispatch, /graph/* bridge, session concat path, and rm/mv goal flows against a stateful mock DeeplakeApi. That pushed measured coverage to ~97% statements / 91% branches / 97% functions / 99% lines.

By registering the threshold here at 90/90/90/90 now, any future change that regresses coverage on this file will fail CI immediately — enforcing the quality bar going forward rather than letting it silently erode again.

The inline comment above the entry in the diff spells this out:

"Previously unenforced: the file sat at ~82% lines / ~72% branches and only surfaced as a red PR-coverage comment … Floor set at 90 to catch regressions on these paths going forward."

Comment thread src/shell/deeplake-fs.ts
Comment on lines +237 to +240
const kind = classifyPath(p);
if ((kind === "goal" && fs.goalsTable) || (kind === "kpi" && fs.kpisTable)) {
continue;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@CodeRabbit what does it do?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@efenocchi, this code change fixes a "phantom goal" bug in the VFS bootstrap. Here's what it does:

Background: The VFS (DeeplakeFs) has two storage layers for goals:

  1. A generic memory table (old approach) — older hook versions (≤0.7.4) wrote goal entries here as plain files.
  2. A dedicated hivemind_goals table (new approach) — the structured source of truth that the CLI (hivemind goal list) reads from.

The bug: When DeeplakeFs.create() bootstrapped the generic memory table, it loaded all rows indiscriminately — including any goal-shaped paths (e.g. /goal/<owner>/opened/<uuid>.md) that old hook versions had written there. This caused those goals to reappear in the VFS (ls /goal/... showed them) even though the structured table had no record of them → "phantom" goals.

The fix (the added lines):

const kind = classifyPath(p);
if ((kind === "goal" && fs.goalsTable) || (kind === "kpi" && fs.kpisTable)) {
  continue;
}

During bootstrap, for each row fetched from the generic memory table:

  • It classifies the path using classifyPath() to check if it looks like a goal or KPI path.
  • If it does and the corresponding dedicated table (goalsTable / kpisTable) is configured, it skips loading that row into the VFS cache.
  • The goal/KPI data is then sourced exclusively from the dedicated structured tables (bootstrapped separately in goalsBootstrap / kpisBootstrap).
  • If no dedicated table is configured (legacy/routing-off mode), the memory rows are kept as-is — they're the only copy.

This ensures the VFS and the CLI always show the same set of goals with no phantom duplicates.

@khustup2 khustup2 merged commit e194fb1 into main Jun 2, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants