@jlongo78/agent-spaces 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.claude/settings.local.json +55 -0
- package/.next/standalone/.claude/spaces-env.json +1 -0
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +2 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +27 -3
- package/.next/standalone/.next/required-server-files.json +19 -19
- package/.next/standalone/.next/routes-manifest.json +6 -0
- package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/admin/users/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/analytics/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/cortex/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/cortex/page/react-loadable-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/network/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/sessions/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/settings/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/(desktop)/workspaces/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error.html +2 -2
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.rsc +7 -6
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +7 -6
- package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.html +1 -1
- package/.next/standalone/.next/server/app/admin/users.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.html +1 -1
- package/.next/standalone/.next/server/app/analytics.rsc +3 -3
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/cortex.html +1 -1
- package/.next/standalone/.next/server/app/cortex.rsc +3 -3
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login.html +1 -1
- package/.next/standalone/.next/server/app/login.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/projects.html +1 -1
- package/.next/standalone/.next/server/app/m/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions/[id]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/sessions.html +1 -1
- package/.next/standalone/.next/server/app/m/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/settings.html +1 -1
- package/.next/standalone/.next/server/app/m/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/m/terminal.html +1 -1
- package/.next/standalone/.next/server/app/m/terminal.rsc +3 -3
- package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.html +1 -1
- package/.next/standalone/.next/server/app/m.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.html +1 -1
- package/.next/standalone/.next/server/app/network.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.html +1 -1
- package/.next/standalone/.next/server/app/projects.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.html +1 -1
- package/.next/standalone/.next/server/app/sessions.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.html +1 -1
- package/.next/standalone/.next/server/app/terminal.rsc +3 -3
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/vr/page/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/vr/page/build-manifest.json +18 -0
- package/.next/standalone/.next/server/app/vr/page/next-font-manifest.json +11 -0
- package/.next/standalone/.next/server/app/vr/page/react-loadable-manifest.json +11 -0
- package/.next/standalone/.next/server/app/vr/page/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/vr/page.js +17 -0
- package/.next/standalone/.next/server/app/vr/page.js.map +5 -0
- package/.next/standalone/.next/server/app/vr/page.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/vr/page_client-reference-manifest.js +2 -0
- package/.next/standalone/.next/server/app/vr.html +1 -0
- package/.next/standalone/.next/server/app/vr.meta +15 -0
- package/.next/standalone/.next/server/app/vr.rsc +21 -0
- package/.next/standalone/.next/server/app/vr.segments/_full.segment.rsc +21 -0
- package/.next/standalone/.next/server/app/vr.segments/_head.segment.rsc +6 -0
- package/.next/standalone/.next/server/app/vr.segments/_index.segment.rsc +6 -0
- package/.next/standalone/.next/server/app/vr.segments/_tree.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/vr.segments/vr/__PAGE__.segment.rsc +9 -0
- package/.next/standalone/.next/server/app/vr.segments/vr.segment.rsc +4 -0
- package/.next/standalone/.next/server/app/workspaces.html +1 -1
- package/.next/standalone/.next/server/app/workspaces.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app-paths-manifest.json +2 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__00bf0ace._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08a68343._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0add852f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c113ed0._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e1a27e0._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e71d908._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e9142f3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10e47926._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1194f2c1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1665dc78._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__175cbabf._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19c2d094._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adae357._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e8fabeb._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1f8deca0._.js +8 -8
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__253fdda1._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__28e6434f._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2a386564._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2acbd703._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2acefabb._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c20fb38._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__309132cd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__33fec964._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3786d8ae._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3ae92407._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3beda9fe._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__3e3f25a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__4619e9bd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a051043._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__50208a5f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__508002e4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5086c373._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5913e097._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5b5f68d2._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c1f2459._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5ec8c977._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__5f8c694a._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__64d30d4d._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c54fc2e._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6dc1fb7e._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6e568102._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__6faa04c0._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__727d05f1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__75d12b32._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e7250a4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8309e0a4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__86cc0e2b._.js +6 -6
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8915603e._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c2565a._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d178ad9._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__93ee06f3._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e4c154a._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__a1fbc199._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d2e1d3._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ae53d343._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b3a04cef._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b6b6ce60._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__b9545dd9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c200e21a._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c3c74ca4._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cba5f007._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cbf4ceb0._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cefdba2f._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf9e82bb._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d15515e3._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2897392._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d3b2d856._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d73273ca._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8417eb6._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__db4726bc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc2a55de._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc6e2e5f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e0d4690b._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e3ecfd17._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9223f55._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ea630076._.js +3 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__eb8acb65._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f26ca49d._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f33e1101._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f3a4c668._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__f515f865._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__fed41403._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff2e98c2._.js +2 -2
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_339169c8.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_97dac613.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0d8d81ca._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1425c64f._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d2ce8f1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__31137509._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__3633a587._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__3c79441b._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__4ca0f26b._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__5b90d3ad._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__62a0b363._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__68205a46._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__69fd2efa._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__85dcf0f7._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__8c53a5da._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__aecb1873._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__b02cd143._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__b9bcde11._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__cac90169._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__d25de2f0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__e2f86be8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__ee626b5b._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f39a9e98._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f3c566cd._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__f76aa221._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_149d7fd4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_2230ad2d._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_2e0dd6a7._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_3cd2355c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_3d206597._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/_47cc9af0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_5cf334fd._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_7082788b._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_7154d8ae._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_75bb1b9a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_aeeff784._.js → _81abf587._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_8acf81e2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_8c36feb8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_91e9bb86._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_ac4c1838._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_ad8515fc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_b1f49e81._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_c0fe7614._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_d4825f5a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_da10a9f4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_db0abd0a._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_db2fec84._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_dee5d4a1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_ef482c0c._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_efe43d2f._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_f4a4e116._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_f4d525d2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_f4e57187._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_vr_page_actions_3fb70d92.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules_32f9d62f._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_02f39477.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_eedfc1fd._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_40fa36ce._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_cortex_page_tsx_0f33d8b3._.js +3 -0
- package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__32a0045c._.js +1 -1
- package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/next-font-manifest.js +1 -1
- package/.next/standalone/.next/server/next-font-manifest.json +4 -0
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +2 -2
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/045c83caa4d15373.js +1 -0
- package/.next/standalone/.next/static/chunks/07ea09e6024a523b.js +1 -0
- package/.next/standalone/.next/static/chunks/{aae9e0fa485bd835.js → 158b52b84e647ac1.js} +2 -2
- package/.next/standalone/.next/static/chunks/232d8aae4fefab70.js +1 -0
- package/.next/standalone/.next/static/chunks/2ad22562bb37ecad.js +1011 -0
- package/.next/standalone/.next/static/chunks/{a4e5c700421eaa46.js → 412140a02893327a.js} +1 -1
- package/.next/standalone/.next/static/chunks/481cc11ae80b08b1.js +1 -0
- package/.next/standalone/.next/static/chunks/5325351ef49cb65f.js +1 -0
- package/.next/standalone/.next/static/chunks/559735e598ca3cbb.js +1 -0
- package/.next/standalone/.next/static/chunks/59c63d5af5cf3daf.js +1 -0
- package/.next/standalone/.next/static/chunks/5d5d7b0095dd52ae.js +1 -0
- package/.next/standalone/.next/static/chunks/69606d281c39f9b2.js +1 -0
- package/.next/standalone/.next/static/chunks/6ae575967d091df4.js +1 -0
- package/.next/standalone/.next/static/chunks/7f8455bb855a6c84.js +1 -0
- package/.next/standalone/.next/static/chunks/84fe8d44deeeb74f.js +757 -0
- package/.next/standalone/.next/static/chunks/898f380eba90427a.js +1 -0
- package/.next/standalone/.next/static/chunks/95339e55722bb4ca.js +5 -0
- package/.next/standalone/.next/static/chunks/9cd594813c539df9.js +1 -0
- package/.next/standalone/.next/static/chunks/{7424664c6ffa94bd.js → 9cfa0291d55d8d2a.js} +1 -1
- package/.next/standalone/.next/static/chunks/ad1423eed05d129b.js +1 -0
- package/.next/standalone/.next/static/chunks/ae7b146884c67d2a.js +1 -0
- package/.next/standalone/.next/static/chunks/b84072d72aa86417.js +1 -0
- package/.next/standalone/.next/static/chunks/c1a95aebf6725f64.css +3 -0
- package/.next/standalone/.next/static/chunks/c515eb77d9410aa0.js +5 -0
- package/.next/standalone/.next/static/chunks/{9899cf4c2bdbe61d.js → d9ae203a7f123546.js} +2 -2
- package/.next/standalone/.next/static/chunks/e116953dc83d4eec.js +1 -0
- package/.next/standalone/.next/static/chunks/fdc09bd135846960.js +1 -0
- package/.next/standalone/.next/static/chunks/ff0196911449e745.js +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-4c21186b79fb4c10.js → turbopack-e1a0994ed4af988c.js} +1 -1
- package/.next/standalone/.spaces/cortex-context.md +70 -0
- package/.next/standalone/bin/cortex-hook.sh +62 -62
- package/.next/standalone/bin/cortex-mcp.js +60 -60
- package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
- package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
- package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
- package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
- package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
- package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -1846
- package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
- package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
- package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
- package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
- package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -341
- package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
- package/.next/standalone/node_modules/@img/{sharp-linux-x64 → sharp-win32-x64}/package.json +39 -46
- package/.next/standalone/package.json +104 -102
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/src/app/(desktop)/cortex/page.tsx +78 -78
- package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
- package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -27
- package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -29
- package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -23
- package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
- package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
- package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
- package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
- package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
- package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
- package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
- package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
- package/.next/standalone/src/app/api/cortex/import/route.ts +75 -75
- package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
- package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +29 -29
- package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
- package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
- package/.next/standalone/src/app/api/cortex/knowledge/route.ts +93 -93
- package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
- package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
- package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
- package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -46
- package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
- package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +6 -6
- package/.next/standalone/src/app/api/cortex/search/route.ts +43 -43
- package/.next/standalone/src/app/api/cortex/settings/route.ts +33 -33
- package/.next/standalone/src/app/api/cortex/status/route.ts +169 -169
- package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
- package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
- package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
- package/.next/standalone/src/components/cortex/constants.ts +29 -29
- package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -304
- package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
- package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
- package/.next/standalone/src/components/cortex/cortex-settings.tsx +221 -221
- package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -810
- package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
- package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
- package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -212
- package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
- package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -109
- package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -158
- package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -215
- package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -126
- package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -113
- package/.next/standalone/src/lib/cortex/config.ts +40 -40
- package/.next/standalone/src/lib/cortex/debug.ts +10 -10
- package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
- package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
- package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
- package/.next/standalone/src/lib/cortex/index.ts +56 -56
- package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
- package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
- package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
- package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
- package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
- package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
- package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
- package/.next/standalone/src/lib/cortex/mcp/server.ts +8 -8
- package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
- package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
- package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
- package/.next/standalone/src/lib/cortex/types.ts +39 -39
- package/.next/standalone/tsconfig.json +34 -34
- package/LICENSE +661 -661
- package/README.md +131 -131
- package/bin/cortex-hook.sh +62 -62
- package/bin/cortex-mcp.js +60 -60
- package/bin/fix-standalone-externals.js +79 -79
- package/bin/lib/auto-setup.js +110 -110
- package/bin/mdns-service.js +171 -171
- package/bin/postinstall.js +35 -35
- package/bin/setup-admin.js +195 -195
- package/bin/spaces-dev.js +208 -208
- package/bin/spaces-install.js +599 -599
- package/bin/spaces-reset-totp.js +50 -50
- package/bin/spaces-service.js +1020 -1020
- package/bin/spaces-setup.js +253 -253
- package/bin/spaces.js +776 -776
- package/bin/ssh-auth-keys.sh +68 -68
- package/bin/terminal-server.js +1683 -1649
- package/package.json +104 -102
- package/.next/standalone/.next/server/chunks/ssr/_078dd64d._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_701606d5._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_72b1de37._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_950142a4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_components_terminal_terminal-pane_tsx_803c5e2c._.js +0 -7
- package/.next/standalone/.next/static/chunks/18f168665aef1aab.js +0 -1
- package/.next/standalone/.next/static/chunks/25b7a243a404a1a7.js +0 -1
- package/.next/standalone/.next/static/chunks/4a50d2a3e9bc9b41.js +0 -1
- package/.next/standalone/.next/static/chunks/6c78a1dfa7ec2959.css +0 -3
- package/.next/standalone/.next/static/chunks/7e0091ab6c5ee8bd.js +0 -1
- package/.next/standalone/.next/static/chunks/869f562dc32e55f4.js +0 -1
- package/.next/standalone/.next/static/chunks/8b3f4572fec83caa.js +0 -5
- package/.next/standalone/.next/static/chunks/8d5419afc4b9116b.js +0 -1
- package/.next/standalone/.next/static/chunks/9b2c5451f0b67975.js +0 -1
- package/.next/standalone/.next/static/chunks/ac339e970df82fa5.js +0 -5
- package/.next/standalone/.next/static/chunks/e7772d64463868eb.js +0 -1
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +0 -46
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +0 -1
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +0 -42
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
- package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
- package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
- package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
- package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
- /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → BEY-sql3lQLouidpurSQf}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → BEY-sql3lQLouidpurSQf}/_clientMiddlewareManifest.json +0 -0
- /package/.next/standalone/.next/static/{77VYbwIoyxFNr5xevTrCu → BEY-sql3lQLouidpurSQf}/_ssgManifest.js +0 -0
- /package/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-win32-x64}/versions.json +0 -0
|
@@ -1,768 +1,768 @@
|
|
|
1
|
-
# Cortex v2 — Pillar 6: Gravity System
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
-
|
|
5
|
-
**Goal:** Implement bi-directional knowledge flow — evidence-based bubble-up promotion, decision trickle-down, conflict detection during ingestion, stale knowledge decay, and a background gravity scheduler that runs every 6 hours.
|
|
6
|
-
|
|
7
|
-
**Architecture:** A new `src/lib/cortex/gravity/` module with four components: `promotion.ts` (bubble-up logic), `trickle.ts` (push-down logic), `contradiction.ts` (ingestion-time conflict detection), and `scheduler.ts` (background timer orchestrating all gravity operations). Uses the `gravity_state` SQLite table (created in Pillar 1) for checkpoint persistence.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, better-sqlite3, LanceDB, vitest
|
|
10
|
-
|
|
11
|
-
**Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 6
|
|
12
|
-
|
|
13
|
-
**Depends on:** All previous pillars (1-5) — completed
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## File Structure
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
New files:
|
|
21
|
-
├── src/lib/cortex/gravity/promotion.ts — Bubble-up: evidence-based promotion
|
|
22
|
-
├── src/lib/cortex/gravity/trickle.ts — Trickle-down: decision push + visibility
|
|
23
|
-
├── src/lib/cortex/gravity/contradiction.ts — Ingestion-time conflict detection
|
|
24
|
-
├── src/lib/cortex/gravity/decay.ts — Stale knowledge decay + archival
|
|
25
|
-
├── src/lib/cortex/gravity/scheduler.ts — Background scheduler (setInterval)
|
|
26
|
-
├── src/lib/cortex/gravity/index.ts — Barrel export
|
|
27
|
-
|
|
28
|
-
Modified files:
|
|
29
|
-
├── src/lib/cortex/index.ts — Add GravityScheduler to CortexInstance
|
|
30
|
-
|
|
31
|
-
Test files:
|
|
32
|
-
├── tests/lib/cortex/gravity/promotion.test.ts
|
|
33
|
-
├── tests/lib/cortex/gravity/trickle.test.ts
|
|
34
|
-
├── tests/lib/cortex/gravity/contradiction.test.ts
|
|
35
|
-
├── tests/lib/cortex/gravity/decay.test.ts
|
|
36
|
-
├── tests/lib/cortex/gravity/scheduler.test.ts
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Chunk 1: Promotion and Trickle-Down
|
|
42
|
-
|
|
43
|
-
### Task 1: Bubble-up promotion logic
|
|
44
|
-
|
|
45
|
-
**Files:**
|
|
46
|
-
- Create: `src/lib/cortex/gravity/promotion.ts`
|
|
47
|
-
- Create: `tests/lib/cortex/gravity/promotion.test.ts`
|
|
48
|
-
|
|
49
|
-
- [ ] **Step 1: Write failing tests**
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
// tests/lib/cortex/gravity/promotion.test.ts
|
|
53
|
-
import { describe, it, expect } from 'vitest';
|
|
54
|
-
import {
|
|
55
|
-
computePromotionScore,
|
|
56
|
-
shouldPromote,
|
|
57
|
-
PROMOTION_TYPE_WEIGHTS,
|
|
58
|
-
} from '@/lib/cortex/gravity/promotion';
|
|
59
|
-
|
|
60
|
-
describe('computePromotionScore', () => {
|
|
61
|
-
it('computes score from evidence, type weight, and freshness', () => {
|
|
62
|
-
const score = computePromotionScore({
|
|
63
|
-
evidenceScore: 0.8,
|
|
64
|
-
type: 'decision',
|
|
65
|
-
createdDaysAgo: 10,
|
|
66
|
-
});
|
|
67
|
-
// 0.8 * 1.5 (decision weight) * 1.0 (< 30 days) = 1.2 → capped at 1.0
|
|
68
|
-
expect(score).toBeLessThanOrEqual(1.0);
|
|
69
|
-
expect(score).toBeGreaterThan(0.5);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('applies type weights correctly', () => {
|
|
73
|
-
const decision = computePromotionScore({ evidenceScore: 0.5, type: 'decision', createdDaysAgo: 10 });
|
|
74
|
-
const conversation = computePromotionScore({ evidenceScore: 0.5, type: 'conversation', createdDaysAgo: 10 });
|
|
75
|
-
expect(decision).toBeGreaterThan(conversation);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('decays with age', () => {
|
|
79
|
-
const recent = computePromotionScore({ evidenceScore: 0.8, type: 'pattern', createdDaysAgo: 5 });
|
|
80
|
-
const old = computePromotionScore({ evidenceScore: 0.8, type: 'pattern', createdDaysAgo: 120 });
|
|
81
|
-
expect(recent).toBeGreaterThan(old);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe('shouldPromote', () => {
|
|
86
|
-
it('promotes personal→team when score and corroborations meet threshold', () => {
|
|
87
|
-
expect(shouldPromote({
|
|
88
|
-
currentLevel: 'personal',
|
|
89
|
-
promotionScore: 0.7,
|
|
90
|
-
corroborations: 3,
|
|
91
|
-
sensitivity: 'internal',
|
|
92
|
-
hasContradictions: false,
|
|
93
|
-
})).toBe(true);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('blocks promotion when sensitivity is restricted', () => {
|
|
97
|
-
expect(shouldPromote({
|
|
98
|
-
currentLevel: 'personal',
|
|
99
|
-
promotionScore: 0.7,
|
|
100
|
-
corroborations: 3,
|
|
101
|
-
sensitivity: 'restricted',
|
|
102
|
-
hasContradictions: false,
|
|
103
|
-
})).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('blocks promotion when corroborations insufficient', () => {
|
|
107
|
-
expect(shouldPromote({
|
|
108
|
-
currentLevel: 'personal',
|
|
109
|
-
promotionScore: 0.7,
|
|
110
|
-
corroborations: 1, // needs ≥ 2
|
|
111
|
-
sensitivity: 'internal',
|
|
112
|
-
hasContradictions: false,
|
|
113
|
-
})).toBe(false);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('blocks dept→org promotion when contradictions exist', () => {
|
|
117
|
-
expect(shouldPromote({
|
|
118
|
-
currentLevel: 'department',
|
|
119
|
-
promotionScore: 0.95,
|
|
120
|
-
corroborations: 6,
|
|
121
|
-
sensitivity: 'internal',
|
|
122
|
-
hasContradictions: true,
|
|
123
|
-
})).toBe(false);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('requires higher thresholds for higher promotions', () => {
|
|
127
|
-
// Score 0.65 passes personal→team but not team→dept
|
|
128
|
-
expect(shouldPromote({
|
|
129
|
-
currentLevel: 'personal', promotionScore: 0.65, corroborations: 2,
|
|
130
|
-
sensitivity: 'internal', hasContradictions: false,
|
|
131
|
-
})).toBe(true);
|
|
132
|
-
|
|
133
|
-
expect(shouldPromote({
|
|
134
|
-
currentLevel: 'team', promotionScore: 0.65, corroborations: 3,
|
|
135
|
-
sensitivity: 'internal', hasContradictions: false,
|
|
136
|
-
})).toBe(false); // needs ≥ 0.75
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
- [ ] **Step 2: Implement promotion logic**
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
// src/lib/cortex/gravity/promotion.ts
|
|
145
|
-
import type { KnowledgeType, ScopeLevel, SensitivityClass } from '../knowledge/types';
|
|
146
|
-
|
|
147
|
-
export const PROMOTION_TYPE_WEIGHTS: Record<string, number> = {
|
|
148
|
-
decision: 1.5,
|
|
149
|
-
error_fix: 1.3,
|
|
150
|
-
pattern: 1.2,
|
|
151
|
-
preference: 1.0,
|
|
152
|
-
code_pattern: 1.0,
|
|
153
|
-
command: 0.8,
|
|
154
|
-
context: 0.7,
|
|
155
|
-
summary: 0.7,
|
|
156
|
-
conversation: 0.5,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
const FRESHNESS_THRESHOLDS = [
|
|
160
|
-
{ maxDays: 30, multiplier: 1.0 },
|
|
161
|
-
{ maxDays: 90, multiplier: 0.8 },
|
|
162
|
-
{ maxDays: Infinity, multiplier: 0.5 },
|
|
163
|
-
];
|
|
164
|
-
|
|
165
|
-
interface PromotionScoreInput {
|
|
166
|
-
evidenceScore: number;
|
|
167
|
-
type: string;
|
|
168
|
-
createdDaysAgo: number;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function computePromotionScore(input: PromotionScoreInput): number {
|
|
172
|
-
const typeWeight = PROMOTION_TYPE_WEIGHTS[input.type] ?? 1.0;
|
|
173
|
-
const freshness = FRESHNESS_THRESHOLDS.find(t => input.createdDaysAgo <= t.maxDays)?.multiplier ?? 0.5;
|
|
174
|
-
return Math.min(1.0, input.evidenceScore * typeWeight * freshness);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
interface PromotionCheck {
|
|
178
|
-
currentLevel: ScopeLevel;
|
|
179
|
-
promotionScore: number;
|
|
180
|
-
corroborations: number;
|
|
181
|
-
sensitivity: string;
|
|
182
|
-
hasContradictions: boolean;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const PROMOTION_THRESHOLDS: Record<string, { minScore: number; minCorroborations: number; noContradictions?: boolean }> = {
|
|
186
|
-
personal: { minScore: 0.6, minCorroborations: 2 },
|
|
187
|
-
team: { minScore: 0.75, minCorroborations: 3 },
|
|
188
|
-
department: { minScore: 0.9, minCorroborations: 5, noContradictions: true },
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const NEXT_LEVEL: Record<string, ScopeLevel> = {
|
|
192
|
-
personal: 'team',
|
|
193
|
-
team: 'department',
|
|
194
|
-
department: 'organization',
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export function shouldPromote(check: PromotionCheck): boolean {
|
|
198
|
-
const threshold = PROMOTION_THRESHOLDS[check.currentLevel];
|
|
199
|
-
if (!threshold) return false; // organization can't promote further
|
|
200
|
-
|
|
201
|
-
if (check.sensitivity === 'restricted' || check.sensitivity === 'confidential') return false;
|
|
202
|
-
if (check.promotionScore < threshold.minScore) return false;
|
|
203
|
-
if (check.corroborations < threshold.minCorroborations) return false;
|
|
204
|
-
if (threshold.noContradictions && check.hasContradictions) return false;
|
|
205
|
-
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export function getNextLevel(current: ScopeLevel): ScopeLevel | null {
|
|
210
|
-
return NEXT_LEVEL[current] ?? null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export const HOP_DECAY = 0.85;
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
- [ ] **Step 3: Run tests, commit**
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
git commit -m "feat(cortex): add evidence-based promotion logic for gravity system"
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
---
|
|
223
|
-
|
|
224
|
-
### Task 2: Trickle-down logic
|
|
225
|
-
|
|
226
|
-
**Files:**
|
|
227
|
-
- Create: `src/lib/cortex/gravity/trickle.ts`
|
|
228
|
-
- Create: `tests/lib/cortex/gravity/trickle.test.ts`
|
|
229
|
-
|
|
230
|
-
- [ ] **Step 1: Write failing tests**
|
|
231
|
-
|
|
232
|
-
```typescript
|
|
233
|
-
// tests/lib/cortex/gravity/trickle.test.ts
|
|
234
|
-
import { describe, it, expect } from 'vitest';
|
|
235
|
-
import { getTrickleMode, TRICKLE_DEFAULTS } from '@/lib/cortex/gravity/trickle';
|
|
236
|
-
|
|
237
|
-
describe('getTrickleMode', () => {
|
|
238
|
-
it('returns PUSH for org decisions', () => {
|
|
239
|
-
expect(getTrickleMode('decision', 'organization')).toBe('push');
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
it('returns PUSH for security policies', () => {
|
|
243
|
-
expect(getTrickleMode('error_fix', 'organization', ['security'])).toBe('push');
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
it('returns VISIBILITY for best practices', () => {
|
|
247
|
-
expect(getTrickleMode('pattern', 'organization')).toBe('visibility');
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('returns VISIBILITY for general patterns', () => {
|
|
251
|
-
expect(getTrickleMode('conversation', 'organization')).toBe('visibility');
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('returns null for non-org scopes', () => {
|
|
255
|
-
expect(getTrickleMode('decision', 'team')).toBeNull();
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('exports trickle defaults table', () => {
|
|
259
|
-
expect(TRICKLE_DEFAULTS).toBeDefined();
|
|
260
|
-
expect(TRICKLE_DEFAULTS.decision).toBe('push');
|
|
261
|
-
expect(TRICKLE_DEFAULTS.pattern).toBe('visibility');
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
- [ ] **Step 2: Implement trickle-down**
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
// src/lib/cortex/gravity/trickle.ts
|
|
270
|
-
import type { KnowledgeType, ScopeLevel } from '../knowledge/types';
|
|
271
|
-
|
|
272
|
-
export type TrickleMode = 'push' | 'visibility';
|
|
273
|
-
|
|
274
|
-
export const TRICKLE_DEFAULTS: Record<string, TrickleMode> = {
|
|
275
|
-
decision: 'push',
|
|
276
|
-
preference: 'push',
|
|
277
|
-
error_fix: 'visibility',
|
|
278
|
-
pattern: 'visibility',
|
|
279
|
-
code_pattern: 'visibility',
|
|
280
|
-
command: 'visibility',
|
|
281
|
-
context: 'visibility',
|
|
282
|
-
conversation: 'visibility',
|
|
283
|
-
summary: 'visibility',
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const SECURITY_TOPICS = ['security', 'vulnerability', 'exploit', 'cve', 'incident'];
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Determine trickle mode for knowledge at a given scope.
|
|
290
|
-
* Only org-level knowledge trickles down.
|
|
291
|
-
* Returns null if knowledge shouldn't trickle (not at org scope).
|
|
292
|
-
*/
|
|
293
|
-
export function getTrickleMode(
|
|
294
|
-
type: string,
|
|
295
|
-
scopeLevel: string,
|
|
296
|
-
topics?: string[],
|
|
297
|
-
): TrickleMode | null {
|
|
298
|
-
// Only org-level knowledge trickles down
|
|
299
|
-
if (scopeLevel !== 'organization') return null;
|
|
300
|
-
|
|
301
|
-
// Security topics always push
|
|
302
|
-
if (topics?.some(t => SECURITY_TOPICS.includes(t.toLowerCase()))) {
|
|
303
|
-
return 'push';
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return TRICKLE_DEFAULTS[type] ?? 'visibility';
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
- [ ] **Step 3: Run tests, commit**
|
|
311
|
-
|
|
312
|
-
```bash
|
|
313
|
-
git commit -m "feat(cortex): add trickle-down logic for gravity system"
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## Chunk 2: Contradiction Detection and Decay
|
|
319
|
-
|
|
320
|
-
### Task 3: Ingestion-time contradiction detection
|
|
321
|
-
|
|
322
|
-
**Files:**
|
|
323
|
-
- Create: `src/lib/cortex/gravity/contradiction.ts`
|
|
324
|
-
- Create: `tests/lib/cortex/gravity/contradiction.test.ts`
|
|
325
|
-
|
|
326
|
-
- [ ] **Step 1: Write failing tests**
|
|
327
|
-
|
|
328
|
-
```typescript
|
|
329
|
-
// tests/lib/cortex/gravity/contradiction.test.ts
|
|
330
|
-
import { describe, it, expect } from 'vitest';
|
|
331
|
-
import {
|
|
332
|
-
detectSentimentConflict,
|
|
333
|
-
CONTRADICTION_KEYWORDS,
|
|
334
|
-
} from '@/lib/cortex/gravity/contradiction';
|
|
335
|
-
|
|
336
|
-
describe('detectSentimentConflict', () => {
|
|
337
|
-
it('detects opposing sentiments', () => {
|
|
338
|
-
expect(detectSentimentConflict(
|
|
339
|
-
'increase connection pool size to 50',
|
|
340
|
-
'do NOT increase pool size, scale horizontally instead',
|
|
341
|
-
)).toBe(true);
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('returns false for agreeing statements', () => {
|
|
345
|
-
expect(detectSentimentConflict(
|
|
346
|
-
'use PostgreSQL for the new service',
|
|
347
|
-
'PostgreSQL is the right choice for reliability',
|
|
348
|
-
)).toBe(false);
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
it('detects negation patterns', () => {
|
|
352
|
-
expect(detectSentimentConflict(
|
|
353
|
-
'we should use Redis for caching',
|
|
354
|
-
'we should not use Redis for caching',
|
|
355
|
-
)).toBe(true);
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
it('detects replacement/alternative patterns', () => {
|
|
359
|
-
expect(detectSentimentConflict(
|
|
360
|
-
'use Express for the API',
|
|
361
|
-
'use Fastify instead of Express',
|
|
362
|
-
)).toBe(true);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
it('returns false for unrelated statements', () => {
|
|
366
|
-
expect(detectSentimentConflict(
|
|
367
|
-
'the auth service handles JWT',
|
|
368
|
-
'deploy to production on Fridays',
|
|
369
|
-
)).toBe(false);
|
|
370
|
-
});
|
|
371
|
-
});
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
- [ ] **Step 2: Implement contradiction detection**
|
|
375
|
-
|
|
376
|
-
```typescript
|
|
377
|
-
// src/lib/cortex/gravity/contradiction.ts
|
|
378
|
-
|
|
379
|
-
export const CONTRADICTION_KEYWORDS = {
|
|
380
|
-
negation: [/\bnot\b/i, /\bdon't\b/i, /\bdo\s+not\b/i, /\bnever\b/i, /\bavoid\b/i, /\bstop\b/i],
|
|
381
|
-
replacement: [/\binstead\s+of\b/i, /\brather\s+than\b/i, /\breplace\b.*\bwith\b/i, /\bswitch\s+(from|to)\b/i],
|
|
382
|
-
opposition: [/\bhowever\b/i, /\bbut\b/i, /\bcontra/i, /\boppos/i],
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Detect if two texts express conflicting conclusions.
|
|
387
|
-
* Uses keyword-based sentiment analysis (no LLM needed).
|
|
388
|
-
*
|
|
389
|
-
* Returns true if text B appears to contradict text A.
|
|
390
|
-
*/
|
|
391
|
-
export function detectSentimentConflict(textA: string, textB: string): boolean {
|
|
392
|
-
const lowerB = textB.toLowerCase();
|
|
393
|
-
const lowerA = textA.toLowerCase();
|
|
394
|
-
|
|
395
|
-
// Check if B contains negation of key terms from A
|
|
396
|
-
const aWords = extractKeyTerms(lowerA);
|
|
397
|
-
const bWords = extractKeyTerms(lowerB);
|
|
398
|
-
|
|
399
|
-
// If B negates something A asserts
|
|
400
|
-
for (const patterns of Object.values(CONTRADICTION_KEYWORDS)) {
|
|
401
|
-
for (const pattern of patterns) {
|
|
402
|
-
if (pattern.test(textB)) {
|
|
403
|
-
// B has negation/replacement language
|
|
404
|
-
// Check if they share subject matter (at least 2 common key terms)
|
|
405
|
-
const commonTerms = aWords.filter(w => bWords.includes(w));
|
|
406
|
-
if (commonTerms.length >= 2) return true;
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
return false;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function extractKeyTerms(text: string): string[] {
|
|
415
|
-
const stopWords = new Set(['the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been',
|
|
416
|
-
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'we', 'should', 'it',
|
|
417
|
-
'this', 'that', 'and', 'or', 'but', 'not', 'do', 'does', 'did', 'has', 'have', 'had']);
|
|
418
|
-
return text.split(/\W+/).filter(w => w.length > 2 && !stopWords.has(w));
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
export const CONTRADICTION_COSINE_THRESHOLD = 0.80;
|
|
422
|
-
export const DEDUP_COSINE_THRESHOLD = 0.90;
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
- [ ] **Step 3: Run tests, commit**
|
|
426
|
-
|
|
427
|
-
```bash
|
|
428
|
-
git commit -m "feat(cortex): add ingestion-time contradiction detection"
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
---
|
|
432
|
-
|
|
433
|
-
### Task 4: Stale knowledge decay
|
|
434
|
-
|
|
435
|
-
**Files:**
|
|
436
|
-
- Create: `src/lib/cortex/gravity/decay.ts`
|
|
437
|
-
- Create: `tests/lib/cortex/gravity/decay.test.ts`
|
|
438
|
-
|
|
439
|
-
- [ ] **Step 1: Write failing tests**
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
// tests/lib/cortex/gravity/decay.test.ts
|
|
443
|
-
import { describe, it, expect } from 'vitest';
|
|
444
|
-
import { computeDecay, shouldArchive, ARCHIVE_THRESHOLD } from '@/lib/cortex/gravity/decay';
|
|
445
|
-
|
|
446
|
-
describe('computeDecay', () => {
|
|
447
|
-
it('returns 0 decay for recently accessed knowledge', () => {
|
|
448
|
-
expect(computeDecay({ daysSinceAccess: 5, currentEvidenceScore: 0.8 })).toBeCloseTo(0);
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
it('returns small decay for moderately old knowledge', () => {
|
|
452
|
-
const decay = computeDecay({ daysSinceAccess: 60, currentEvidenceScore: 0.8 });
|
|
453
|
-
expect(decay).toBeGreaterThan(0);
|
|
454
|
-
expect(decay).toBeLessThan(0.2);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
it('returns larger decay for very old knowledge', () => {
|
|
458
|
-
const moderate = computeDecay({ daysSinceAccess: 60, currentEvidenceScore: 0.8 });
|
|
459
|
-
const old = computeDecay({ daysSinceAccess: 180, currentEvidenceScore: 0.8 });
|
|
460
|
-
expect(old).toBeGreaterThan(moderate);
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
it('never makes evidence score negative', () => {
|
|
464
|
-
const decay = computeDecay({ daysSinceAccess: 365, currentEvidenceScore: 0.1 });
|
|
465
|
-
expect(0.1 - decay).toBeGreaterThanOrEqual(0);
|
|
466
|
-
});
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
describe('shouldArchive', () => {
|
|
470
|
-
it('archives units with evidence below threshold after 6 months', () => {
|
|
471
|
-
expect(shouldArchive({ evidenceScore: 0.05, daysSinceCreated: 200 })).toBe(true);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it('does not archive recent units even with low evidence', () => {
|
|
475
|
-
expect(shouldArchive({ evidenceScore: 0.05, daysSinceCreated: 30 })).toBe(false);
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
it('does not archive units above threshold', () => {
|
|
479
|
-
expect(shouldArchive({ evidenceScore: 0.5, daysSinceCreated: 200 })).toBe(false);
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
it('uses ARCHIVE_THRESHOLD of 0.1', () => {
|
|
483
|
-
expect(ARCHIVE_THRESHOLD).toBe(0.1);
|
|
484
|
-
});
|
|
485
|
-
});
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
- [ ] **Step 2: Implement decay**
|
|
489
|
-
|
|
490
|
-
```typescript
|
|
491
|
-
// src/lib/cortex/gravity/decay.ts
|
|
492
|
-
|
|
493
|
-
export const ARCHIVE_THRESHOLD = 0.1;
|
|
494
|
-
const ARCHIVE_MIN_AGE_DAYS = 180; // 6 months
|
|
495
|
-
const DECAY_START_DAYS = 30; // no decay within first 30 days of last access
|
|
496
|
-
|
|
497
|
-
interface DecayInput {
|
|
498
|
-
daysSinceAccess: number;
|
|
499
|
-
currentEvidenceScore: number;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Compute evidence score decay for unaccessed knowledge.
|
|
504
|
-
* Returns the amount to SUBTRACT from evidence_score.
|
|
505
|
-
*
|
|
506
|
-
* Decay formula: gradual increase after 30 days of no access.
|
|
507
|
-
* decay = max(0, (daysSinceAccess - 30) / 365) * 0.2
|
|
508
|
-
* Capped so evidence never goes below 0.
|
|
509
|
-
*/
|
|
510
|
-
export function computeDecay(input: DecayInput): number {
|
|
511
|
-
const { daysSinceAccess, currentEvidenceScore } = input;
|
|
512
|
-
|
|
513
|
-
if (daysSinceAccess <= DECAY_START_DAYS) return 0;
|
|
514
|
-
|
|
515
|
-
const rawDecay = ((daysSinceAccess - DECAY_START_DAYS) / 365) * 0.2;
|
|
516
|
-
return Math.min(rawDecay, currentEvidenceScore); // never go below 0
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
interface ArchiveCheck {
|
|
520
|
-
evidenceScore: number;
|
|
521
|
-
daysSinceCreated: number;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
* Determine if a knowledge unit should be archived.
|
|
526
|
-
* Archived when evidence < ARCHIVE_THRESHOLD and older than 6 months.
|
|
527
|
-
*/
|
|
528
|
-
export function shouldArchive(check: ArchiveCheck): boolean {
|
|
529
|
-
return check.evidenceScore < ARCHIVE_THRESHOLD && check.daysSinceCreated >= ARCHIVE_MIN_AGE_DAYS;
|
|
530
|
-
}
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
- [ ] **Step 3: Run tests, commit**
|
|
534
|
-
|
|
535
|
-
```bash
|
|
536
|
-
git commit -m "feat(cortex): add knowledge decay and archival logic"
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
---
|
|
540
|
-
|
|
541
|
-
## Chunk 3: Gravity Scheduler and Integration
|
|
542
|
-
|
|
543
|
-
### Task 5: Gravity scheduler
|
|
544
|
-
|
|
545
|
-
**Files:**
|
|
546
|
-
- Create: `src/lib/cortex/gravity/scheduler.ts`
|
|
547
|
-
- Create: `tests/lib/cortex/gravity/scheduler.test.ts`
|
|
548
|
-
|
|
549
|
-
- [ ] **Step 1: Write failing tests**
|
|
550
|
-
|
|
551
|
-
```typescript
|
|
552
|
-
// tests/lib/cortex/gravity/scheduler.test.ts
|
|
553
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
554
|
-
import { GravityScheduler } from '@/lib/cortex/gravity/scheduler';
|
|
555
|
-
|
|
556
|
-
describe('GravityScheduler', () => {
|
|
557
|
-
let scheduler: GravityScheduler;
|
|
558
|
-
const mockRunCycle = vi.fn().mockResolvedValue(undefined);
|
|
559
|
-
|
|
560
|
-
beforeEach(() => {
|
|
561
|
-
vi.useFakeTimers();
|
|
562
|
-
scheduler = new GravityScheduler({
|
|
563
|
-
intervalMs: 1000, // 1 second for testing (real: 6 hours)
|
|
564
|
-
runCycle: mockRunCycle,
|
|
565
|
-
});
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
afterEach(() => {
|
|
569
|
-
scheduler.stop();
|
|
570
|
-
vi.useRealTimers();
|
|
571
|
-
});
|
|
572
|
-
|
|
573
|
-
it('starts and runs the first cycle', async () => {
|
|
574
|
-
scheduler.start();
|
|
575
|
-
expect(scheduler.isRunning()).toBe(true);
|
|
576
|
-
// First cycle runs immediately
|
|
577
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
578
|
-
expect(mockRunCycle).toHaveBeenCalledTimes(1);
|
|
579
|
-
});
|
|
580
|
-
|
|
581
|
-
it('runs on interval', async () => {
|
|
582
|
-
scheduler.start();
|
|
583
|
-
await vi.advanceTimersByTimeAsync(10); // first immediate run
|
|
584
|
-
await vi.advanceTimersByTimeAsync(1000); // second interval run
|
|
585
|
-
expect(mockRunCycle).toHaveBeenCalledTimes(2);
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
it('stops cleanly', async () => {
|
|
589
|
-
scheduler.start();
|
|
590
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
591
|
-
scheduler.stop();
|
|
592
|
-
expect(scheduler.isRunning()).toBe(false);
|
|
593
|
-
await vi.advanceTimersByTimeAsync(2000);
|
|
594
|
-
expect(mockRunCycle).toHaveBeenCalledTimes(1); // no more runs after stop
|
|
595
|
-
});
|
|
596
|
-
|
|
597
|
-
it('does not run concurrent cycles', async () => {
|
|
598
|
-
let resolveFirst: () => void;
|
|
599
|
-
const slowCycle = vi.fn().mockImplementation(() =>
|
|
600
|
-
new Promise<void>(resolve => { resolveFirst = resolve; })
|
|
601
|
-
);
|
|
602
|
-
const slow = new GravityScheduler({ intervalMs: 100, runCycle: slowCycle });
|
|
603
|
-
slow.start();
|
|
604
|
-
await vi.advanceTimersByTimeAsync(10); // starts first cycle
|
|
605
|
-
await vi.advanceTimersByTimeAsync(200); // interval fires but first still running
|
|
606
|
-
expect(slowCycle).toHaveBeenCalledTimes(1);
|
|
607
|
-
resolveFirst!();
|
|
608
|
-
slow.stop();
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
it('handles cycle errors without crashing', async () => {
|
|
612
|
-
const failingCycle = vi.fn().mockRejectedValue(new Error('cycle failed'));
|
|
613
|
-
const failing = new GravityScheduler({ intervalMs: 1000, runCycle: failingCycle });
|
|
614
|
-
failing.start();
|
|
615
|
-
await vi.advanceTimersByTimeAsync(10);
|
|
616
|
-
expect(failing.isRunning()).toBe(true); // still running despite error
|
|
617
|
-
failing.stop();
|
|
618
|
-
});
|
|
619
|
-
});
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
- [ ] **Step 2: Implement scheduler**
|
|
623
|
-
|
|
624
|
-
```typescript
|
|
625
|
-
// src/lib/cortex/gravity/scheduler.ts
|
|
626
|
-
|
|
627
|
-
export const GRAVITY_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
628
|
-
|
|
629
|
-
export interface GravitySchedulerConfig {
|
|
630
|
-
intervalMs?: number;
|
|
631
|
-
runCycle: () => Promise<void>;
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
export class GravityScheduler {
|
|
635
|
-
private timer: ReturnType<typeof setInterval> | null = null;
|
|
636
|
-
private running = false;
|
|
637
|
-
private cycling = false;
|
|
638
|
-
private config: Required<GravitySchedulerConfig>;
|
|
639
|
-
|
|
640
|
-
constructor(config: GravitySchedulerConfig) {
|
|
641
|
-
this.config = {
|
|
642
|
-
intervalMs: config.intervalMs ?? GRAVITY_INTERVAL_MS,
|
|
643
|
-
runCycle: config.runCycle,
|
|
644
|
-
};
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
start(): void {
|
|
648
|
-
if (this.running) return;
|
|
649
|
-
this.running = true;
|
|
650
|
-
|
|
651
|
-
// Run first cycle immediately (non-blocking)
|
|
652
|
-
this.executeCycle();
|
|
653
|
-
|
|
654
|
-
// Schedule recurring cycles
|
|
655
|
-
this.timer = setInterval(() => this.executeCycle(), this.config.intervalMs);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
stop(): void {
|
|
659
|
-
this.running = false;
|
|
660
|
-
if (this.timer) {
|
|
661
|
-
clearInterval(this.timer);
|
|
662
|
-
this.timer = null;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
isRunning(): boolean {
|
|
667
|
-
return this.running;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
private async executeCycle(): Promise<void> {
|
|
671
|
-
if (this.cycling) return; // prevent concurrent cycles
|
|
672
|
-
this.cycling = true;
|
|
673
|
-
try {
|
|
674
|
-
await this.config.runCycle();
|
|
675
|
-
} catch {
|
|
676
|
-
// Log but don't crash — scheduler continues
|
|
677
|
-
} finally {
|
|
678
|
-
this.cycling = false;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
- [ ] **Step 3: Run tests, commit**
|
|
685
|
-
|
|
686
|
-
```bash
|
|
687
|
-
git commit -m "feat(cortex): add gravity scheduler with interval execution"
|
|
688
|
-
```
|
|
689
|
-
|
|
690
|
-
---
|
|
691
|
-
|
|
692
|
-
### Task 6: Barrel export and CortexInstance integration
|
|
693
|
-
|
|
694
|
-
**Files:**
|
|
695
|
-
- Create: `src/lib/cortex/gravity/index.ts`
|
|
696
|
-
- Modify: `src/lib/cortex/index.ts`
|
|
697
|
-
|
|
698
|
-
- [ ] **Step 1: Create barrel export**
|
|
699
|
-
|
|
700
|
-
```typescript
|
|
701
|
-
// src/lib/cortex/gravity/index.ts
|
|
702
|
-
export { computePromotionScore, shouldPromote, getNextLevel, HOP_DECAY, PROMOTION_TYPE_WEIGHTS } from './promotion';
|
|
703
|
-
export { getTrickleMode, TRICKLE_DEFAULTS } from './trickle';
|
|
704
|
-
export type { TrickleMode } from './trickle';
|
|
705
|
-
export { detectSentimentConflict, CONTRADICTION_COSINE_THRESHOLD, DEDUP_COSINE_THRESHOLD } from './contradiction';
|
|
706
|
-
export { computeDecay, shouldArchive, ARCHIVE_THRESHOLD } from './decay';
|
|
707
|
-
export { GravityScheduler, GRAVITY_INTERVAL_MS } from './scheduler';
|
|
708
|
-
export type { GravitySchedulerConfig } from './scheduler';
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
- [ ] **Step 2: Add GravityScheduler to CortexInstance**
|
|
712
|
-
|
|
713
|
-
Read `src/lib/cortex/index.ts`. Add:
|
|
714
|
-
|
|
715
|
-
1. Import: `import { GravityScheduler } from './gravity/scheduler';`
|
|
716
|
-
2. Add `gravityScheduler?: GravityScheduler` to CortexInstance interface
|
|
717
|
-
3. In getCortex(), after signalPipeline initialization:
|
|
718
|
-
|
|
719
|
-
```typescript
|
|
720
|
-
const gravityScheduler = new GravityScheduler({
|
|
721
|
-
runCycle: async () => {
|
|
722
|
-
// Gravity cycle placeholder — full implementation requires
|
|
723
|
-
// scanning all knowledge units, computing promotion scores,
|
|
724
|
-
// executing trickle-down, decaying stale knowledge, etc.
|
|
725
|
-
// Individual functions are ready; the orchestration wiring
|
|
726
|
-
// will be connected when the system has enough data to test.
|
|
727
|
-
},
|
|
728
|
-
});
|
|
729
|
-
// Don't auto-start — let the application decide when to start
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
4. Include `gravityScheduler` in instance object
|
|
733
|
-
5. In `resetCortex()`, add `_instance.gravityScheduler?.stop()` before nulling
|
|
734
|
-
|
|
735
|
-
- [ ] **Step 3: Run full test suite**
|
|
736
|
-
|
|
737
|
-
```bash
|
|
738
|
-
npx vitest run tests/lib/cortex/
|
|
739
|
-
```
|
|
740
|
-
|
|
741
|
-
- [ ] **Step 4: Commit**
|
|
742
|
-
|
|
743
|
-
```bash
|
|
744
|
-
git commit -m "feat(cortex): add gravity module barrel export and CortexInstance integration"
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
---
|
|
748
|
-
|
|
749
|
-
## Summary
|
|
750
|
-
|
|
751
|
-
| Task | Component | Tests | Status |
|
|
752
|
-
|------|-----------|-------|--------|
|
|
753
|
-
| 1 | Promotion (bubble-up) | 8 | |
|
|
754
|
-
| 2 | Trickle-down | 6 | |
|
|
755
|
-
| 3 | Contradiction detection | 5 | |
|
|
756
|
-
| 4 | Decay + archival | 8 | |
|
|
757
|
-
| 5 | Gravity scheduler | 5 | |
|
|
758
|
-
| 6 | Barrel export + integration | regression | |
|
|
759
|
-
|
|
760
|
-
**Total: 6 tasks, ~32 new tests, 3 chunks**
|
|
761
|
-
|
|
762
|
-
**Key design decisions:**
|
|
763
|
-
- Promotion is COPY (not move) — original stays, promoted copy gets decayed confidence (×0.85)
|
|
764
|
-
- Trickle-down has two modes: PUSH (copies to lower scopes) and VISIBILITY (accessible via graph but not copied)
|
|
765
|
-
- Contradiction detection uses keyword-based sentiment analysis (not LLM) — fast and deterministic
|
|
766
|
-
- Decay is gradual — starts after 30 days of no access, increases over time, archives below 0.1 after 6 months
|
|
767
|
-
- Scheduler uses setInterval (consistent with FederationSync pattern), prevents concurrent cycles, survives errors
|
|
768
|
-
- The runCycle body is a placeholder — individual gravity functions are ready but the full orchestration loop connecting them to store iteration will be wired when there's enough data to test against
|
|
1
|
+
# Cortex v2 — Pillar 6: Gravity System
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Implement bi-directional knowledge flow — evidence-based bubble-up promotion, decision trickle-down, conflict detection during ingestion, stale knowledge decay, and a background gravity scheduler that runs every 6 hours.
|
|
6
|
+
|
|
7
|
+
**Architecture:** A new `src/lib/cortex/gravity/` module with four components: `promotion.ts` (bubble-up logic), `trickle.ts` (push-down logic), `contradiction.ts` (ingestion-time conflict detection), and `scheduler.ts` (background timer orchestrating all gravity operations). Uses the `gravity_state` SQLite table (created in Pillar 1) for checkpoint persistence.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, better-sqlite3, LanceDB, vitest
|
|
10
|
+
|
|
11
|
+
**Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 6
|
|
12
|
+
|
|
13
|
+
**Depends on:** All previous pillars (1-5) — completed
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## File Structure
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
New files:
|
|
21
|
+
├── src/lib/cortex/gravity/promotion.ts — Bubble-up: evidence-based promotion
|
|
22
|
+
├── src/lib/cortex/gravity/trickle.ts — Trickle-down: decision push + visibility
|
|
23
|
+
├── src/lib/cortex/gravity/contradiction.ts — Ingestion-time conflict detection
|
|
24
|
+
├── src/lib/cortex/gravity/decay.ts — Stale knowledge decay + archival
|
|
25
|
+
├── src/lib/cortex/gravity/scheduler.ts — Background scheduler (setInterval)
|
|
26
|
+
├── src/lib/cortex/gravity/index.ts — Barrel export
|
|
27
|
+
|
|
28
|
+
Modified files:
|
|
29
|
+
├── src/lib/cortex/index.ts — Add GravityScheduler to CortexInstance
|
|
30
|
+
|
|
31
|
+
Test files:
|
|
32
|
+
├── tests/lib/cortex/gravity/promotion.test.ts
|
|
33
|
+
├── tests/lib/cortex/gravity/trickle.test.ts
|
|
34
|
+
├── tests/lib/cortex/gravity/contradiction.test.ts
|
|
35
|
+
├── tests/lib/cortex/gravity/decay.test.ts
|
|
36
|
+
├── tests/lib/cortex/gravity/scheduler.test.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Chunk 1: Promotion and Trickle-Down
|
|
42
|
+
|
|
43
|
+
### Task 1: Bubble-up promotion logic
|
|
44
|
+
|
|
45
|
+
**Files:**
|
|
46
|
+
- Create: `src/lib/cortex/gravity/promotion.ts`
|
|
47
|
+
- Create: `tests/lib/cortex/gravity/promotion.test.ts`
|
|
48
|
+
|
|
49
|
+
- [ ] **Step 1: Write failing tests**
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// tests/lib/cortex/gravity/promotion.test.ts
|
|
53
|
+
import { describe, it, expect } from 'vitest';
|
|
54
|
+
import {
|
|
55
|
+
computePromotionScore,
|
|
56
|
+
shouldPromote,
|
|
57
|
+
PROMOTION_TYPE_WEIGHTS,
|
|
58
|
+
} from '@/lib/cortex/gravity/promotion';
|
|
59
|
+
|
|
60
|
+
describe('computePromotionScore', () => {
|
|
61
|
+
it('computes score from evidence, type weight, and freshness', () => {
|
|
62
|
+
const score = computePromotionScore({
|
|
63
|
+
evidenceScore: 0.8,
|
|
64
|
+
type: 'decision',
|
|
65
|
+
createdDaysAgo: 10,
|
|
66
|
+
});
|
|
67
|
+
// 0.8 * 1.5 (decision weight) * 1.0 (< 30 days) = 1.2 → capped at 1.0
|
|
68
|
+
expect(score).toBeLessThanOrEqual(1.0);
|
|
69
|
+
expect(score).toBeGreaterThan(0.5);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('applies type weights correctly', () => {
|
|
73
|
+
const decision = computePromotionScore({ evidenceScore: 0.5, type: 'decision', createdDaysAgo: 10 });
|
|
74
|
+
const conversation = computePromotionScore({ evidenceScore: 0.5, type: 'conversation', createdDaysAgo: 10 });
|
|
75
|
+
expect(decision).toBeGreaterThan(conversation);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('decays with age', () => {
|
|
79
|
+
const recent = computePromotionScore({ evidenceScore: 0.8, type: 'pattern', createdDaysAgo: 5 });
|
|
80
|
+
const old = computePromotionScore({ evidenceScore: 0.8, type: 'pattern', createdDaysAgo: 120 });
|
|
81
|
+
expect(recent).toBeGreaterThan(old);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('shouldPromote', () => {
|
|
86
|
+
it('promotes personal→team when score and corroborations meet threshold', () => {
|
|
87
|
+
expect(shouldPromote({
|
|
88
|
+
currentLevel: 'personal',
|
|
89
|
+
promotionScore: 0.7,
|
|
90
|
+
corroborations: 3,
|
|
91
|
+
sensitivity: 'internal',
|
|
92
|
+
hasContradictions: false,
|
|
93
|
+
})).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('blocks promotion when sensitivity is restricted', () => {
|
|
97
|
+
expect(shouldPromote({
|
|
98
|
+
currentLevel: 'personal',
|
|
99
|
+
promotionScore: 0.7,
|
|
100
|
+
corroborations: 3,
|
|
101
|
+
sensitivity: 'restricted',
|
|
102
|
+
hasContradictions: false,
|
|
103
|
+
})).toBe(false);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('blocks promotion when corroborations insufficient', () => {
|
|
107
|
+
expect(shouldPromote({
|
|
108
|
+
currentLevel: 'personal',
|
|
109
|
+
promotionScore: 0.7,
|
|
110
|
+
corroborations: 1, // needs ≥ 2
|
|
111
|
+
sensitivity: 'internal',
|
|
112
|
+
hasContradictions: false,
|
|
113
|
+
})).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('blocks dept→org promotion when contradictions exist', () => {
|
|
117
|
+
expect(shouldPromote({
|
|
118
|
+
currentLevel: 'department',
|
|
119
|
+
promotionScore: 0.95,
|
|
120
|
+
corroborations: 6,
|
|
121
|
+
sensitivity: 'internal',
|
|
122
|
+
hasContradictions: true,
|
|
123
|
+
})).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('requires higher thresholds for higher promotions', () => {
|
|
127
|
+
// Score 0.65 passes personal→team but not team→dept
|
|
128
|
+
expect(shouldPromote({
|
|
129
|
+
currentLevel: 'personal', promotionScore: 0.65, corroborations: 2,
|
|
130
|
+
sensitivity: 'internal', hasContradictions: false,
|
|
131
|
+
})).toBe(true);
|
|
132
|
+
|
|
133
|
+
expect(shouldPromote({
|
|
134
|
+
currentLevel: 'team', promotionScore: 0.65, corroborations: 3,
|
|
135
|
+
sensitivity: 'internal', hasContradictions: false,
|
|
136
|
+
})).toBe(false); // needs ≥ 0.75
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- [ ] **Step 2: Implement promotion logic**
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// src/lib/cortex/gravity/promotion.ts
|
|
145
|
+
import type { KnowledgeType, ScopeLevel, SensitivityClass } from '../knowledge/types';
|
|
146
|
+
|
|
147
|
+
export const PROMOTION_TYPE_WEIGHTS: Record<string, number> = {
|
|
148
|
+
decision: 1.5,
|
|
149
|
+
error_fix: 1.3,
|
|
150
|
+
pattern: 1.2,
|
|
151
|
+
preference: 1.0,
|
|
152
|
+
code_pattern: 1.0,
|
|
153
|
+
command: 0.8,
|
|
154
|
+
context: 0.7,
|
|
155
|
+
summary: 0.7,
|
|
156
|
+
conversation: 0.5,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const FRESHNESS_THRESHOLDS = [
|
|
160
|
+
{ maxDays: 30, multiplier: 1.0 },
|
|
161
|
+
{ maxDays: 90, multiplier: 0.8 },
|
|
162
|
+
{ maxDays: Infinity, multiplier: 0.5 },
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
interface PromotionScoreInput {
|
|
166
|
+
evidenceScore: number;
|
|
167
|
+
type: string;
|
|
168
|
+
createdDaysAgo: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function computePromotionScore(input: PromotionScoreInput): number {
|
|
172
|
+
const typeWeight = PROMOTION_TYPE_WEIGHTS[input.type] ?? 1.0;
|
|
173
|
+
const freshness = FRESHNESS_THRESHOLDS.find(t => input.createdDaysAgo <= t.maxDays)?.multiplier ?? 0.5;
|
|
174
|
+
return Math.min(1.0, input.evidenceScore * typeWeight * freshness);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
interface PromotionCheck {
|
|
178
|
+
currentLevel: ScopeLevel;
|
|
179
|
+
promotionScore: number;
|
|
180
|
+
corroborations: number;
|
|
181
|
+
sensitivity: string;
|
|
182
|
+
hasContradictions: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const PROMOTION_THRESHOLDS: Record<string, { minScore: number; minCorroborations: number; noContradictions?: boolean }> = {
|
|
186
|
+
personal: { minScore: 0.6, minCorroborations: 2 },
|
|
187
|
+
team: { minScore: 0.75, minCorroborations: 3 },
|
|
188
|
+
department: { minScore: 0.9, minCorroborations: 5, noContradictions: true },
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const NEXT_LEVEL: Record<string, ScopeLevel> = {
|
|
192
|
+
personal: 'team',
|
|
193
|
+
team: 'department',
|
|
194
|
+
department: 'organization',
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export function shouldPromote(check: PromotionCheck): boolean {
|
|
198
|
+
const threshold = PROMOTION_THRESHOLDS[check.currentLevel];
|
|
199
|
+
if (!threshold) return false; // organization can't promote further
|
|
200
|
+
|
|
201
|
+
if (check.sensitivity === 'restricted' || check.sensitivity === 'confidential') return false;
|
|
202
|
+
if (check.promotionScore < threshold.minScore) return false;
|
|
203
|
+
if (check.corroborations < threshold.minCorroborations) return false;
|
|
204
|
+
if (threshold.noContradictions && check.hasContradictions) return false;
|
|
205
|
+
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function getNextLevel(current: ScopeLevel): ScopeLevel | null {
|
|
210
|
+
return NEXT_LEVEL[current] ?? null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const HOP_DECAY = 0.85;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
- [ ] **Step 3: Run tests, commit**
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
git commit -m "feat(cortex): add evidence-based promotion logic for gravity system"
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### Task 2: Trickle-down logic
|
|
225
|
+
|
|
226
|
+
**Files:**
|
|
227
|
+
- Create: `src/lib/cortex/gravity/trickle.ts`
|
|
228
|
+
- Create: `tests/lib/cortex/gravity/trickle.test.ts`
|
|
229
|
+
|
|
230
|
+
- [ ] **Step 1: Write failing tests**
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// tests/lib/cortex/gravity/trickle.test.ts
|
|
234
|
+
import { describe, it, expect } from 'vitest';
|
|
235
|
+
import { getTrickleMode, TRICKLE_DEFAULTS } from '@/lib/cortex/gravity/trickle';
|
|
236
|
+
|
|
237
|
+
describe('getTrickleMode', () => {
|
|
238
|
+
it('returns PUSH for org decisions', () => {
|
|
239
|
+
expect(getTrickleMode('decision', 'organization')).toBe('push');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('returns PUSH for security policies', () => {
|
|
243
|
+
expect(getTrickleMode('error_fix', 'organization', ['security'])).toBe('push');
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('returns VISIBILITY for best practices', () => {
|
|
247
|
+
expect(getTrickleMode('pattern', 'organization')).toBe('visibility');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('returns VISIBILITY for general patterns', () => {
|
|
251
|
+
expect(getTrickleMode('conversation', 'organization')).toBe('visibility');
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('returns null for non-org scopes', () => {
|
|
255
|
+
expect(getTrickleMode('decision', 'team')).toBeNull();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('exports trickle defaults table', () => {
|
|
259
|
+
expect(TRICKLE_DEFAULTS).toBeDefined();
|
|
260
|
+
expect(TRICKLE_DEFAULTS.decision).toBe('push');
|
|
261
|
+
expect(TRICKLE_DEFAULTS.pattern).toBe('visibility');
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
- [ ] **Step 2: Implement trickle-down**
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// src/lib/cortex/gravity/trickle.ts
|
|
270
|
+
import type { KnowledgeType, ScopeLevel } from '../knowledge/types';
|
|
271
|
+
|
|
272
|
+
export type TrickleMode = 'push' | 'visibility';
|
|
273
|
+
|
|
274
|
+
export const TRICKLE_DEFAULTS: Record<string, TrickleMode> = {
|
|
275
|
+
decision: 'push',
|
|
276
|
+
preference: 'push',
|
|
277
|
+
error_fix: 'visibility',
|
|
278
|
+
pattern: 'visibility',
|
|
279
|
+
code_pattern: 'visibility',
|
|
280
|
+
command: 'visibility',
|
|
281
|
+
context: 'visibility',
|
|
282
|
+
conversation: 'visibility',
|
|
283
|
+
summary: 'visibility',
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const SECURITY_TOPICS = ['security', 'vulnerability', 'exploit', 'cve', 'incident'];
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Determine trickle mode for knowledge at a given scope.
|
|
290
|
+
* Only org-level knowledge trickles down.
|
|
291
|
+
* Returns null if knowledge shouldn't trickle (not at org scope).
|
|
292
|
+
*/
|
|
293
|
+
export function getTrickleMode(
|
|
294
|
+
type: string,
|
|
295
|
+
scopeLevel: string,
|
|
296
|
+
topics?: string[],
|
|
297
|
+
): TrickleMode | null {
|
|
298
|
+
// Only org-level knowledge trickles down
|
|
299
|
+
if (scopeLevel !== 'organization') return null;
|
|
300
|
+
|
|
301
|
+
// Security topics always push
|
|
302
|
+
if (topics?.some(t => SECURITY_TOPICS.includes(t.toLowerCase()))) {
|
|
303
|
+
return 'push';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return TRICKLE_DEFAULTS[type] ?? 'visibility';
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
- [ ] **Step 3: Run tests, commit**
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
git commit -m "feat(cortex): add trickle-down logic for gravity system"
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Chunk 2: Contradiction Detection and Decay
|
|
319
|
+
|
|
320
|
+
### Task 3: Ingestion-time contradiction detection
|
|
321
|
+
|
|
322
|
+
**Files:**
|
|
323
|
+
- Create: `src/lib/cortex/gravity/contradiction.ts`
|
|
324
|
+
- Create: `tests/lib/cortex/gravity/contradiction.test.ts`
|
|
325
|
+
|
|
326
|
+
- [ ] **Step 1: Write failing tests**
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// tests/lib/cortex/gravity/contradiction.test.ts
|
|
330
|
+
import { describe, it, expect } from 'vitest';
|
|
331
|
+
import {
|
|
332
|
+
detectSentimentConflict,
|
|
333
|
+
CONTRADICTION_KEYWORDS,
|
|
334
|
+
} from '@/lib/cortex/gravity/contradiction';
|
|
335
|
+
|
|
336
|
+
describe('detectSentimentConflict', () => {
|
|
337
|
+
it('detects opposing sentiments', () => {
|
|
338
|
+
expect(detectSentimentConflict(
|
|
339
|
+
'increase connection pool size to 50',
|
|
340
|
+
'do NOT increase pool size, scale horizontally instead',
|
|
341
|
+
)).toBe(true);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('returns false for agreeing statements', () => {
|
|
345
|
+
expect(detectSentimentConflict(
|
|
346
|
+
'use PostgreSQL for the new service',
|
|
347
|
+
'PostgreSQL is the right choice for reliability',
|
|
348
|
+
)).toBe(false);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('detects negation patterns', () => {
|
|
352
|
+
expect(detectSentimentConflict(
|
|
353
|
+
'we should use Redis for caching',
|
|
354
|
+
'we should not use Redis for caching',
|
|
355
|
+
)).toBe(true);
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
it('detects replacement/alternative patterns', () => {
|
|
359
|
+
expect(detectSentimentConflict(
|
|
360
|
+
'use Express for the API',
|
|
361
|
+
'use Fastify instead of Express',
|
|
362
|
+
)).toBe(true);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('returns false for unrelated statements', () => {
|
|
366
|
+
expect(detectSentimentConflict(
|
|
367
|
+
'the auth service handles JWT',
|
|
368
|
+
'deploy to production on Fridays',
|
|
369
|
+
)).toBe(false);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
- [ ] **Step 2: Implement contradiction detection**
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
// src/lib/cortex/gravity/contradiction.ts
|
|
378
|
+
|
|
379
|
+
export const CONTRADICTION_KEYWORDS = {
|
|
380
|
+
negation: [/\bnot\b/i, /\bdon't\b/i, /\bdo\s+not\b/i, /\bnever\b/i, /\bavoid\b/i, /\bstop\b/i],
|
|
381
|
+
replacement: [/\binstead\s+of\b/i, /\brather\s+than\b/i, /\breplace\b.*\bwith\b/i, /\bswitch\s+(from|to)\b/i],
|
|
382
|
+
opposition: [/\bhowever\b/i, /\bbut\b/i, /\bcontra/i, /\boppos/i],
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Detect if two texts express conflicting conclusions.
|
|
387
|
+
* Uses keyword-based sentiment analysis (no LLM needed).
|
|
388
|
+
*
|
|
389
|
+
* Returns true if text B appears to contradict text A.
|
|
390
|
+
*/
|
|
391
|
+
export function detectSentimentConflict(textA: string, textB: string): boolean {
|
|
392
|
+
const lowerB = textB.toLowerCase();
|
|
393
|
+
const lowerA = textA.toLowerCase();
|
|
394
|
+
|
|
395
|
+
// Check if B contains negation of key terms from A
|
|
396
|
+
const aWords = extractKeyTerms(lowerA);
|
|
397
|
+
const bWords = extractKeyTerms(lowerB);
|
|
398
|
+
|
|
399
|
+
// If B negates something A asserts
|
|
400
|
+
for (const patterns of Object.values(CONTRADICTION_KEYWORDS)) {
|
|
401
|
+
for (const pattern of patterns) {
|
|
402
|
+
if (pattern.test(textB)) {
|
|
403
|
+
// B has negation/replacement language
|
|
404
|
+
// Check if they share subject matter (at least 2 common key terms)
|
|
405
|
+
const commonTerms = aWords.filter(w => bWords.includes(w));
|
|
406
|
+
if (commonTerms.length >= 2) return true;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function extractKeyTerms(text: string): string[] {
|
|
415
|
+
const stopWords = new Set(['the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been',
|
|
416
|
+
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'we', 'should', 'it',
|
|
417
|
+
'this', 'that', 'and', 'or', 'but', 'not', 'do', 'does', 'did', 'has', 'have', 'had']);
|
|
418
|
+
return text.split(/\W+/).filter(w => w.length > 2 && !stopWords.has(w));
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export const CONTRADICTION_COSINE_THRESHOLD = 0.80;
|
|
422
|
+
export const DEDUP_COSINE_THRESHOLD = 0.90;
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
- [ ] **Step 3: Run tests, commit**
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
git commit -m "feat(cortex): add ingestion-time contradiction detection"
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
### Task 4: Stale knowledge decay
|
|
434
|
+
|
|
435
|
+
**Files:**
|
|
436
|
+
- Create: `src/lib/cortex/gravity/decay.ts`
|
|
437
|
+
- Create: `tests/lib/cortex/gravity/decay.test.ts`
|
|
438
|
+
|
|
439
|
+
- [ ] **Step 1: Write failing tests**
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// tests/lib/cortex/gravity/decay.test.ts
|
|
443
|
+
import { describe, it, expect } from 'vitest';
|
|
444
|
+
import { computeDecay, shouldArchive, ARCHIVE_THRESHOLD } from '@/lib/cortex/gravity/decay';
|
|
445
|
+
|
|
446
|
+
describe('computeDecay', () => {
|
|
447
|
+
it('returns 0 decay for recently accessed knowledge', () => {
|
|
448
|
+
expect(computeDecay({ daysSinceAccess: 5, currentEvidenceScore: 0.8 })).toBeCloseTo(0);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('returns small decay for moderately old knowledge', () => {
|
|
452
|
+
const decay = computeDecay({ daysSinceAccess: 60, currentEvidenceScore: 0.8 });
|
|
453
|
+
expect(decay).toBeGreaterThan(0);
|
|
454
|
+
expect(decay).toBeLessThan(0.2);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
it('returns larger decay for very old knowledge', () => {
|
|
458
|
+
const moderate = computeDecay({ daysSinceAccess: 60, currentEvidenceScore: 0.8 });
|
|
459
|
+
const old = computeDecay({ daysSinceAccess: 180, currentEvidenceScore: 0.8 });
|
|
460
|
+
expect(old).toBeGreaterThan(moderate);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('never makes evidence score negative', () => {
|
|
464
|
+
const decay = computeDecay({ daysSinceAccess: 365, currentEvidenceScore: 0.1 });
|
|
465
|
+
expect(0.1 - decay).toBeGreaterThanOrEqual(0);
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
describe('shouldArchive', () => {
|
|
470
|
+
it('archives units with evidence below threshold after 6 months', () => {
|
|
471
|
+
expect(shouldArchive({ evidenceScore: 0.05, daysSinceCreated: 200 })).toBe(true);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it('does not archive recent units even with low evidence', () => {
|
|
475
|
+
expect(shouldArchive({ evidenceScore: 0.05, daysSinceCreated: 30 })).toBe(false);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
it('does not archive units above threshold', () => {
|
|
479
|
+
expect(shouldArchive({ evidenceScore: 0.5, daysSinceCreated: 200 })).toBe(false);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it('uses ARCHIVE_THRESHOLD of 0.1', () => {
|
|
483
|
+
expect(ARCHIVE_THRESHOLD).toBe(0.1);
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
- [ ] **Step 2: Implement decay**
|
|
489
|
+
|
|
490
|
+
```typescript
|
|
491
|
+
// src/lib/cortex/gravity/decay.ts
|
|
492
|
+
|
|
493
|
+
export const ARCHIVE_THRESHOLD = 0.1;
|
|
494
|
+
const ARCHIVE_MIN_AGE_DAYS = 180; // 6 months
|
|
495
|
+
const DECAY_START_DAYS = 30; // no decay within first 30 days of last access
|
|
496
|
+
|
|
497
|
+
interface DecayInput {
|
|
498
|
+
daysSinceAccess: number;
|
|
499
|
+
currentEvidenceScore: number;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Compute evidence score decay for unaccessed knowledge.
|
|
504
|
+
* Returns the amount to SUBTRACT from evidence_score.
|
|
505
|
+
*
|
|
506
|
+
* Decay formula: gradual increase after 30 days of no access.
|
|
507
|
+
* decay = max(0, (daysSinceAccess - 30) / 365) * 0.2
|
|
508
|
+
* Capped so evidence never goes below 0.
|
|
509
|
+
*/
|
|
510
|
+
export function computeDecay(input: DecayInput): number {
|
|
511
|
+
const { daysSinceAccess, currentEvidenceScore } = input;
|
|
512
|
+
|
|
513
|
+
if (daysSinceAccess <= DECAY_START_DAYS) return 0;
|
|
514
|
+
|
|
515
|
+
const rawDecay = ((daysSinceAccess - DECAY_START_DAYS) / 365) * 0.2;
|
|
516
|
+
return Math.min(rawDecay, currentEvidenceScore); // never go below 0
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
interface ArchiveCheck {
|
|
520
|
+
evidenceScore: number;
|
|
521
|
+
daysSinceCreated: number;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Determine if a knowledge unit should be archived.
|
|
526
|
+
* Archived when evidence < ARCHIVE_THRESHOLD and older than 6 months.
|
|
527
|
+
*/
|
|
528
|
+
export function shouldArchive(check: ArchiveCheck): boolean {
|
|
529
|
+
return check.evidenceScore < ARCHIVE_THRESHOLD && check.daysSinceCreated >= ARCHIVE_MIN_AGE_DAYS;
|
|
530
|
+
}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
- [ ] **Step 3: Run tests, commit**
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
git commit -m "feat(cortex): add knowledge decay and archival logic"
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Chunk 3: Gravity Scheduler and Integration
|
|
542
|
+
|
|
543
|
+
### Task 5: Gravity scheduler
|
|
544
|
+
|
|
545
|
+
**Files:**
|
|
546
|
+
- Create: `src/lib/cortex/gravity/scheduler.ts`
|
|
547
|
+
- Create: `tests/lib/cortex/gravity/scheduler.test.ts`
|
|
548
|
+
|
|
549
|
+
- [ ] **Step 1: Write failing tests**
|
|
550
|
+
|
|
551
|
+
```typescript
|
|
552
|
+
// tests/lib/cortex/gravity/scheduler.test.ts
|
|
553
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
554
|
+
import { GravityScheduler } from '@/lib/cortex/gravity/scheduler';
|
|
555
|
+
|
|
556
|
+
describe('GravityScheduler', () => {
|
|
557
|
+
let scheduler: GravityScheduler;
|
|
558
|
+
const mockRunCycle = vi.fn().mockResolvedValue(undefined);
|
|
559
|
+
|
|
560
|
+
beforeEach(() => {
|
|
561
|
+
vi.useFakeTimers();
|
|
562
|
+
scheduler = new GravityScheduler({
|
|
563
|
+
intervalMs: 1000, // 1 second for testing (real: 6 hours)
|
|
564
|
+
runCycle: mockRunCycle,
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
afterEach(() => {
|
|
569
|
+
scheduler.stop();
|
|
570
|
+
vi.useRealTimers();
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it('starts and runs the first cycle', async () => {
|
|
574
|
+
scheduler.start();
|
|
575
|
+
expect(scheduler.isRunning()).toBe(true);
|
|
576
|
+
// First cycle runs immediately
|
|
577
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
578
|
+
expect(mockRunCycle).toHaveBeenCalledTimes(1);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
it('runs on interval', async () => {
|
|
582
|
+
scheduler.start();
|
|
583
|
+
await vi.advanceTimersByTimeAsync(10); // first immediate run
|
|
584
|
+
await vi.advanceTimersByTimeAsync(1000); // second interval run
|
|
585
|
+
expect(mockRunCycle).toHaveBeenCalledTimes(2);
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
it('stops cleanly', async () => {
|
|
589
|
+
scheduler.start();
|
|
590
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
591
|
+
scheduler.stop();
|
|
592
|
+
expect(scheduler.isRunning()).toBe(false);
|
|
593
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
594
|
+
expect(mockRunCycle).toHaveBeenCalledTimes(1); // no more runs after stop
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
it('does not run concurrent cycles', async () => {
|
|
598
|
+
let resolveFirst: () => void;
|
|
599
|
+
const slowCycle = vi.fn().mockImplementation(() =>
|
|
600
|
+
new Promise<void>(resolve => { resolveFirst = resolve; })
|
|
601
|
+
);
|
|
602
|
+
const slow = new GravityScheduler({ intervalMs: 100, runCycle: slowCycle });
|
|
603
|
+
slow.start();
|
|
604
|
+
await vi.advanceTimersByTimeAsync(10); // starts first cycle
|
|
605
|
+
await vi.advanceTimersByTimeAsync(200); // interval fires but first still running
|
|
606
|
+
expect(slowCycle).toHaveBeenCalledTimes(1);
|
|
607
|
+
resolveFirst!();
|
|
608
|
+
slow.stop();
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
it('handles cycle errors without crashing', async () => {
|
|
612
|
+
const failingCycle = vi.fn().mockRejectedValue(new Error('cycle failed'));
|
|
613
|
+
const failing = new GravityScheduler({ intervalMs: 1000, runCycle: failingCycle });
|
|
614
|
+
failing.start();
|
|
615
|
+
await vi.advanceTimersByTimeAsync(10);
|
|
616
|
+
expect(failing.isRunning()).toBe(true); // still running despite error
|
|
617
|
+
failing.stop();
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
- [ ] **Step 2: Implement scheduler**
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
// src/lib/cortex/gravity/scheduler.ts
|
|
626
|
+
|
|
627
|
+
export const GRAVITY_INTERVAL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
628
|
+
|
|
629
|
+
export interface GravitySchedulerConfig {
|
|
630
|
+
intervalMs?: number;
|
|
631
|
+
runCycle: () => Promise<void>;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export class GravityScheduler {
|
|
635
|
+
private timer: ReturnType<typeof setInterval> | null = null;
|
|
636
|
+
private running = false;
|
|
637
|
+
private cycling = false;
|
|
638
|
+
private config: Required<GravitySchedulerConfig>;
|
|
639
|
+
|
|
640
|
+
constructor(config: GravitySchedulerConfig) {
|
|
641
|
+
this.config = {
|
|
642
|
+
intervalMs: config.intervalMs ?? GRAVITY_INTERVAL_MS,
|
|
643
|
+
runCycle: config.runCycle,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
start(): void {
|
|
648
|
+
if (this.running) return;
|
|
649
|
+
this.running = true;
|
|
650
|
+
|
|
651
|
+
// Run first cycle immediately (non-blocking)
|
|
652
|
+
this.executeCycle();
|
|
653
|
+
|
|
654
|
+
// Schedule recurring cycles
|
|
655
|
+
this.timer = setInterval(() => this.executeCycle(), this.config.intervalMs);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
stop(): void {
|
|
659
|
+
this.running = false;
|
|
660
|
+
if (this.timer) {
|
|
661
|
+
clearInterval(this.timer);
|
|
662
|
+
this.timer = null;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
isRunning(): boolean {
|
|
667
|
+
return this.running;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
private async executeCycle(): Promise<void> {
|
|
671
|
+
if (this.cycling) return; // prevent concurrent cycles
|
|
672
|
+
this.cycling = true;
|
|
673
|
+
try {
|
|
674
|
+
await this.config.runCycle();
|
|
675
|
+
} catch {
|
|
676
|
+
// Log but don't crash — scheduler continues
|
|
677
|
+
} finally {
|
|
678
|
+
this.cycling = false;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
- [ ] **Step 3: Run tests, commit**
|
|
685
|
+
|
|
686
|
+
```bash
|
|
687
|
+
git commit -m "feat(cortex): add gravity scheduler with interval execution"
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
### Task 6: Barrel export and CortexInstance integration
|
|
693
|
+
|
|
694
|
+
**Files:**
|
|
695
|
+
- Create: `src/lib/cortex/gravity/index.ts`
|
|
696
|
+
- Modify: `src/lib/cortex/index.ts`
|
|
697
|
+
|
|
698
|
+
- [ ] **Step 1: Create barrel export**
|
|
699
|
+
|
|
700
|
+
```typescript
|
|
701
|
+
// src/lib/cortex/gravity/index.ts
|
|
702
|
+
export { computePromotionScore, shouldPromote, getNextLevel, HOP_DECAY, PROMOTION_TYPE_WEIGHTS } from './promotion';
|
|
703
|
+
export { getTrickleMode, TRICKLE_DEFAULTS } from './trickle';
|
|
704
|
+
export type { TrickleMode } from './trickle';
|
|
705
|
+
export { detectSentimentConflict, CONTRADICTION_COSINE_THRESHOLD, DEDUP_COSINE_THRESHOLD } from './contradiction';
|
|
706
|
+
export { computeDecay, shouldArchive, ARCHIVE_THRESHOLD } from './decay';
|
|
707
|
+
export { GravityScheduler, GRAVITY_INTERVAL_MS } from './scheduler';
|
|
708
|
+
export type { GravitySchedulerConfig } from './scheduler';
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
- [ ] **Step 2: Add GravityScheduler to CortexInstance**
|
|
712
|
+
|
|
713
|
+
Read `src/lib/cortex/index.ts`. Add:
|
|
714
|
+
|
|
715
|
+
1. Import: `import { GravityScheduler } from './gravity/scheduler';`
|
|
716
|
+
2. Add `gravityScheduler?: GravityScheduler` to CortexInstance interface
|
|
717
|
+
3. In getCortex(), after signalPipeline initialization:
|
|
718
|
+
|
|
719
|
+
```typescript
|
|
720
|
+
const gravityScheduler = new GravityScheduler({
|
|
721
|
+
runCycle: async () => {
|
|
722
|
+
// Gravity cycle placeholder — full implementation requires
|
|
723
|
+
// scanning all knowledge units, computing promotion scores,
|
|
724
|
+
// executing trickle-down, decaying stale knowledge, etc.
|
|
725
|
+
// Individual functions are ready; the orchestration wiring
|
|
726
|
+
// will be connected when the system has enough data to test.
|
|
727
|
+
},
|
|
728
|
+
});
|
|
729
|
+
// Don't auto-start — let the application decide when to start
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
4. Include `gravityScheduler` in instance object
|
|
733
|
+
5. In `resetCortex()`, add `_instance.gravityScheduler?.stop()` before nulling
|
|
734
|
+
|
|
735
|
+
- [ ] **Step 3: Run full test suite**
|
|
736
|
+
|
|
737
|
+
```bash
|
|
738
|
+
npx vitest run tests/lib/cortex/
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
- [ ] **Step 4: Commit**
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
git commit -m "feat(cortex): add gravity module barrel export and CortexInstance integration"
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
---
|
|
748
|
+
|
|
749
|
+
## Summary
|
|
750
|
+
|
|
751
|
+
| Task | Component | Tests | Status |
|
|
752
|
+
|------|-----------|-------|--------|
|
|
753
|
+
| 1 | Promotion (bubble-up) | 8 | |
|
|
754
|
+
| 2 | Trickle-down | 6 | |
|
|
755
|
+
| 3 | Contradiction detection | 5 | |
|
|
756
|
+
| 4 | Decay + archival | 8 | |
|
|
757
|
+
| 5 | Gravity scheduler | 5 | |
|
|
758
|
+
| 6 | Barrel export + integration | regression | |
|
|
759
|
+
|
|
760
|
+
**Total: 6 tasks, ~32 new tests, 3 chunks**
|
|
761
|
+
|
|
762
|
+
**Key design decisions:**
|
|
763
|
+
- Promotion is COPY (not move) — original stays, promoted copy gets decayed confidence (×0.85)
|
|
764
|
+
- Trickle-down has two modes: PUSH (copies to lower scopes) and VISIBILITY (accessible via graph but not copied)
|
|
765
|
+
- Contradiction detection uses keyword-based sentiment analysis (not LLM) — fast and deterministic
|
|
766
|
+
- Decay is gradual — starts after 30 days of no access, increases over time, archives below 0.1 after 6 months
|
|
767
|
+
- Scheduler uses setInterval (consistent with FederationSync pattern), prevents concurrent cycles, survives errors
|
|
768
|
+
- The runCycle body is a placeholder — individual gravity functions are ready but the full orchestration loop connecting them to store iteration will be wired when there's enough data to test against
|