@jlongo78/agent-spaces 0.7.3 → 0.7.5

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.
Files changed (597) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +7 -0
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/required-server-files.json +19 -19
  6. package/.next/standalone/.next/routes-manifest.json +42 -0
  7. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js +1 -1
  8. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page.js.nft.json +1 -1
  9. package/.next/standalone/.next/server/app/(desktop)/admin/analytics/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js +1 -1
  11. package/.next/standalone/.next/server/app/(desktop)/admin/users/page.js.nft.json +1 -1
  12. package/.next/standalone/.next/server/app/(desktop)/admin/users/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js +1 -1
  14. package/.next/standalone/.next/server/app/(desktop)/analytics/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/(desktop)/analytics/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js +1 -1
  17. package/.next/standalone/.next/server/app/(desktop)/cortex/page.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/(desktop)/cortex/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/.next/server/app/(desktop)/network/page.js +1 -1
  20. package/.next/standalone/.next/server/app/(desktop)/network/page.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/(desktop)/network/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/.next/server/app/(desktop)/page.js +1 -1
  23. package/.next/standalone/.next/server/app/(desktop)/page.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/(desktop)/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/.next/server/app/(desktop)/projects/page.js +1 -1
  26. package/.next/standalone/.next/server/app/(desktop)/projects/page.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/(desktop)/projects/page_client-reference-manifest.js +1 -1
  28. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js +1 -1
  29. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/(desktop)/sessions/[id]/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js +1 -1
  32. package/.next/standalone/.next/server/app/(desktop)/sessions/page.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/(desktop)/sessions/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/.next/server/app/(desktop)/settings/page.js +1 -1
  35. package/.next/standalone/.next/server/app/(desktop)/settings/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/(desktop)/settings/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js +1 -1
  38. package/.next/standalone/.next/server/app/(desktop)/terminal/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/(desktop)/terminal/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js +1 -1
  41. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/(desktop)/terminal/pane/[id]/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js +1 -1
  44. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/(desktop)/terminal/remote/[nodeId]/[workspaceId]/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js +1 -1
  47. package/.next/standalone/.next/server/app/(desktop)/workspaces/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/(desktop)/workspaces/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  50. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  51. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  52. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  53. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  54. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  55. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  56. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  58. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  59. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  60. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  61. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  62. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  63. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  65. package/.next/standalone/.next/server/app/admin/analytics.html +1 -1
  66. package/.next/standalone/.next/server/app/admin/analytics.rsc +17 -16
  67. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics/__PAGE__.segment.rsc +2 -2
  68. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin/analytics.segment.rsc +1 -1
  69. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  70. package/.next/standalone/.next/server/app/admin/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  71. package/.next/standalone/.next/server/app/admin/analytics.segments/_full.segment.rsc +17 -16
  72. package/.next/standalone/.next/server/app/admin/analytics.segments/_head.segment.rsc +1 -1
  73. package/.next/standalone/.next/server/app/admin/analytics.segments/_index.segment.rsc +2 -2
  74. package/.next/standalone/.next/server/app/admin/analytics.segments/_tree.segment.rsc +2 -2
  75. package/.next/standalone/.next/server/app/admin/users.html +1 -1
  76. package/.next/standalone/.next/server/app/admin/users.rsc +17 -16
  77. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users/__PAGE__.segment.rsc +2 -2
  78. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin/users.segment.rsc +1 -1
  79. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap/admin.segment.rsc +1 -1
  80. package/.next/standalone/.next/server/app/admin/users.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  81. package/.next/standalone/.next/server/app/admin/users.segments/_full.segment.rsc +17 -16
  82. package/.next/standalone/.next/server/app/admin/users.segments/_head.segment.rsc +1 -1
  83. package/.next/standalone/.next/server/app/admin/users.segments/_index.segment.rsc +2 -2
  84. package/.next/standalone/.next/server/app/admin/users.segments/_tree.segment.rsc +2 -2
  85. package/.next/standalone/.next/server/app/analytics.html +1 -1
  86. package/.next/standalone/.next/server/app/analytics.rsc +17 -16
  87. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics/__PAGE__.segment.rsc +2 -2
  88. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap/analytics.segment.rsc +1 -1
  89. package/.next/standalone/.next/server/app/analytics.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  90. package/.next/standalone/.next/server/app/analytics.segments/_full.segment.rsc +17 -16
  91. package/.next/standalone/.next/server/app/analytics.segments/_head.segment.rsc +1 -1
  92. package/.next/standalone/.next/server/app/analytics.segments/_index.segment.rsc +2 -2
  93. package/.next/standalone/.next/server/app/analytics.segments/_tree.segment.rsc +2 -2
  94. package/.next/standalone/.next/server/app/api/analytics/overview/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/bulk/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/chat/route.js +1 -1
  97. package/.next/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/config/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/cortex/context/route.js.nft.json +1 -1
  100. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/app-paths-manifest.json +3 -0
  101. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/build-manifest.json +11 -0
  102. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route/server-reference-manifest.json +4 -0
  103. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js +7 -0
  104. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.map +5 -0
  105. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route.js.nft.json +1 -0
  106. package/.next/standalone/.next/server/app/api/cortex/curation/assess/route_client-reference-manifest.js +2 -0
  107. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/app-paths-manifest.json +3 -0
  108. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/build-manifest.json +11 -0
  109. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route/server-reference-manifest.json +4 -0
  110. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js +7 -0
  111. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.map +5 -0
  112. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route.js.nft.json +1 -0
  113. package/.next/standalone/.next/server/app/api/cortex/curation/publish/route_client-reference-manifest.js +2 -0
  114. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/app-paths-manifest.json +3 -0
  115. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/build-manifest.json +11 -0
  116. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route/server-reference-manifest.json +4 -0
  117. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js +7 -0
  118. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.map +5 -0
  119. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route.js.nft.json +1 -0
  120. package/.next/standalone/.next/server/app/api/cortex/curation/refine/route_client-reference-manifest.js +2 -0
  121. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/app-paths-manifest.json +3 -0
  122. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/build-manifest.json +11 -0
  123. package/.next/standalone/.next/server/app/api/cortex/curation/review/route/server-reference-manifest.json +4 -0
  124. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js +7 -0
  125. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.map +5 -0
  126. package/.next/standalone/.next/server/app/api/cortex/curation/review/route.js.nft.json +1 -0
  127. package/.next/standalone/.next/server/app/api/cortex/curation/review/route_client-reference-manifest.js +2 -0
  128. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/app-paths-manifest.json +3 -0
  129. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/build-manifest.json +11 -0
  130. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route/server-reference-manifest.json +4 -0
  131. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js +7 -0
  132. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.map +5 -0
  133. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route.js.nft.json +1 -0
  134. package/.next/standalone/.next/server/app/api/cortex/curation/seed/route_client-reference-manifest.js +2 -0
  135. package/.next/standalone/.next/server/app/api/cortex/export/route.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/api/cortex/federation/pending/route.js.nft.json +1 -1
  137. package/.next/standalone/.next/server/app/api/cortex/federation/resolve/route.js.nft.json +1 -1
  138. package/.next/standalone/.next/server/app/api/cortex/federation/search/route.js.nft.json +1 -1
  139. package/.next/standalone/.next/server/app/api/cortex/federation/teach/route.js.nft.json +1 -1
  140. package/.next/standalone/.next/server/app/api/cortex/graph/edges/route.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/api/cortex/graph/entities/[id]/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/cortex/graph/entities/route.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/api/cortex/graph/populate/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/cortex/import/route.js.nft.json +1 -1
  145. package/.next/standalone/.next/server/app/api/cortex/import/status/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/cortex/ingest/bootstrap/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/api/cortex/ingest/status/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/cortex/knowledge/[id]/route.js.nft.json +1 -1
  149. package/.next/standalone/.next/server/app/api/cortex/knowledge/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/cortex/lobes/[id]/route.js.nft.json +1 -1
  151. package/.next/standalone/.next/server/app/api/cortex/lobes/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/cortex/lobes/share/route.js.nft.json +1 -1
  153. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/app-paths-manifest.json +3 -0
  154. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/build-manifest.json +11 -0
  155. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route/server-reference-manifest.json +4 -0
  156. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js +7 -0
  157. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.map +5 -0
  158. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route.js.nft.json +1 -0
  159. package/.next/standalone/.next/server/app/api/cortex/marketplace/browse/route_client-reference-manifest.js +2 -0
  160. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/app-paths-manifest.json +3 -0
  161. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/build-manifest.json +11 -0
  162. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route/server-reference-manifest.json +4 -0
  163. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js +7 -0
  164. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.map +5 -0
  165. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route.js.nft.json +1 -0
  166. package/.next/standalone/.next/server/app/api/cortex/marketplace/preview/route_client-reference-manifest.js +2 -0
  167. package/.next/standalone/.next/server/app/api/cortex/mcp/call/route.js.nft.json +1 -1
  168. package/.next/standalone/.next/server/app/api/cortex/mcp/tools/route.js.nft.json +1 -1
  169. package/.next/standalone/.next/server/app/api/cortex/search/route.js.nft.json +1 -1
  170. package/.next/standalone/.next/server/app/api/cortex/settings/route.js.nft.json +1 -1
  171. package/.next/standalone/.next/server/app/api/cortex/status/route.js.nft.json +1 -1
  172. package/.next/standalone/.next/server/app/api/cortex/timeline/route.js.nft.json +1 -1
  173. package/.next/standalone/.next/server/app/api/cortex/usage/route.js.nft.json +1 -1
  174. package/.next/standalone/.next/server/app/api/cortex/workspace/[id]/context/route.js.nft.json +1 -1
  175. package/.next/standalone/.next/server/app/api/events/route.js.nft.json +1 -1
  176. package/.next/standalone/.next/server/app/api/folders/route.js.nft.json +1 -1
  177. package/.next/standalone/.next/server/app/api/network/handshake/route.js.nft.json +1 -1
  178. package/.next/standalone/.next/server/app/api/network/projects/route.js.nft.json +1 -1
  179. package/.next/standalone/.next/server/app/api/network/search/route.js.nft.json +1 -1
  180. package/.next/standalone/.next/server/app/api/network/sessions/[id]/messages/route.js.nft.json +1 -1
  181. package/.next/standalone/.next/server/app/api/network/sessions/[id]/route.js.nft.json +1 -1
  182. package/.next/standalone/.next/server/app/api/network/sessions/route.js.nft.json +1 -1
  183. package/.next/standalone/.next/server/app/api/network/workspaces/[id]/route.js.nft.json +1 -1
  184. package/.next/standalone/.next/server/app/api/network/workspaces/route.js +1 -1
  185. package/.next/standalone/.next/server/app/api/network/workspaces/route.js.nft.json +1 -1
  186. package/.next/standalone/.next/server/app/api/panes/[id]/route.js.nft.json +1 -1
  187. package/.next/standalone/.next/server/app/api/panes/route.js.nft.json +1 -1
  188. package/.next/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  189. package/.next/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  190. package/.next/standalone/.next/server/app/api/sessions/[id]/chat/route.js.nft.json +1 -1
  191. package/.next/standalone/.next/server/app/api/sessions/[id]/messages/route.js.nft.json +1 -1
  192. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  193. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  194. package/.next/standalone/.next/server/app/api/sync/route.js.nft.json +1 -1
  195. package/.next/standalone/.next/server/app/api/tags/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/tier/route.js.nft.json +1 -1
  197. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/[key]/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/workspaces/[id]/context/route.js.nft.json +1 -1
  199. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/[msgId]/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/workspaces/[id]/messages/route.js.nft.json +1 -1
  201. package/.next/standalone/.next/server/app/api/workspaces/[id]/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/workspaces/[id]/sessions/route.js.nft.json +1 -1
  203. package/.next/standalone/.next/server/app/api/workspaces/route.js.nft.json +1 -1
  204. package/.next/standalone/.next/server/app/cortex.html +1 -1
  205. package/.next/standalone/.next/server/app/cortex.rsc +17 -16
  206. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex/__PAGE__.segment.rsc +2 -2
  207. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap/cortex.segment.rsc +1 -1
  208. package/.next/standalone/.next/server/app/cortex.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  209. package/.next/standalone/.next/server/app/cortex.segments/_full.segment.rsc +17 -16
  210. package/.next/standalone/.next/server/app/cortex.segments/_head.segment.rsc +1 -1
  211. package/.next/standalone/.next/server/app/cortex.segments/_index.segment.rsc +2 -2
  212. package/.next/standalone/.next/server/app/cortex.segments/_tree.segment.rsc +2 -2
  213. package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  214. package/.next/standalone/.next/server/app/login.html +1 -1
  215. package/.next/standalone/.next/server/app/login.rsc +2 -2
  216. package/.next/standalone/.next/server/app/login.segments/_full.segment.rsc +2 -2
  217. package/.next/standalone/.next/server/app/login.segments/_head.segment.rsc +1 -1
  218. package/.next/standalone/.next/server/app/login.segments/_index.segment.rsc +2 -2
  219. package/.next/standalone/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  220. package/.next/standalone/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
  221. package/.next/standalone/.next/server/app/login.segments/login.segment.rsc +1 -1
  222. package/.next/standalone/.next/server/app/m/page.js.nft.json +1 -1
  223. package/.next/standalone/.next/server/app/m/page_client-reference-manifest.js +1 -1
  224. package/.next/standalone/.next/server/app/m/projects/page.js.nft.json +1 -1
  225. package/.next/standalone/.next/server/app/m/projects/page_client-reference-manifest.js +1 -1
  226. package/.next/standalone/.next/server/app/m/projects.html +1 -1
  227. package/.next/standalone/.next/server/app/m/projects.rsc +4 -4
  228. package/.next/standalone/.next/server/app/m/projects.segments/_full.segment.rsc +4 -4
  229. package/.next/standalone/.next/server/app/m/projects.segments/_head.segment.rsc +1 -1
  230. package/.next/standalone/.next/server/app/m/projects.segments/_index.segment.rsc +2 -2
  231. package/.next/standalone/.next/server/app/m/projects.segments/_tree.segment.rsc +2 -2
  232. package/.next/standalone/.next/server/app/m/projects.segments/m/projects/__PAGE__.segment.rsc +2 -2
  233. package/.next/standalone/.next/server/app/m/projects.segments/m/projects.segment.rsc +1 -1
  234. package/.next/standalone/.next/server/app/m/projects.segments/m.segment.rsc +2 -2
  235. package/.next/standalone/.next/server/app/m/sessions/[id]/page.js.nft.json +1 -1
  236. package/.next/standalone/.next/server/app/m/sessions/[id]/page_client-reference-manifest.js +1 -1
  237. package/.next/standalone/.next/server/app/m/sessions/page.js.nft.json +1 -1
  238. package/.next/standalone/.next/server/app/m/sessions/page_client-reference-manifest.js +1 -1
  239. package/.next/standalone/.next/server/app/m/sessions.html +1 -1
  240. package/.next/standalone/.next/server/app/m/sessions.rsc +4 -4
  241. package/.next/standalone/.next/server/app/m/sessions.segments/_full.segment.rsc +4 -4
  242. package/.next/standalone/.next/server/app/m/sessions.segments/_head.segment.rsc +1 -1
  243. package/.next/standalone/.next/server/app/m/sessions.segments/_index.segment.rsc +2 -2
  244. package/.next/standalone/.next/server/app/m/sessions.segments/_tree.segment.rsc +2 -2
  245. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions/__PAGE__.segment.rsc +2 -2
  246. package/.next/standalone/.next/server/app/m/sessions.segments/m/sessions.segment.rsc +1 -1
  247. package/.next/standalone/.next/server/app/m/sessions.segments/m.segment.rsc +2 -2
  248. package/.next/standalone/.next/server/app/m/settings/page.js.nft.json +1 -1
  249. package/.next/standalone/.next/server/app/m/settings/page_client-reference-manifest.js +1 -1
  250. package/.next/standalone/.next/server/app/m/settings.html +1 -1
  251. package/.next/standalone/.next/server/app/m/settings.rsc +4 -4
  252. package/.next/standalone/.next/server/app/m/settings.segments/_full.segment.rsc +4 -4
  253. package/.next/standalone/.next/server/app/m/settings.segments/_head.segment.rsc +1 -1
  254. package/.next/standalone/.next/server/app/m/settings.segments/_index.segment.rsc +2 -2
  255. package/.next/standalone/.next/server/app/m/settings.segments/_tree.segment.rsc +2 -2
  256. package/.next/standalone/.next/server/app/m/settings.segments/m/settings/__PAGE__.segment.rsc +2 -2
  257. package/.next/standalone/.next/server/app/m/settings.segments/m/settings.segment.rsc +1 -1
  258. package/.next/standalone/.next/server/app/m/settings.segments/m.segment.rsc +2 -2
  259. package/.next/standalone/.next/server/app/m/terminal/page.js.nft.json +1 -1
  260. package/.next/standalone/.next/server/app/m/terminal/page_client-reference-manifest.js +1 -1
  261. package/.next/standalone/.next/server/app/m/terminal.html +1 -1
  262. package/.next/standalone/.next/server/app/m/terminal.rsc +4 -4
  263. package/.next/standalone/.next/server/app/m/terminal.segments/_full.segment.rsc +4 -4
  264. package/.next/standalone/.next/server/app/m/terminal.segments/_head.segment.rsc +1 -1
  265. package/.next/standalone/.next/server/app/m/terminal.segments/_index.segment.rsc +2 -2
  266. package/.next/standalone/.next/server/app/m/terminal.segments/_tree.segment.rsc +2 -2
  267. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal/__PAGE__.segment.rsc +2 -2
  268. package/.next/standalone/.next/server/app/m/terminal.segments/m/terminal.segment.rsc +1 -1
  269. package/.next/standalone/.next/server/app/m/terminal.segments/m.segment.rsc +2 -2
  270. package/.next/standalone/.next/server/app/m.html +1 -1
  271. package/.next/standalone/.next/server/app/m.rsc +4 -4
  272. package/.next/standalone/.next/server/app/m.segments/_full.segment.rsc +4 -4
  273. package/.next/standalone/.next/server/app/m.segments/_head.segment.rsc +1 -1
  274. package/.next/standalone/.next/server/app/m.segments/_index.segment.rsc +2 -2
  275. package/.next/standalone/.next/server/app/m.segments/_tree.segment.rsc +2 -2
  276. package/.next/standalone/.next/server/app/m.segments/m/__PAGE__.segment.rsc +2 -2
  277. package/.next/standalone/.next/server/app/m.segments/m.segment.rsc +2 -2
  278. package/.next/standalone/.next/server/app/network.html +1 -1
  279. package/.next/standalone/.next/server/app/network.rsc +17 -16
  280. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network/__PAGE__.segment.rsc +2 -2
  281. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap/network.segment.rsc +1 -1
  282. package/.next/standalone/.next/server/app/network.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  283. package/.next/standalone/.next/server/app/network.segments/_full.segment.rsc +17 -16
  284. package/.next/standalone/.next/server/app/network.segments/_head.segment.rsc +1 -1
  285. package/.next/standalone/.next/server/app/network.segments/_index.segment.rsc +2 -2
  286. package/.next/standalone/.next/server/app/network.segments/_tree.segment.rsc +2 -2
  287. package/.next/standalone/.next/server/app/projects.html +1 -1
  288. package/.next/standalone/.next/server/app/projects.rsc +17 -16
  289. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects/__PAGE__.segment.rsc +2 -2
  290. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap/projects.segment.rsc +1 -1
  291. package/.next/standalone/.next/server/app/projects.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  292. package/.next/standalone/.next/server/app/projects.segments/_full.segment.rsc +17 -16
  293. package/.next/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  294. package/.next/standalone/.next/server/app/projects.segments/_index.segment.rsc +2 -2
  295. package/.next/standalone/.next/server/app/projects.segments/_tree.segment.rsc +2 -2
  296. package/.next/standalone/.next/server/app/sessions.html +1 -1
  297. package/.next/standalone/.next/server/app/sessions.rsc +17 -16
  298. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions/__PAGE__.segment.rsc +2 -2
  299. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap/sessions.segment.rsc +1 -1
  300. package/.next/standalone/.next/server/app/sessions.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  301. package/.next/standalone/.next/server/app/sessions.segments/_full.segment.rsc +17 -16
  302. package/.next/standalone/.next/server/app/sessions.segments/_head.segment.rsc +1 -1
  303. package/.next/standalone/.next/server/app/sessions.segments/_index.segment.rsc +2 -2
  304. package/.next/standalone/.next/server/app/sessions.segments/_tree.segment.rsc +2 -2
  305. package/.next/standalone/.next/server/app/settings.html +1 -1
  306. package/.next/standalone/.next/server/app/settings.rsc +17 -16
  307. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings/__PAGE__.segment.rsc +2 -2
  308. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap/settings.segment.rsc +1 -1
  309. package/.next/standalone/.next/server/app/settings.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  310. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +17 -16
  311. package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  312. package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  313. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  314. package/.next/standalone/.next/server/app/terminal.html +1 -1
  315. package/.next/standalone/.next/server/app/terminal.rsc +17 -16
  316. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal/__PAGE__.segment.rsc +2 -2
  317. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap/terminal.segment.rsc +1 -1
  318. package/.next/standalone/.next/server/app/terminal.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  319. package/.next/standalone/.next/server/app/terminal.segments/_full.segment.rsc +17 -16
  320. package/.next/standalone/.next/server/app/terminal.segments/_head.segment.rsc +1 -1
  321. package/.next/standalone/.next/server/app/terminal.segments/_index.segment.rsc +2 -2
  322. package/.next/standalone/.next/server/app/terminal.segments/_tree.segment.rsc +2 -2
  323. package/.next/standalone/.next/server/app/workspaces.html +1 -1
  324. package/.next/standalone/.next/server/app/workspaces.rsc +17 -16
  325. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces/__PAGE__.segment.rsc +2 -2
  326. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap/workspaces.segment.rsc +1 -1
  327. package/.next/standalone/.next/server/app/workspaces.segments/!KGRlc2t0b3Ap.segment.rsc +5 -4
  328. package/.next/standalone/.next/server/app/workspaces.segments/_full.segment.rsc +17 -16
  329. package/.next/standalone/.next/server/app/workspaces.segments/_head.segment.rsc +1 -1
  330. package/.next/standalone/.next/server/app/workspaces.segments/_index.segment.rsc +2 -2
  331. package/.next/standalone/.next/server/app/workspaces.segments/_tree.segment.rsc +2 -2
  332. package/.next/standalone/.next/server/app-paths-manifest.json +7 -0
  333. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0041efe4._.js +98 -0
  334. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00bf0ace._.js +2 -2
  335. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e71d908._.js +2 -2
  336. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e9142f3._.js +2 -2
  337. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10e47926._.js +1 -1
  338. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1665dc78._.js +2 -2
  339. package/.next/standalone/.next/server/chunks/[root-of-the-server]__175cbabf._.js +2 -2
  340. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adae357._.js +2 -2
  341. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d359752._.js +2 -2
  342. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e8fabeb._.js +3 -3
  343. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1f8deca0._.js +8 -8
  344. package/.next/standalone/.next/server/chunks/[root-of-the-server]__253fdda1._.js +2 -2
  345. package/.next/standalone/.next/server/chunks/[root-of-the-server]__28e6434f._.js +2 -2
  346. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2a386564._.js +1 -1
  347. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c20fb38._.js +2 -2
  348. package/.next/standalone/.next/server/chunks/[root-of-the-server]__309132cd._.js +1 -1
  349. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__cf3c60c2._.js → [root-of-the-server]__33fec964._.js} +4 -4
  350. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3786d8ae._.js +1 -1
  351. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3ae92407._.js +2 -2
  352. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3beda9fe._.js +2 -2
  353. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4619e9bd._.js +1 -1
  354. package/.next/standalone/.next/server/chunks/[root-of-the-server]__4a051043._.js +1 -1
  355. package/.next/standalone/.next/server/chunks/[root-of-the-server]__508002e4._.js +2 -2
  356. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5086c373._.js +2 -2
  357. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5913e097._.js +2 -2
  358. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5b5f68d2._.js +2 -2
  359. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5c1f2459._.js +2 -2
  360. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5ec8c977._.js +2 -2
  361. package/.next/standalone/.next/server/chunks/[root-of-the-server]__63cebc6c._.js +98 -0
  362. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64d30d4d._.js +2 -2
  363. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c54fc2e._.js +2 -2
  364. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6dc1fb7e._.js +1 -1
  365. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6e568102._.js +1 -1
  366. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6faa04c0._.js +2 -2
  367. package/.next/standalone/.next/server/chunks/[root-of-the-server]__74a34dc3._.js +98 -0
  368. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e7250a4._.js +3 -3
  369. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8309e0a4._.js +2 -2
  370. package/.next/standalone/.next/server/chunks/[root-of-the-server]__86cc0e2b._.js +6 -6
  371. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c2565a._.js +2 -2
  372. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8d178ad9._.js +2 -2
  373. package/.next/standalone/.next/server/chunks/[root-of-the-server]__93ee06f3._.js +3 -3
  374. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9e4c154a._.js +2 -2
  375. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a9d2e1d3._.js +2 -2
  376. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ae53d343._.js +2 -2
  377. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b3a04cef._.js +2 -2
  378. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b4270b77._.js +3 -0
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b6b6ce60._.js +1 -1
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b9545dd9._.js +1 -1
  381. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c88b63f7._.js +98 -0
  382. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__eee4c5e8._.js → [root-of-the-server]__cba5f007._.js} +2 -2
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cbf4ceb0._.js +2 -2
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cefdba2f._.js +2 -2
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__cf9e82bb._.js +2 -2
  386. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d2897392._.js +2 -2
  387. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d3b2d856._.js +2 -2
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d73273ca._.js +1 -1
  389. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8417eb6._.js +2 -2
  390. package/.next/standalone/.next/server/chunks/[root-of-the-server]__dc2a55de._.js +2 -2
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e0d4690b._.js +3 -3
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e678dd53._.js +3 -0
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e9223f55._.js +2 -2
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ea630076._.js +3 -3
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__eb8acb65._.js +1 -1
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f26ca49d._.js +1 -1
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f33e1101._.js +1 -1
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f515f865._.js +2 -2
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fceb5d60._.js +98 -0
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__fed41403._.js +2 -2
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ff2e98c2._.js +2 -2
  402. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_assess_route_actions_3e8ef2a6.js +3 -0
  403. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_publish_route_actions_49238be3.js +3 -0
  404. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_refine_route_actions_05675688.js +3 -0
  405. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_review_route_actions_5cbb5f6b.js +3 -0
  406. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_curation_seed_route_actions_21084bdb.js +3 -0
  407. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_browse_route_actions_7ed0768c.js +3 -0
  408. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_cortex_marketplace_preview_route_actions_38d4cc17.js +3 -0
  409. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19afc53d._.js +3 -0
  410. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__66aca5d4._.js +1 -1
  411. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__efef0a06._.js → [root-of-the-server]__ca5beb09._.js} +2 -2
  412. package/.next/standalone/.next/server/chunks/ssr/{_7dd2ac82._.js → _078dd64d._.js} +1 -1
  413. package/.next/standalone/.next/server/chunks/ssr/_163d0838._.js +3 -0
  414. package/.next/standalone/.next/server/chunks/ssr/{_a4eeff0d._.js → _2230ad2d._.js} +2 -2
  415. package/.next/standalone/.next/server/chunks/ssr/{_9303a965._.js → _701606d5._.js} +1 -1
  416. package/.next/standalone/.next/server/chunks/ssr/_72b1de37._.js +3 -0
  417. package/.next/standalone/.next/server/chunks/ssr/{_d39bcfda._.js → _93ef0f79._.js} +2 -2
  418. package/.next/standalone/.next/server/chunks/ssr/_950142a4._.js +1 -1
  419. package/.next/standalone/.next/server/chunks/ssr/_a22b5eb0._.js +3 -0
  420. package/.next/standalone/.next/server/chunks/ssr/_aeeff784._.js +3 -0
  421. package/.next/standalone/.next/server/chunks/ssr/_c1cfdd09._.js +3 -0
  422. package/.next/standalone/.next/server/chunks/ssr/_c2d3f6de._.js +3 -0
  423. package/.next/standalone/.next/server/chunks/ssr/{_8167090e._.js → _db2fec84._.js} +2 -2
  424. package/.next/standalone/.next/server/chunks/ssr/src_02bae6e5._.js +3 -0
  425. package/.next/standalone/.next/server/chunks/ssr/src_app_(desktop)_terminal_page_tsx_de5e8d85._.js +2 -2
  426. package/.next/standalone/.next/server/chunks/ssr/src_components_terminal_terminal-pane_tsx_803c5e2c._.js +2 -2
  427. package/.next/standalone/.next/server/edge/chunks/_d73df637._.js +1 -1
  428. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  429. package/.next/standalone/.next/server/pages/404.html +1 -1
  430. package/.next/standalone/.next/server/pages/500.html +2 -2
  431. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  432. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  433. package/.next/standalone/.next/static/chunks/25b7a243a404a1a7.js +1 -0
  434. package/.next/standalone/.next/static/chunks/2b997e211a5d547b.js +1 -0
  435. package/.next/standalone/.next/static/chunks/5e08abb00653754a.js +1 -0
  436. package/.next/standalone/.next/static/chunks/61f2ed39b75b1efc.js +1 -0
  437. package/.next/standalone/.next/static/chunks/6c78a1dfa7ec2959.css +3 -0
  438. package/.next/standalone/.next/static/chunks/7246f1ee445f7024.js +1 -0
  439. package/.next/standalone/.next/static/chunks/7424664c6ffa94bd.js +1 -0
  440. package/.next/standalone/.next/static/chunks/7e0091ab6c5ee8bd.js +1 -0
  441. package/.next/standalone/.next/static/chunks/8b3f4572fec83caa.js +5 -0
  442. package/.next/standalone/.next/static/chunks/{a7b2795949a6c63e.js → 9899cf4c2bdbe61d.js} +2 -2
  443. package/.next/standalone/.next/static/chunks/ac339e970df82fa5.js +5 -0
  444. package/.next/standalone/.next/static/chunks/{0e61e67b7b8fc3f3.js → c418112e102673ce.js} +1 -1
  445. package/.next/standalone/.next/static/chunks/e2f0a2330dedff4b.js +85 -0
  446. package/.next/standalone/.next/static/chunks/f0c8b3f8cc1939ec.js +1 -0
  447. package/.next/standalone/.next/static/chunks/f9f2628207848ac2.js +1 -0
  448. package/.next/standalone/bin/cortex-hook.sh +62 -62
  449. package/.next/standalone/bin/cortex-mcp.js +60 -60
  450. package/.next/standalone/docs/superpowers/plans/2026-03-13-cortex-wiring.md +1387 -1387
  451. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-entity-graph.md +1923 -1923
  452. package/.next/standalone/docs/superpowers/plans/2026-03-14-cortex-v2-knowledge-evolution.md +1113 -1113
  453. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-boundary-engine.md +853 -853
  454. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-context-engine.md +1274 -1274
  455. package/.next/standalone/docs/superpowers/plans/2026-03-15-cortex-v2-signal-ingestion.md +933 -933
  456. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-lobes.md +1080 -1080
  457. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-gravity-system.md +768 -768
  458. package/.next/standalone/docs/superpowers/plans/2026-03-16-cortex-v2-ui.md +1108 -1108
  459. package/.next/standalone/docs/superpowers/plans/2026-03-18-cortex-ui-integration.md +1846 -0
  460. package/.next/standalone/docs/superpowers/specs/2026-03-13-cortex-wiring-design.md +268 -268
  461. package/.next/standalone/docs/superpowers/specs/2026-03-14-cortex-v2-design.md +623 -623
  462. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-lobes-design.md +263 -263
  463. package/.next/standalone/docs/superpowers/specs/2026-03-16-cortex-v2-ui-design.md +240 -240
  464. package/.next/standalone/docs/superpowers/specs/2026-03-18-cortex-ui-integration-design.md +341 -0
  465. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/README.md +46 -0
  466. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +221 -0
  467. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/index.js +1 -0
  468. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  469. package/.next/standalone/node_modules/@img/sharp-libvips-linux-x64/package.json +42 -0
  470. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +46 -0
  471. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +221 -0
  472. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +1 -0
  473. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  474. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +42 -0
  475. package/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +30 -0
  476. package/.next/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  477. package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-linux-x64}/package.json +46 -39
  478. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  479. package/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +46 -0
  480. package/.next/standalone/package.json +102 -102
  481. package/.next/standalone/server.js +1 -1
  482. package/.next/standalone/src/app/(desktop)/cortex/page.tsx +78 -75
  483. package/.next/standalone/src/app/api/cortex/context/route.ts +78 -78
  484. package/.next/standalone/src/app/api/cortex/curation/assess/route.ts +27 -0
  485. package/.next/standalone/src/app/api/cortex/curation/publish/route.ts +23 -0
  486. package/.next/standalone/src/app/api/cortex/curation/refine/route.ts +23 -0
  487. package/.next/standalone/src/app/api/cortex/curation/review/route.ts +29 -0
  488. package/.next/standalone/src/app/api/cortex/curation/seed/route.ts +23 -0
  489. package/.next/standalone/src/app/api/cortex/export/route.ts +40 -40
  490. package/.next/standalone/src/app/api/cortex/federation/pending/route.ts +20 -20
  491. package/.next/standalone/src/app/api/cortex/federation/resolve/route.ts +43 -43
  492. package/.next/standalone/src/app/api/cortex/federation/search/route.ts +35 -35
  493. package/.next/standalone/src/app/api/cortex/federation/teach/route.ts +76 -76
  494. package/.next/standalone/src/app/api/cortex/graph/edges/route.ts +112 -112
  495. package/.next/standalone/src/app/api/cortex/graph/entities/[id]/route.ts +73 -73
  496. package/.next/standalone/src/app/api/cortex/graph/entities/route.ts +75 -75
  497. package/.next/standalone/src/app/api/cortex/graph/populate/route.ts +203 -203
  498. package/.next/standalone/src/app/api/cortex/import/route.ts +75 -43
  499. package/.next/standalone/src/app/api/cortex/import/status/route.ts +15 -15
  500. package/.next/standalone/src/app/api/cortex/ingest/bootstrap/route.ts +29 -29
  501. package/.next/standalone/src/app/api/cortex/ingest/status/route.ts +15 -15
  502. package/.next/standalone/src/app/api/cortex/knowledge/[id]/route.ts +91 -91
  503. package/.next/standalone/src/app/api/cortex/knowledge/route.ts +93 -93
  504. package/.next/standalone/src/app/api/cortex/lobes/[id]/route.ts +67 -67
  505. package/.next/standalone/src/app/api/cortex/lobes/route.ts +22 -22
  506. package/.next/standalone/src/app/api/cortex/lobes/share/route.ts +80 -80
  507. package/.next/standalone/src/app/api/cortex/marketplace/browse/route.ts +43 -0
  508. package/.next/standalone/src/app/api/cortex/marketplace/preview/route.ts +46 -0
  509. package/.next/standalone/src/app/api/cortex/mcp/call/route.ts +11 -11
  510. package/.next/standalone/src/app/api/cortex/mcp/tools/route.ts +6 -6
  511. package/.next/standalone/src/app/api/cortex/search/route.ts +43 -43
  512. package/.next/standalone/src/app/api/cortex/settings/route.ts +33 -33
  513. package/.next/standalone/src/app/api/cortex/status/route.ts +169 -129
  514. package/.next/standalone/src/app/api/cortex/timeline/route.ts +42 -42
  515. package/.next/standalone/src/app/api/cortex/usage/route.ts +31 -31
  516. package/.next/standalone/src/app/api/cortex/workspace/[id]/context/route.ts +41 -41
  517. package/.next/standalone/src/components/cortex/constants.ts +29 -0
  518. package/.next/standalone/src/components/cortex/cortex-dashboard.tsx +304 -228
  519. package/.next/standalone/src/components/cortex/cortex-indicator.tsx +44 -44
  520. package/.next/standalone/src/components/cortex/cortex-panel.tsx +140 -140
  521. package/.next/standalone/src/components/cortex/cortex-settings.tsx +221 -221
  522. package/.next/standalone/src/components/cortex/curation-tab.tsx +810 -0
  523. package/.next/standalone/src/components/cortex/entity-detail.tsx +101 -101
  524. package/.next/standalone/src/components/cortex/entity-graph.tsx +382 -382
  525. package/.next/standalone/src/components/cortex/import-dialog.tsx +212 -0
  526. package/.next/standalone/src/components/cortex/injection-badge.tsx +72 -72
  527. package/.next/standalone/src/components/cortex/knowledge-card.tsx +109 -127
  528. package/.next/standalone/src/components/cortex/knowledge-tab.tsx +158 -56
  529. package/.next/standalone/src/components/cortex/lobe-settings.tsx +215 -199
  530. package/.next/standalone/src/components/cortex/marketplace-card.tsx +126 -0
  531. package/.next/standalone/src/components/cortex/marketplace-tab.tsx +113 -0
  532. package/.next/standalone/src/lib/cortex/config.ts +40 -40
  533. package/.next/standalone/src/lib/cortex/debug.ts +10 -10
  534. package/.next/standalone/src/lib/cortex/distillation/usage-store.ts +18 -18
  535. package/.next/standalone/src/lib/cortex/graph/resolver.ts +10 -10
  536. package/.next/standalone/src/lib/cortex/graph/types.ts +22 -22
  537. package/.next/standalone/src/lib/cortex/index.ts +56 -56
  538. package/.next/standalone/src/lib/cortex/ingestion/bootstrap.ts +14 -14
  539. package/.next/standalone/src/lib/cortex/knowledge/compat.ts +14 -14
  540. package/.next/standalone/src/lib/cortex/knowledge/contradiction.ts +10 -10
  541. package/.next/standalone/src/lib/cortex/knowledge/types.ts +67 -67
  542. package/.next/standalone/src/lib/cortex/lobes/config.ts +16 -16
  543. package/.next/standalone/src/lib/cortex/lobes/resolver.ts +8 -8
  544. package/.next/standalone/src/lib/cortex/lobes/shares.ts +14 -14
  545. package/.next/standalone/src/lib/cortex/mcp/server.ts +8 -8
  546. package/.next/standalone/src/lib/cortex/portability/exporter.ts +6 -6
  547. package/.next/standalone/src/lib/cortex/portability/importer.ts +10 -10
  548. package/.next/standalone/src/lib/cortex/retrieval/context-engine.ts +10 -10
  549. package/.next/standalone/src/lib/cortex/types.ts +39 -38
  550. package/.next/standalone/tsconfig.json +34 -34
  551. package/LICENSE +661 -661
  552. package/README.md +131 -131
  553. package/bin/cortex-hook.sh +62 -62
  554. package/bin/cortex-mcp.js +60 -60
  555. package/bin/fix-standalone-externals.js +79 -79
  556. package/bin/lib/auto-setup.js +110 -110
  557. package/bin/mdns-service.js +171 -171
  558. package/bin/postinstall.js +35 -35
  559. package/bin/setup-admin.js +195 -195
  560. package/bin/spaces-dev.js +208 -208
  561. package/bin/spaces-install.js +599 -599
  562. package/bin/spaces-reset-totp.js +50 -50
  563. package/bin/spaces-service.js +1020 -1020
  564. package/bin/spaces-setup.js +253 -253
  565. package/bin/spaces.js +776 -728
  566. package/bin/ssh-auth-keys.sh +68 -68
  567. package/bin/terminal-server.js +1649 -1646
  568. package/package.json +102 -102
  569. package/.next/standalone/.claude/settings.local.json +0 -55
  570. package/.next/standalone/.claude/spaces-env.json +0 -1
  571. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ecce08b._.js +0 -3
  572. package/.next/standalone/.next/server/chunks/ssr/_7e63066a._.js +0 -3
  573. package/.next/standalone/.next/server/chunks/ssr/_a012c43b._.js +0 -3
  574. package/.next/standalone/.next/server/chunks/ssr/_b4db3983._.js +0 -3
  575. package/.next/standalone/.next/server/chunks/ssr/_cd50a174._.js +0 -3
  576. package/.next/standalone/.next/server/chunks/ssr/_e7a9e2b0._.js +0 -3
  577. package/.next/standalone/.next/server/chunks/ssr/_ed6c285b._.js +0 -3
  578. package/.next/standalone/.next/server/chunks/ssr/src_133a7c8a._.js +0 -3
  579. package/.next/standalone/.next/static/chunks/17d164c01fa1aaa9.js +0 -5
  580. package/.next/standalone/.next/static/chunks/19da759dde107f02.js +0 -1
  581. package/.next/standalone/.next/static/chunks/58d78765e5140dcb.js +0 -1
  582. package/.next/standalone/.next/static/chunks/596bd56e0ad09173.js +0 -5
  583. package/.next/standalone/.next/static/chunks/78dd908e70bf8c4b.js +0 -85
  584. package/.next/standalone/.next/static/chunks/79aacab676df80c4.js +0 -1
  585. package/.next/standalone/.next/static/chunks/846d6ef408f69390.js +0 -1
  586. package/.next/standalone/.next/static/chunks/8de5e432a2fc563a.js +0 -1
  587. package/.next/standalone/.next/static/chunks/9196173f0d081f2c.js +0 -1
  588. package/.next/standalone/.next/static/chunks/9bd8a119aaeafc9e.js +0 -1
  589. package/.next/standalone/.next/static/chunks/e35e863c09511a51.js +0 -1
  590. package/.next/standalone/.next/static/chunks/f644c11ace7a0d9d.css +0 -3
  591. package/.next/standalone/.spaces/cortex-context.md +0 -70
  592. package/.next/standalone/node_modules/@img/sharp-win32-x64/lib/sharp-win32-x64.node +0 -0
  593. package/.next/standalone/src/components/cortex/context-tab.tsx +0 -171
  594. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_buildManifest.js +0 -0
  595. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_clientMiddlewareManifest.json +0 -0
  596. /package/.next/standalone/.next/static/{B207XFa7QvXAYS7Sqq2_4 → 77VYbwIoyxFNr5xevTrCu}/_ssgManifest.js +0 -0
  597. /package/.next/standalone/node_modules/@img/{sharp-win32-x64 → sharp-libvips-linux-x64}/versions.json +0 -0
@@ -1,1113 +1,1113 @@
1
- # Cortex v2 — Pillar 2: Knowledge Unit Schema Evolution
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:** Evolve the KnowledgeUnit schema from flat `layer` to graph-aware `scope`, add entity links, evidence tracking, sensitivity classification, and provenance — while maintaining full backward compatibility with the v1 API and existing ~542 knowledge units.
6
-
7
- **Architecture:** The `layer` field is KEPT for backward compatibility (spec says "removed" but we intentionally keep it as a derived field to avoid breaking existing consumers — this is a documented deviation). New v2 fields (`scope`, `entity_links`, `evidence_score`, etc.) are added as nullable Arrow columns. Existing LanceDB tables are migrated in-place using LanceDB's `addColumns()` API in a migration step during `store.init()`. A compatibility layer maps v1 `layer` params to v2 `scope` in all API routes, MCP tools, and hooks.
8
-
9
- **Tech Stack:** TypeScript, LanceDB (Arrow schema), vitest
10
-
11
- **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 2
12
-
13
- **Depends on:** Pillar 1 (Entity Graph) — completed
14
-
15
- ---
16
-
17
- ## File Structure
18
-
19
- ```
20
- Modified files:
21
- ├── src/lib/cortex/knowledge/types.ts — Add v2 interfaces, keep v1 layer for compat (intentional spec deviation)
22
- ├── src/lib/cortex/knowledge/evidence.ts — NEW: evidence score computation
23
- ├── src/lib/cortex/knowledge/compat.ts — NEW: v1↔v2 layer/scope mapping
24
- ├── src/lib/cortex/store.ts — Evolve Arrow schema, add v2 fields, migrate existing tables
25
- ├── src/lib/cortex/store-migration.ts — NEW: LanceDB table schema migration (addColumns)
26
- ├── src/lib/cortex/retrieval/search.ts — Use scope instead of layer for weights
27
- ├── src/lib/cortex/retrieval/scoring.ts — Add evidence_score to formula
28
- ├── src/app/api/cortex/knowledge/route.ts — Accept both layer and scope params
29
- ├── src/lib/cortex/mcp/server.ts — Accept both layer and scope in tools
30
- ├── bin/cortex-learn-hook.js — Map 'personal' to scope format
31
-
32
- Test files:
33
- ├── tests/lib/cortex/knowledge/evidence.test.ts — Evidence score computation
34
- ├── tests/lib/cortex/knowledge/compat.test.ts — v1↔v2 mapping
35
- ├── tests/lib/cortex/knowledge/types.test.ts — Updated for v2 types
36
- ├── tests/lib/cortex/store.test.ts — Updated for v2 schema
37
- ├── tests/lib/cortex/retrieval/search.test.ts — Updated for scope-based weights
38
- ```
39
-
40
- ---
41
-
42
- ## Chunk 1: New Types and Compatibility Layer
43
-
44
- ### Task 1: Add v2 type definitions
45
-
46
- **Files:**
47
- - Modify: `src/lib/cortex/knowledge/types.ts`
48
-
49
- - [ ] **Step 1: Add new interfaces after existing ones (keep all v1 types for backward compat)**
50
-
51
- Add these types to `src/lib/cortex/knowledge/types.ts` below the existing interfaces:
52
-
53
- ```typescript
54
- // --- v2 Schema Extensions ---
55
-
56
- export const SCOPE_LEVELS = ['personal', 'team', 'department', 'organization'] as const;
57
- export type ScopeLevel = typeof SCOPE_LEVELS[number];
58
-
59
- export interface Scope {
60
- level: ScopeLevel;
61
- entity_id: string; // format: {type}-{slug}
62
- }
63
-
64
- export interface EntityLink {
65
- entity_id: string;
66
- entity_type: EntityType; // imported from graph module
67
- relation: 'created_by' | 'about' | 'scoped_to' | 'derived_from';
68
- weight: number; // 0-1
69
- }
70
- ```
71
-
72
- Add this import at the top of types.ts:
73
- ```typescript
74
- import type { EntityType } from '@/lib/cortex/graph/types';
75
-
76
- export const SENSITIVITY_CLASSES = ['public', 'internal', 'restricted', 'confidential'] as const;
77
- export type SensitivityClass = typeof SENSITIVITY_CLASSES[number];
78
-
79
- export interface ScopeOverride {
80
- max_level: ScopeLevel;
81
- }
82
-
83
- export const ORIGIN_SOURCE_TYPES = [
84
- 'conversation', 'git_commit', 'pr_review', 'document',
85
- 'behavioral', 'distillation', 'manual',
86
- ] as const;
87
- export type OriginSourceType = typeof ORIGIN_SOURCE_TYPES[number];
88
-
89
- export interface Origin {
90
- source_type: OriginSourceType;
91
- source_ref: string;
92
- creator_entity_id: string;
93
- }
94
-
95
- export interface PropHop {
96
- from_scope: Scope;
97
- to_scope: Scope;
98
- reason: 'evidence_threshold' | 'policy_push' | 'manual_promote';
99
- timestamp: string;
100
- confidence_at_hop: number;
101
- }
102
-
103
- export function isValidScopeLevel(s: string): s is ScopeLevel {
104
- return SCOPE_LEVELS.includes(s as ScopeLevel);
105
- }
106
-
107
- export function isValidSensitivity(s: string): s is SensitivityClass {
108
- return SENSITIVITY_CLASSES.includes(s as SensitivityClass);
109
- }
110
- ```
111
-
112
- - [ ] **Step 1b: Update HOP_DECAY_FACTOR from 0.8 to 0.85**
113
-
114
- Per spec Key Constants table, update the existing `HOP_DECAY_FACTOR` constant in types.ts from `0.8` to `0.85` (increased to preserve more signal across propagation hops).
115
-
116
- - [ ] **Step 2: Extend KnowledgeUnit interface with optional v2 fields**
117
-
118
- Add new optional fields to the existing `KnowledgeUnit` interface (keeping `layer` for backward compat):
119
-
120
- ```typescript
121
- export interface KnowledgeUnit {
122
- // ... all existing v1 fields unchanged ...
123
- layer: Layer; // KEPT for backward compat (derived from scope on read)
124
-
125
- // v2 fields (optional — null/default when reading v1 data)
126
- scope?: Scope;
127
- entity_links?: EntityLink[];
128
- evidence_score?: number;
129
- corroborations?: number;
130
- contradiction_refs?: string[];
131
- sensitivity?: SensitivityClass;
132
- creator_scope?: ScopeOverride | null;
133
- origin?: Origin;
134
- propagation_path?: PropHop[];
135
- }
136
- ```
137
-
138
- - [ ] **Step 3: Commit**
139
-
140
- ```bash
141
- git add src/lib/cortex/knowledge/types.ts
142
- git commit -m "feat(cortex): add v2 knowledge unit type definitions"
143
- ```
144
-
145
- ---
146
-
147
- ### Task 2: Create v1↔v2 compatibility layer
148
-
149
- **Files:**
150
- - Create: `src/lib/cortex/knowledge/compat.ts`
151
- - Create: `tests/lib/cortex/knowledge/compat.test.ts`
152
-
153
- - [ ] **Step 1: Write failing tests**
154
-
155
- ```typescript
156
- // tests/lib/cortex/knowledge/compat.test.ts
157
- import { describe, it, expect } from 'vitest';
158
- import {
159
- layerToScope,
160
- scopeToLayer,
161
- scopeToLayerKey,
162
- layerKeyToScope,
163
- } from '@/lib/cortex/knowledge/compat';
164
-
165
- describe('v1↔v2 Compatibility', () => {
166
- describe('layerToScope', () => {
167
- it('maps personal to personal scope', () => {
168
- const scope = layerToScope('personal', null, 'default-user');
169
- expect(scope).toEqual({ level: 'personal', entity_id: 'person-default-user' });
170
- });
171
-
172
- it('maps workspace to team scope', () => {
173
- const scope = layerToScope('workspace', 42);
174
- expect(scope).toEqual({ level: 'team', entity_id: 'team-default' });
175
- });
176
-
177
- it('maps team to organization scope', () => {
178
- const scope = layerToScope('team', null);
179
- expect(scope).toEqual({ level: 'organization', entity_id: 'organization-default' });
180
- });
181
- });
182
-
183
- describe('scopeToLayer', () => {
184
- it('maps personal scope to personal layer', () => {
185
- expect(scopeToLayer({ level: 'personal', entity_id: 'person-alice' })).toBe('personal');
186
- });
187
-
188
- it('maps team scope to workspace layer', () => {
189
- expect(scopeToLayer({ level: 'team', entity_id: 'team-platform' })).toBe('workspace');
190
- });
191
-
192
- it('maps department scope to team layer', () => {
193
- expect(scopeToLayer({ level: 'department', entity_id: 'dept-eng' })).toBe('team');
194
- });
195
-
196
- it('maps organization scope to team layer', () => {
197
- expect(scopeToLayer({ level: 'organization', entity_id: 'org-acme' })).toBe('team');
198
- });
199
- });
200
-
201
- describe('scopeToLayerKey', () => {
202
- it('maps personal scope to personal key', () => {
203
- expect(scopeToLayerKey({ level: 'personal', entity_id: 'person-alice' })).toBe('personal');
204
- });
205
-
206
- it('maps team scope with workspace_id to workspace/id key', () => {
207
- expect(scopeToLayerKey({ level: 'team', entity_id: 'team-platform' }, 42)).toBe('workspace/42');
208
- });
209
-
210
- it('maps team scope without workspace_id to team key', () => {
211
- expect(scopeToLayerKey({ level: 'team', entity_id: 'team-platform' })).toBe('team');
212
- });
213
-
214
- it('maps organization scope to team key', () => {
215
- expect(scopeToLayerKey({ level: 'organization', entity_id: 'org-acme' })).toBe('team');
216
- });
217
- });
218
-
219
- describe('layerKeyToScope', () => {
220
- it('maps personal key to personal scope', () => {
221
- const scope = layerKeyToScope('personal', 'default-user');
222
- expect(scope).toEqual({ level: 'personal', entity_id: 'person-default-user' });
223
- });
224
-
225
- it('maps workspace/id key to team scope', () => {
226
- const scope = layerKeyToScope('workspace/42');
227
- expect(scope).toEqual({ level: 'team', entity_id: 'team-default' });
228
- });
229
-
230
- it('maps team key to organization scope', () => {
231
- const scope = layerKeyToScope('team');
232
- expect(scope).toEqual({ level: 'organization', entity_id: 'organization-default' });
233
- });
234
- });
235
- });
236
- ```
237
-
238
- - [ ] **Step 2: Run tests to verify they fail**
239
-
240
- Run: `npx vitest run tests/lib/cortex/knowledge/compat.test.ts`
241
-
242
- - [ ] **Step 3: Implement compatibility layer**
243
-
244
- ```typescript
245
- // src/lib/cortex/knowledge/compat.ts
246
- import type { Layer, Scope, ScopeLevel } from './types';
247
-
248
- /**
249
- * Convert v1 layer to v2 scope.
250
- * personal → personal scope, workspace → team scope, team → organization scope.
251
- */
252
- export function layerToScope(
253
- layer: Layer,
254
- workspaceId?: number | null,
255
- userId?: string,
256
- ): Scope {
257
- switch (layer) {
258
- case 'personal':
259
- return { level: 'personal', entity_id: `person-${userId ?? 'default-user'}` };
260
- case 'workspace':
261
- return { level: 'team', entity_id: 'team-default' };
262
- case 'team':
263
- return { level: 'organization', entity_id: 'organization-default' };
264
- }
265
- }
266
-
267
- /**
268
- * Convert v2 scope back to v1 layer (for backward compat).
269
- * personal → personal, team → workspace, department/organization → team.
270
- */
271
- export function scopeToLayer(scope: Scope): Layer {
272
- switch (scope.level) {
273
- case 'personal': return 'personal';
274
- case 'team': return 'workspace';
275
- case 'department':
276
- case 'organization': return 'team';
277
- }
278
- }
279
-
280
- /**
281
- * Convert v2 scope to a LanceDB layer key (storage path).
282
- * Maintains compatibility with existing store.layerPath() logic.
283
- */
284
- export function scopeToLayerKey(scope: Scope, workspaceId?: number | null): string {
285
- switch (scope.level) {
286
- case 'personal': return 'personal';
287
- case 'team':
288
- return workspaceId ? `workspace/${workspaceId}` : 'team';
289
- case 'department':
290
- case 'organization':
291
- return 'team';
292
- }
293
- }
294
-
295
- /**
296
- * Convert a LanceDB layer key back to a v2 scope.
297
- */
298
- export function layerKeyToScope(layerKey: string, userId?: string): Scope {
299
- if (layerKey === 'personal') {
300
- return { level: 'personal', entity_id: `person-${userId ?? 'default-user'}` };
301
- }
302
- if (layerKey.startsWith('workspace/')) {
303
- return { level: 'team', entity_id: 'team-default' };
304
- }
305
- // 'team' key → organization scope
306
- return { level: 'organization', entity_id: 'organization-default' };
307
- }
308
- ```
309
-
310
- - [ ] **Step 4: Run tests to verify they pass**
311
-
312
- Run: `npx vitest run tests/lib/cortex/knowledge/compat.test.ts`
313
- Expected: PASS (10 tests)
314
-
315
- - [ ] **Step 5: Commit**
316
-
317
- ```bash
318
- git add src/lib/cortex/knowledge/compat.ts tests/lib/cortex/knowledge/compat.test.ts
319
- git commit -m "feat(cortex): add v1↔v2 layer/scope compatibility mapping"
320
- ```
321
-
322
- ---
323
-
324
- ### Task 3: Evidence score computation
325
-
326
- **Files:**
327
- - Create: `src/lib/cortex/knowledge/evidence.ts`
328
- - Create: `tests/lib/cortex/knowledge/evidence.test.ts`
329
-
330
- - [ ] **Step 1: Write failing tests**
331
-
332
- ```typescript
333
- // tests/lib/cortex/knowledge/evidence.test.ts
334
- import { describe, it, expect } from 'vitest';
335
- import { computeEvidenceScore, AUTHORITY_FACTORS } from '@/lib/cortex/knowledge/evidence';
336
-
337
- describe('computeEvidenceScore', () => {
338
- it('returns base confidence for fresh unit with no interactions', () => {
339
- const score = computeEvidenceScore({
340
- baseConfidence: 0.8,
341
- corroborations: 0,
342
- accessCount: 0,
343
- authorityFactor: 1.0,
344
- contradictionCount: 0,
345
- });
346
- expect(score).toBeCloseTo(0.8);
347
- });
348
-
349
- it('increases with corroborations', () => {
350
- const base = computeEvidenceScore({
351
- baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
352
- });
353
- const withCorr = computeEvidenceScore({
354
- baseConfidence: 0.8, corroborations: 3, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
355
- });
356
- expect(withCorr).toBeGreaterThan(base);
357
- });
358
-
359
- it('increases with access count (diminishing returns)', () => {
360
- const low = computeEvidenceScore({
361
- baseConfidence: 0.8, corroborations: 0, accessCount: 5, authorityFactor: 1.0, contradictionCount: 0,
362
- });
363
- const high = computeEvidenceScore({
364
- baseConfidence: 0.8, corroborations: 0, accessCount: 50, authorityFactor: 1.0, contradictionCount: 0,
365
- });
366
- expect(high).toBeGreaterThan(low);
367
- // Capped at 50 — going higher has no effect
368
- const over = computeEvidenceScore({
369
- baseConfidence: 0.8, corroborations: 0, accessCount: 100, authorityFactor: 1.0, contradictionCount: 0,
370
- });
371
- expect(over).toBeCloseTo(high);
372
- });
373
-
374
- it('decreases with contradictions', () => {
375
- const clean = computeEvidenceScore({
376
- baseConfidence: 0.8, corroborations: 2, accessCount: 10, authorityFactor: 1.0, contradictionCount: 0,
377
- });
378
- const contested = computeEvidenceScore({
379
- baseConfidence: 0.8, corroborations: 2, accessCount: 10, authorityFactor: 1.0, contradictionCount: 2,
380
- });
381
- expect(contested).toBeLessThan(clean);
382
- });
383
-
384
- it('caps corroboration contribution at 10', () => {
385
- const at10 = computeEvidenceScore({
386
- baseConfidence: 0.8, corroborations: 10, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
387
- });
388
- const at20 = computeEvidenceScore({
389
- baseConfidence: 0.8, corroborations: 20, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
390
- });
391
- expect(at20).toBeCloseTo(at10); // no additional benefit beyond 10
392
- });
393
-
394
- it('is boosted by authority factor', () => {
395
- const conversation = computeEvidenceScore({
396
- baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: AUTHORITY_FACTORS.conversation, contradictionCount: 0,
397
- });
398
- const document = computeEvidenceScore({
399
- baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: AUTHORITY_FACTORS.document, contradictionCount: 0,
400
- });
401
- expect(document).toBeGreaterThan(conversation);
402
- });
403
-
404
- it('is capped at 1.0', () => {
405
- const score = computeEvidenceScore({
406
- baseConfidence: 0.95, corroborations: 10, accessCount: 50, authorityFactor: 1.3, contradictionCount: 0,
407
- });
408
- expect(score).toBeLessThanOrEqual(1.0);
409
- });
410
-
411
- it('never goes below 0', () => {
412
- const score = computeEvidenceScore({
413
- baseConfidence: 0.1, corroborations: 0, accessCount: 0, authorityFactor: 1.0, contradictionCount: 10,
414
- });
415
- expect(score).toBeGreaterThanOrEqual(0);
416
- });
417
- });
418
- ```
419
-
420
- - [ ] **Step 2: Run tests to verify they fail**
421
-
422
- Run: `npx vitest run tests/lib/cortex/knowledge/evidence.test.ts`
423
-
424
- - [ ] **Step 3: Implement evidence score**
425
-
426
- ```typescript
427
- // src/lib/cortex/knowledge/evidence.ts
428
-
429
- export const AUTHORITY_FACTORS = {
430
- conversation: 1.0,
431
- git_commit: 1.1,
432
- pr_review: 1.1,
433
- document: 1.2,
434
- behavioral: 1.0,
435
- distillation: 1.1,
436
- manual: 1.3,
437
- } as const;
438
-
439
- export interface EvidenceScoreInput {
440
- baseConfidence: number;
441
- corroborations: number;
442
- accessCount: number;
443
- authorityFactor: number;
444
- contradictionCount: number;
445
- }
446
-
447
- /**
448
- * Compute evidence score (0-1) from knowledge unit metrics.
449
- *
450
- * Formula from spec:
451
- * evidence_score = min(1.0,
452
- * base_confidence
453
- * × (1 + 0.1 × corroborations)
454
- * × (1 + 0.01 × min(access_count, 50))
455
- * × authority_factor
456
- * ÷ (1 + 0.5 × contradiction_count)
457
- * )
458
- */
459
- export function computeEvidenceScore(input: EvidenceScoreInput): number {
460
- const { baseConfidence, corroborations, accessCount, authorityFactor, contradictionCount } = input;
461
-
462
- const corroborationBoost = 1 + 0.1 * Math.min(corroborations, 10);
463
- const accessBoost = 1 + 0.01 * Math.min(accessCount, 50);
464
- const contradictionPenalty = 1 + 0.5 * contradictionCount;
465
-
466
- const raw = (baseConfidence * corroborationBoost * accessBoost * authorityFactor) / contradictionPenalty;
467
-
468
- return Math.max(0, Math.min(1.0, raw));
469
- }
470
- ```
471
-
472
- - [ ] **Step 4: Run tests to verify they pass**
473
-
474
- Run: `npx vitest run tests/lib/cortex/knowledge/evidence.test.ts`
475
- Expected: PASS (7 tests)
476
-
477
- - [ ] **Step 5: Commit**
478
-
479
- ```bash
480
- git add src/lib/cortex/knowledge/evidence.ts tests/lib/cortex/knowledge/evidence.test.ts
481
- git commit -m "feat(cortex): add evidence score computation"
482
- ```
483
-
484
- ---
485
-
486
- ## Chunk 2: LanceDB Schema Evolution and Store Updates
487
-
488
- ### Task 4: Evolve Arrow schema with v2 fields and table migration
489
-
490
- **Files:**
491
- - Create: `src/lib/cortex/store-migration.ts`
492
- - Modify: `src/lib/cortex/store.ts`
493
- - Modify: `tests/lib/cortex/store.test.ts`
494
-
495
- > **CRITICAL:** LanceDB is strict about schema — you cannot add records with columns that don't exist in the table's schema. Existing v1 tables lack the 9 new v2 columns. We must migrate existing tables by adding the new columns before any v2 writes.
496
-
497
- - [ ] **Step 1: Read the current store.ts**
498
-
499
- Read `src/lib/cortex/store.ts` to understand:
500
- - The `buildSchema(dimensions)` function (Arrow field definitions)
501
- - The `unitToRecord` serialization
502
- - The deserialization in `search()` and `browse()`
503
- - The `updateAccessCount()` method (delete + re-add pattern)
504
- - How `getConnection()` opens tables
505
-
506
- - [ ] **Step 1b: Create store-migration.ts**
507
-
508
- ```typescript
509
- // src/lib/cortex/store-migration.ts
510
- import type { Table } from '@lancedb/lancedb';
511
-
512
- /**
513
- * V2 columns to add to existing LanceDB tables.
514
- * Each entry: [column_name, sql_expression_for_default_value]
515
- */
516
- const V2_COLUMNS: [string, string][] = [
517
- ['scope', "'null'"], // JSON string, null for v1 data
518
- ['entity_links', "'[]'"], // JSON array string
519
- ['evidence_score', '0.5'], // float default
520
- ['corroborations', '0'], // int default
521
- ['contradiction_refs', "'[]'"], // JSON array string
522
- ['sensitivity', "'internal'"], // string default
523
- ['creator_scope', "'null'"], // JSON string, null
524
- ['origin', "'null'"], // JSON string, null
525
- ['propagation_path', "'[]'"], // JSON array string
526
- ];
527
-
528
- /**
529
- * Migrate a LanceDB table to v2 schema by adding missing columns.
530
- * Safe to call repeatedly — checks column existence before adding.
531
- */
532
- export async function migrateTableToV2(table: Table): Promise<void> {
533
- const schema = await table.schema;
534
- const existingFields = new Set(schema.fields.map(f => f.name));
535
-
536
- for (const [colName, defaultExpr] of V2_COLUMNS) {
537
- if (!existingFields.has(colName)) {
538
- try {
539
- await table.addColumns([{ name: colName, valueSql: defaultExpr }]);
540
- } catch {
541
- // Column may have been added concurrently, ignore
542
- }
543
- }
544
- }
545
- }
546
- ```
547
-
548
- This uses LanceDB's `table.addColumns()` API to add nullable columns with default values to existing tables in-place, without needing to read/drop/recreate.
549
-
550
- - [ ] **Step 2: Write a failing test for v2 fields**
551
-
552
- Add to `tests/lib/cortex/store.test.ts`:
553
-
554
- ```typescript
555
- describe('CortexStore — v2 fields', () => {
556
- let tmpDir: string;
557
- let store: CortexStore;
558
-
559
- beforeEach(async () => {
560
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cortex-store-'));
561
- store = new CortexStore(tmpDir);
562
- await store.init(384);
563
- });
564
-
565
- afterEach(async () => {
566
- await store.close();
567
- fs.rmSync(tmpDir, { recursive: true, force: true });
568
- });
569
-
570
- it('stores and retrieves v2 fields', async () => {
571
- const vector = new Array(384).fill(0).map(() => Math.random());
572
- const unit = {
573
- id: 'v2-test-1',
574
- vector,
575
- text: 'Auth uses JWT with refresh tokens',
576
- type: 'decision' as const,
577
- layer: 'personal' as const,
578
- workspace_id: null,
579
- session_id: 'sess-1',
580
- agent_type: 'claude' as const,
581
- project_path: '/project',
582
- file_refs: ['src/auth.ts'],
583
- confidence: 0.85,
584
- created: new Date().toISOString(),
585
- source_timestamp: new Date().toISOString(),
586
- stale_score: 0,
587
- access_count: 0,
588
- last_accessed: null,
589
- metadata: {},
590
- // v2 fields
591
- scope: { level: 'personal' as const, entity_id: 'person-alice' },
592
- entity_links: [
593
- { entity_id: 'topic-auth', entity_type: 'topic', relation: 'about' as const, weight: 0.9 },
594
- ],
595
- evidence_score: 0.72,
596
- corroborations: 2,
597
- contradiction_refs: ['other-id-1'],
598
- sensitivity: 'internal' as const,
599
- creator_scope: null,
600
- origin: { source_type: 'conversation' as const, source_ref: 'sess-1', creator_entity_id: 'person-alice' },
601
- propagation_path: [],
602
- };
603
-
604
- await store.add('personal', unit);
605
- const results = await store.search('personal', vector, 5);
606
- expect(results).toHaveLength(1);
607
-
608
- const result = results[0];
609
- expect(result.scope).toEqual({ level: 'personal', entity_id: 'person-alice' });
610
- expect(result.entity_links).toHaveLength(1);
611
- expect(result.entity_links![0].entity_id).toBe('topic-auth');
612
- expect(result.evidence_score).toBeCloseTo(0.72);
613
- expect(result.corroborations).toBe(2);
614
- expect(result.contradiction_refs).toEqual(['other-id-1']);
615
- expect(result.sensitivity).toBe('internal');
616
- expect(result.origin?.source_type).toBe('conversation');
617
- });
618
-
619
- it('reads v1 data with default v2 fields', async () => {
620
- const vector = new Array(384).fill(0).map(() => Math.random());
621
- // Store a unit WITHOUT v2 fields (simulating v1 data)
622
- const unit = {
623
- id: 'v1-test-1',
624
- vector,
625
- text: 'Old v1 knowledge',
626
- type: 'context' as const,
627
- layer: 'personal' as const,
628
- workspace_id: null,
629
- session_id: null,
630
- agent_type: 'claude' as const,
631
- project_path: null,
632
- file_refs: [],
633
- confidence: 0.6,
634
- created: new Date().toISOString(),
635
- source_timestamp: new Date().toISOString(),
636
- stale_score: 0,
637
- access_count: 0,
638
- last_accessed: null,
639
- metadata: {},
640
- };
641
-
642
- await store.add('personal', unit);
643
- const results = await store.search('personal', vector, 5);
644
- const result = results[0];
645
-
646
- // v2 fields should have sensible defaults
647
- expect(result.evidence_score).toBe(0.5);
648
- expect(result.corroborations).toBe(0);
649
- expect(result.contradiction_refs).toEqual([]);
650
- expect(result.sensitivity).toBe('internal');
651
- expect(result.entity_links).toEqual([]);
652
- expect(result.propagation_path).toEqual([]);
653
- });
654
- });
655
- ```
656
-
657
- - [ ] **Step 3: Run tests to verify they fail**
658
-
659
- Run: `npx vitest run tests/lib/cortex/store.test.ts`
660
-
661
- - [ ] **Step 4: Evolve the Arrow schema**
662
-
663
- In `src/lib/cortex/store.ts`, add new Arrow fields to the schema builder function. These are all nullable Utf8 fields (JSON-serialized for complex types) or nullable Float64/Int32 for numbers:
664
-
665
- ```typescript
666
- // Add after existing fields in the schema:
667
- new arrow.Field('scope', new arrow.Utf8(), true), // JSON: { level, entity_id }
668
- new arrow.Field('entity_links', new arrow.Utf8(), true), // JSON array
669
- new arrow.Field('evidence_score', new arrow.Float64(), true), // nullable
670
- new arrow.Field('corroborations', new arrow.Int32(), true), // nullable
671
- new arrow.Field('contradiction_refs', new arrow.Utf8(), true), // JSON array
672
- new arrow.Field('sensitivity', new arrow.Utf8(), true), // nullable
673
- new arrow.Field('creator_scope', new arrow.Utf8(), true), // JSON or null
674
- new arrow.Field('origin', new arrow.Utf8(), true), // JSON or null
675
- new arrow.Field('propagation_path', new arrow.Utf8(), true), // JSON array
676
- ```
677
-
678
- In the `add()` method, after opening/creating the table but before `table.add([record])`, call migration:
679
- ```typescript
680
- import { migrateTableToV2 } from './store-migration';
681
-
682
- // In add(), after getting/creating the table:
683
- await migrateTableToV2(table);
684
- ```
685
-
686
- Also call `migrateTableToV2` in `search()` and `browse()` after getting the table, to ensure reads from v1 tables also get the new columns. Cache a Set of already-migrated table paths to avoid repeated migration checks.
687
-
688
- Update the serialization (unitToRecord) to include v2 fields:
689
- ```typescript
690
- scope: unit.scope ? JSON.stringify(unit.scope) : null,
691
- entity_links: JSON.stringify(unit.entity_links ?? []),
692
- evidence_score: unit.evidence_score ?? 0.5,
693
- corroborations: unit.corroborations ?? 0,
694
- contradiction_refs: JSON.stringify(unit.contradiction_refs ?? []),
695
- sensitivity: unit.sensitivity ?? 'internal',
696
- creator_scope: unit.creator_scope ? JSON.stringify(unit.creator_scope) : null,
697
- origin: unit.origin ? JSON.stringify(unit.origin) : null,
698
- propagation_path: JSON.stringify(unit.propagation_path ?? []),
699
- ```
700
-
701
- **CRITICAL: Also update `updateAccessCount()`** — this method uses a delete+re-add pattern that reconstructs the record from raw fields. It must include all v2 fields in the reconstruction to avoid dropping them:
702
-
703
- ```typescript
704
- // In updateAccessCount(), when reconstructing the record, add:
705
- scope: raw.scope ?? null,
706
- entity_links: raw.entity_links ?? '[]',
707
- evidence_score: raw.evidence_score ?? 0.5,
708
- corroborations: raw.corroborations ?? 0,
709
- contradiction_refs: raw.contradiction_refs ?? '[]',
710
- sensitivity: raw.sensitivity ?? 'internal',
711
- creator_scope: raw.creator_scope ?? null,
712
- origin: raw.origin ?? null,
713
- propagation_path: raw.propagation_path ?? '[]',
714
- ```
715
-
716
- **Also update `browse()` deserialization** — `browse()` has its own row-mapping logic separate from `search()`. Apply the same v2 field parsing to `browse()` results.
717
-
718
- Update deserialization in BOTH `search()` and `browse()` to parse v2 fields with defaults:
719
- ```typescript
720
- scope: row.scope ? JSON.parse(row.scope) : undefined,
721
- entity_links: JSON.parse(row.entity_links || '[]'),
722
- evidence_score: row.evidence_score ?? 0.5,
723
- corroborations: row.corroborations ?? 0,
724
- contradiction_refs: JSON.parse(row.contradiction_refs || '[]'),
725
- sensitivity: row.sensitivity || 'internal',
726
- creator_scope: row.creator_scope ? JSON.parse(row.creator_scope) : null,
727
- origin: row.origin ? JSON.parse(row.origin) : undefined,
728
- propagation_path: JSON.parse(row.propagation_path || '[]'),
729
- ```
730
-
731
- - [ ] **Step 5: Run tests to verify they pass**
732
-
733
- Run: `npx vitest run tests/lib/cortex/store.test.ts`
734
- Expected: All tests pass (existing + 2 new)
735
-
736
- - [ ] **Step 6: Commit**
737
-
738
- ```bash
739
- git add src/lib/cortex/store.ts tests/lib/cortex/store.test.ts
740
- git commit -m "feat(cortex): evolve LanceDB schema with v2 knowledge unit fields"
741
- ```
742
-
743
- ---
744
-
745
- ### Task 5: Update search and scoring for v2
746
-
747
- **Files:**
748
- - Modify: `src/lib/cortex/retrieval/scoring.ts`
749
- - Modify: `src/lib/cortex/retrieval/search.ts`
750
- - Modify: `tests/lib/cortex/retrieval/search.test.ts`
751
-
752
- - [ ] **Step 1: Read current search.ts and scoring.ts**
753
-
754
- Read both files to understand the current scoring formula and search layer iteration.
755
-
756
- - [ ] **Step 2: Write a failing test for evidence-aware scoring**
757
-
758
- Add to `tests/lib/cortex/retrieval/scoring.test.ts` (or the existing scoring test file):
759
-
760
- ```typescript
761
- import { computeRelevanceScore } from '@/lib/cortex/retrieval/scoring';
762
-
763
- it('uses evidence_score when provided instead of confidence', () => {
764
- const withConfidenceOnly = computeRelevanceScore({
765
- similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
766
- });
767
- const withHighEvidence = computeRelevanceScore({
768
- similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
769
- evidence_score: 0.95,
770
- });
771
- const withLowEvidence = computeRelevanceScore({
772
- similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
773
- evidence_score: 0.3,
774
- });
775
-
776
- // evidence_score should override confidence in the formula
777
- expect(withHighEvidence).toBeGreaterThan(withConfidenceOnly);
778
- expect(withLowEvidence).toBeLessThan(withConfidenceOnly);
779
- });
780
-
781
- it('falls back to confidence when evidence_score is undefined', () => {
782
- const result = computeRelevanceScore({
783
- similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
784
- });
785
- // Should use confidence (0.8) as the evidence factor
786
- expect(result).toBeGreaterThan(0);
787
- });
788
- ```
789
-
790
- - [ ] **Step 3: Update scoring.ts to incorporate evidence_score**
791
-
792
- Add `evidence_score` as an optional parameter to `computeRelevanceScore`:
793
-
794
- ```typescript
795
- export function computeRelevanceScore(params: {
796
- similarity: number;
797
- confidence: number;
798
- stale_score: number;
799
- created: string;
800
- evidence_score?: number; // NEW: v2 evidence score
801
- }): number {
802
- const recencyBoost = computeRecencyBoost(params.created);
803
- const evidence = params.evidence_score ?? params.confidence; // fallback to confidence for v1 data
804
- return Math.min(1.0, params.similarity * evidence * (1 - params.stale_score) * recencyBoost);
805
- }
806
- ```
807
-
808
- - [ ] **Step 4: Update search.ts to pass evidence_score in ALL scoring calls**
809
-
810
- In the search method, pass `evidence_score` in BOTH the initial scoring AND the staleness recomputation:
811
-
812
- ```typescript
813
- // Initial scoring (in the per-layer loop):
814
- const relevance = computeRelevanceScore({
815
- similarity,
816
- confidence: unit.confidence,
817
- stale_score: unit.stale_score,
818
- created: unit.created,
819
- evidence_score: unit.evidence_score, // NEW
820
- }) * weight;
821
- ```
822
-
823
- Also find the staleness recomputation block (where `computeStaleness` results are used to re-score) and pass `evidence_score` there too:
824
- ```typescript
825
- // After staleness recomputation:
826
- r.relevance_score = computeRelevanceScore({
827
- similarity: r.similarity,
828
- confidence: r.confidence,
829
- stale_score: r.stale_score,
830
- created: r.created,
831
- evidence_score: r.evidence_score, // NEW — must be here too
832
- }) * (LAYER_WEIGHTS[r.layer] ?? 0.5);
833
- ```
834
-
835
- - [ ] **Step 5: Run tests to verify they pass**
836
-
837
- Run: `npx vitest run tests/lib/cortex/retrieval/`
838
- Expected: All tests pass
839
-
840
- - [ ] **Step 6: Commit**
841
-
842
- ```bash
843
- git add src/lib/cortex/retrieval/scoring.ts src/lib/cortex/retrieval/search.ts tests/lib/cortex/retrieval/search.test.ts
844
- git commit -m "feat(cortex): incorporate evidence_score into retrieval scoring"
845
- ```
846
-
847
- ---
848
-
849
- ## Chunk 3: API Backward Compatibility
850
-
851
- ### Task 6: Update knowledge API to accept both layer and scope
852
-
853
- **Files:**
854
- - Modify: `src/app/api/cortex/knowledge/route.ts`
855
-
856
- - [ ] **Step 1: Read current knowledge/route.ts**
857
-
858
- - [ ] **Step 2: Update POST handler to accept both formats**
859
-
860
- The POST handler currently requires `layer`. Update it to:
861
- 1. Accept `scope` as an alternative to `layer`
862
- 2. If `scope` is provided, use it directly and derive `layer` for backward compat
863
- 3. If only `layer` is provided, derive `scope` from it
864
- 4. Accept new v2 fields: `sensitivity`, `origin`, `entity_links`
865
-
866
- ```typescript
867
- // In POST handler, after parsing body:
868
- const { text, type, workspace_id } = body;
869
- let { layer, scope, sensitivity, origin, entity_links } = body;
870
-
871
- // Validate: need either layer or scope
872
- if (!text || !type) {
873
- return NextResponse.json({ error: 'text and type are required' }, { status: 400 });
874
- }
875
-
876
- if (!layer && !scope) {
877
- return NextResponse.json({ error: 'layer or scope is required' }, { status: 400 });
878
- }
879
-
880
- // Resolve layer ↔ scope
881
- if (scope && !layer) {
882
- layer = scopeToLayer(scope);
883
- } else if (layer && !scope) {
884
- scope = layerToScope(layer, workspace_id);
885
- }
886
-
887
- // Compute layerKey from scope (or fallback to old method)
888
- const layerKey = scope
889
- ? scopeToLayerKey(scope, workspace_id)
890
- : (layer === 'workspace' && workspace_id ? `workspace/${workspace_id}` : layer);
891
- ```
892
-
893
- Import the compat functions:
894
- ```typescript
895
- import { layerToScope, scopeToLayer, scopeToLayerKey } from '@/lib/cortex/knowledge/compat';
896
- ```
897
-
898
- Add v2 fields to the unit construction. Use `getConfidenceBase(type)` for initial evidence_score (not a flat 0.5 — per spec, evidence starts from the type's base confidence). Derive `creator_entity_id` from the authenticated user:
899
-
900
- ```typescript
901
- import { getConfidenceBase } from '@/lib/cortex/knowledge/types';
902
-
903
- // In unit construction:
904
- scope,
905
- entity_links: entity_links ?? [],
906
- evidence_score: getConfidenceBase(type), // NOT 0.5 — matches spec
907
- corroborations: 0,
908
- contradiction_refs: [],
909
- sensitivity: sensitivity ?? 'internal',
910
- creator_scope: null,
911
- origin: origin ?? { source_type: 'manual', source_ref: '', creator_entity_id: `person-${user}` },
912
- propagation_path: [],
913
- ```
914
-
915
- Note: `user` is already available from `getAuthUser(request)` at the top of the handler.
916
-
917
- - [ ] **Step 3: Commit**
918
-
919
- ```bash
920
- git add src/app/api/cortex/knowledge/route.ts
921
- git commit -m "feat(cortex): accept both layer and scope in knowledge API"
922
- ```
923
-
924
- ---
925
-
926
- ### Task 7: Update MCP tools to accept both layer and scope
927
-
928
- **Files:**
929
- - Modify: `src/lib/cortex/mcp/server.ts`
930
-
931
- - [ ] **Step 1: Read current mcp/server.ts**
932
-
933
- Read the `cortex_teach` tool schema and handler to understand what fields are accepted.
934
-
935
- - [ ] **Step 2: Update cortex_teach tool**
936
-
937
- 1. Add `scope` as an optional property in the tool's input schema (alongside existing `layer`)
938
- 2. In the handler, apply the same layer↔scope resolution logic from Task 6
939
- 3. Add `sensitivity` and `origin` as optional properties
940
- 4. Include v2 fields in the unit construction, using `getConfidenceBase(type)` for evidence_score (not 0.5)
941
- 5. Derive `creator_entity_id` from the agent context (use `'person-default-user'` as placeholder since MCP tools don't have user auth context — the real entity ID will be resolved by Pillar 5)
942
-
943
- The key change: `layer` remains supported but `scope` is preferred. If both are provided, `scope` wins.
944
-
945
- Import compat functions:
946
- ```typescript
947
- import { layerToScope, scopeToLayer, scopeToLayerKey } from '../knowledge/compat';
948
- ```
949
-
950
- - [ ] **Step 3: Commit**
951
-
952
- ```bash
953
- git add src/lib/cortex/mcp/server.ts
954
- git commit -m "feat(cortex): accept both layer and scope in MCP cortex_teach tool"
955
- ```
956
-
957
- ---
958
-
959
- ### Task 8: Update learn hook for v2 compatibility
960
-
961
- **Files:**
962
- - Modify: `bin/cortex-learn-hook.js`
963
-
964
- - [ ] **Step 1: Read current cortex-learn-hook.js**
965
-
966
- - [ ] **Step 2: Add scope field alongside layer**
967
-
968
- The hook currently POSTs `{ text, type, layer: 'personal' }`. Update both entries to also include:
969
-
970
- ```javascript
971
- const scope = JSON.stringify({ level: 'personal', entity_id: 'person-default-user' });
972
-
973
- // Question entry:
974
- const questionEntry = JSON.stringify({
975
- text: lastExchange.question,
976
- type: 'context',
977
- layer: 'personal',
978
- scope: { level: 'personal', entity_id: 'person-default-user' },
979
- origin: { source_type: 'conversation', source_ref: sessionId || '', creator_entity_id: 'person-default-user' },
980
- });
981
-
982
- // Answer entry:
983
- const answerEntry = JSON.stringify({
984
- text: `Q: ${lastExchange.question}\nA: ${condensedAnswer}`,
985
- type: knowledgeType,
986
- layer: 'personal',
987
- scope: { level: 'personal', entity_id: 'person-default-user' },
988
- origin: { source_type: 'conversation', source_ref: sessionId || '', creator_entity_id: 'person-default-user' },
989
- });
990
- ```
991
-
992
- Note: `sessionId` should be extracted from the input JSON if available (the hook receives `{ transcript_path }` — the session ID is the filename without extension).
993
-
994
- - [ ] **Step 3: Commit**
995
-
996
- ```bash
997
- git add bin/cortex-learn-hook.js
998
- git commit -m "feat(cortex): add scope and origin to learn hook knowledge entries"
999
- ```
1000
-
1001
- ---
1002
-
1003
- ## Chunk 4: Pipeline Integration and Final Tests
1004
-
1005
- ### Task 9: Update ingestion pipeline for v2 fields
1006
-
1007
- **Files:**
1008
- - Modify: `src/lib/cortex/ingestion/pipeline.ts`
1009
- - Modify: `src/lib/cortex/ingestion/chunker.ts`
1010
-
1011
- - [ ] **Step 1: Read pipeline.ts and chunker.ts**
1012
-
1013
- - [ ] **Step 2: Update RawChunk → KnowledgeUnit mapping in pipeline**
1014
-
1015
- In the pipeline where KnowledgeUnit is constructed from RawChunk, add v2 fields with defaults:
1016
-
1017
- ```typescript
1018
- const unit: KnowledgeUnit = {
1019
- // ... existing v1 fields ...
1020
- // v2 fields with defaults
1021
- scope: layerToScope(chunk.layer, chunk.workspace_id),
1022
- entity_links: [],
1023
- evidence_score: getConfidenceBase(chunk.type), // start with base confidence
1024
- corroborations: 0,
1025
- contradiction_refs: [],
1026
- sensitivity: 'internal',
1027
- creator_scope: null,
1028
- origin: {
1029
- source_type: 'conversation',
1030
- source_ref: chunk.session_id ?? '',
1031
- creator_entity_id: 'person-default-user',
1032
- },
1033
- propagation_path: [],
1034
- };
1035
- ```
1036
-
1037
- Import the compat function:
1038
- ```typescript
1039
- import { layerToScope } from '../knowledge/compat';
1040
- ```
1041
-
1042
- - [ ] **Step 3: Run the full cortex test suite**
1043
-
1044
- Run: `npx vitest run tests/lib/cortex/`
1045
- Expected: All tests pass (including existing pipeline tests)
1046
-
1047
- - [ ] **Step 4: Commit**
1048
-
1049
- ```bash
1050
- git add src/lib/cortex/ingestion/pipeline.ts
1051
- git commit -m "feat(cortex): add v2 fields to ingestion pipeline output"
1052
- ```
1053
-
1054
- ---
1055
-
1056
- ### Task 10: Export knowledge/compat and evidence from knowledge index
1057
-
1058
- **Files:**
1059
- - Modify or create: `src/lib/cortex/knowledge/index.ts` (if a barrel exists, update it; if not, create one)
1060
-
1061
- - [ ] **Step 1: Check if knowledge/index.ts exists**
1062
-
1063
- Read `src/lib/cortex/knowledge/` directory to see if there's a barrel export.
1064
-
1065
- - [ ] **Step 2: Create or update barrel export**
1066
-
1067
- Ensure these are re-exported:
1068
- ```typescript
1069
- export { layerToScope, scopeToLayer, scopeToLayerKey, layerKeyToScope } from './compat';
1070
- export { computeEvidenceScore, AUTHORITY_FACTORS } from './evidence';
1071
- export type { EvidenceScoreInput } from './evidence';
1072
- // Existing type exports from types.ts should already be accessible
1073
- ```
1074
-
1075
- - [ ] **Step 3: Run the full test suite**
1076
-
1077
- Run: `npx vitest run tests/lib/cortex/`
1078
- Expected: All tests pass
1079
-
1080
- - [ ] **Step 4: Commit**
1081
-
1082
- ```bash
1083
- git add src/lib/cortex/knowledge/
1084
- git commit -m "feat(cortex): export compat and evidence modules from knowledge barrel"
1085
- ```
1086
-
1087
- ---
1088
-
1089
- ## Summary
1090
-
1091
- | Task | Component | Tests | Status |
1092
- |------|-----------|-------|--------|
1093
- | 1 | v2 type definitions | — | |
1094
- | 2 | v1↔v2 compatibility layer | 10 | |
1095
- | 3 | Evidence score computation | 8 | |
1096
- | 4 | Arrow schema evolution | 2 | |
1097
- | 5 | Search/scoring update | 2 | |
1098
- | 6 | Knowledge API backward compat | — | |
1099
- | 7 | MCP tool backward compat | — | |
1100
- | 8 | Learn hook v2 fields | — | |
1101
- | 9 | Pipeline v2 integration | regression | |
1102
- | 10 | Barrel export | regression | |
1103
-
1104
- **Total: 10 tasks, ~22 new tests, 4 chunks**
1105
-
1106
- **Key design decisions:**
1107
- - `layer` field is KEPT on KnowledgeUnit for backward compat (intentional spec deviation — spec says "removed" but we keep it as derived field)
1108
- - v2 fields are all optional/nullable — existing LanceDB tables migrated in-place via `addColumns()` during `store.init()`
1109
- - `updateAccessCount()` and `browse()` updated to preserve/parse v2 fields
1110
- - API accepts both `layer` and `scope` params — `scope` takes precedence
1111
- - Evidence score starts at `base_confidence` and evolves with access/corroboration (computed by Pillar 6: Gravity)
1112
-
1113
- After this plan is complete, both the Entity Graph (Pillar 1) and Knowledge Unit Evolution (Pillar 2) will be in place — enabling Pillar 3 (Context Assembly Engine) and Pillar 4 (Boundary Engine) to build on them.
1
+ # Cortex v2 — Pillar 2: Knowledge Unit Schema Evolution
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:** Evolve the KnowledgeUnit schema from flat `layer` to graph-aware `scope`, add entity links, evidence tracking, sensitivity classification, and provenance — while maintaining full backward compatibility with the v1 API and existing ~542 knowledge units.
6
+
7
+ **Architecture:** The `layer` field is KEPT for backward compatibility (spec says "removed" but we intentionally keep it as a derived field to avoid breaking existing consumers — this is a documented deviation). New v2 fields (`scope`, `entity_links`, `evidence_score`, etc.) are added as nullable Arrow columns. Existing LanceDB tables are migrated in-place using LanceDB's `addColumns()` API in a migration step during `store.init()`. A compatibility layer maps v1 `layer` params to v2 `scope` in all API routes, MCP tools, and hooks.
8
+
9
+ **Tech Stack:** TypeScript, LanceDB (Arrow schema), vitest
10
+
11
+ **Spec:** `docs/superpowers/specs/2026-03-14-cortex-v2-design.md` — Pillar 2
12
+
13
+ **Depends on:** Pillar 1 (Entity Graph) — completed
14
+
15
+ ---
16
+
17
+ ## File Structure
18
+
19
+ ```
20
+ Modified files:
21
+ ├── src/lib/cortex/knowledge/types.ts — Add v2 interfaces, keep v1 layer for compat (intentional spec deviation)
22
+ ├── src/lib/cortex/knowledge/evidence.ts — NEW: evidence score computation
23
+ ├── src/lib/cortex/knowledge/compat.ts — NEW: v1↔v2 layer/scope mapping
24
+ ├── src/lib/cortex/store.ts — Evolve Arrow schema, add v2 fields, migrate existing tables
25
+ ├── src/lib/cortex/store-migration.ts — NEW: LanceDB table schema migration (addColumns)
26
+ ├── src/lib/cortex/retrieval/search.ts — Use scope instead of layer for weights
27
+ ├── src/lib/cortex/retrieval/scoring.ts — Add evidence_score to formula
28
+ ├── src/app/api/cortex/knowledge/route.ts — Accept both layer and scope params
29
+ ├── src/lib/cortex/mcp/server.ts — Accept both layer and scope in tools
30
+ ├── bin/cortex-learn-hook.js — Map 'personal' to scope format
31
+
32
+ Test files:
33
+ ├── tests/lib/cortex/knowledge/evidence.test.ts — Evidence score computation
34
+ ├── tests/lib/cortex/knowledge/compat.test.ts — v1↔v2 mapping
35
+ ├── tests/lib/cortex/knowledge/types.test.ts — Updated for v2 types
36
+ ├── tests/lib/cortex/store.test.ts — Updated for v2 schema
37
+ ├── tests/lib/cortex/retrieval/search.test.ts — Updated for scope-based weights
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Chunk 1: New Types and Compatibility Layer
43
+
44
+ ### Task 1: Add v2 type definitions
45
+
46
+ **Files:**
47
+ - Modify: `src/lib/cortex/knowledge/types.ts`
48
+
49
+ - [ ] **Step 1: Add new interfaces after existing ones (keep all v1 types for backward compat)**
50
+
51
+ Add these types to `src/lib/cortex/knowledge/types.ts` below the existing interfaces:
52
+
53
+ ```typescript
54
+ // --- v2 Schema Extensions ---
55
+
56
+ export const SCOPE_LEVELS = ['personal', 'team', 'department', 'organization'] as const;
57
+ export type ScopeLevel = typeof SCOPE_LEVELS[number];
58
+
59
+ export interface Scope {
60
+ level: ScopeLevel;
61
+ entity_id: string; // format: {type}-{slug}
62
+ }
63
+
64
+ export interface EntityLink {
65
+ entity_id: string;
66
+ entity_type: EntityType; // imported from graph module
67
+ relation: 'created_by' | 'about' | 'scoped_to' | 'derived_from';
68
+ weight: number; // 0-1
69
+ }
70
+ ```
71
+
72
+ Add this import at the top of types.ts:
73
+ ```typescript
74
+ import type { EntityType } from '@/lib/cortex/graph/types';
75
+
76
+ export const SENSITIVITY_CLASSES = ['public', 'internal', 'restricted', 'confidential'] as const;
77
+ export type SensitivityClass = typeof SENSITIVITY_CLASSES[number];
78
+
79
+ export interface ScopeOverride {
80
+ max_level: ScopeLevel;
81
+ }
82
+
83
+ export const ORIGIN_SOURCE_TYPES = [
84
+ 'conversation', 'git_commit', 'pr_review', 'document',
85
+ 'behavioral', 'distillation', 'manual',
86
+ ] as const;
87
+ export type OriginSourceType = typeof ORIGIN_SOURCE_TYPES[number];
88
+
89
+ export interface Origin {
90
+ source_type: OriginSourceType;
91
+ source_ref: string;
92
+ creator_entity_id: string;
93
+ }
94
+
95
+ export interface PropHop {
96
+ from_scope: Scope;
97
+ to_scope: Scope;
98
+ reason: 'evidence_threshold' | 'policy_push' | 'manual_promote';
99
+ timestamp: string;
100
+ confidence_at_hop: number;
101
+ }
102
+
103
+ export function isValidScopeLevel(s: string): s is ScopeLevel {
104
+ return SCOPE_LEVELS.includes(s as ScopeLevel);
105
+ }
106
+
107
+ export function isValidSensitivity(s: string): s is SensitivityClass {
108
+ return SENSITIVITY_CLASSES.includes(s as SensitivityClass);
109
+ }
110
+ ```
111
+
112
+ - [ ] **Step 1b: Update HOP_DECAY_FACTOR from 0.8 to 0.85**
113
+
114
+ Per spec Key Constants table, update the existing `HOP_DECAY_FACTOR` constant in types.ts from `0.8` to `0.85` (increased to preserve more signal across propagation hops).
115
+
116
+ - [ ] **Step 2: Extend KnowledgeUnit interface with optional v2 fields**
117
+
118
+ Add new optional fields to the existing `KnowledgeUnit` interface (keeping `layer` for backward compat):
119
+
120
+ ```typescript
121
+ export interface KnowledgeUnit {
122
+ // ... all existing v1 fields unchanged ...
123
+ layer: Layer; // KEPT for backward compat (derived from scope on read)
124
+
125
+ // v2 fields (optional — null/default when reading v1 data)
126
+ scope?: Scope;
127
+ entity_links?: EntityLink[];
128
+ evidence_score?: number;
129
+ corroborations?: number;
130
+ contradiction_refs?: string[];
131
+ sensitivity?: SensitivityClass;
132
+ creator_scope?: ScopeOverride | null;
133
+ origin?: Origin;
134
+ propagation_path?: PropHop[];
135
+ }
136
+ ```
137
+
138
+ - [ ] **Step 3: Commit**
139
+
140
+ ```bash
141
+ git add src/lib/cortex/knowledge/types.ts
142
+ git commit -m "feat(cortex): add v2 knowledge unit type definitions"
143
+ ```
144
+
145
+ ---
146
+
147
+ ### Task 2: Create v1↔v2 compatibility layer
148
+
149
+ **Files:**
150
+ - Create: `src/lib/cortex/knowledge/compat.ts`
151
+ - Create: `tests/lib/cortex/knowledge/compat.test.ts`
152
+
153
+ - [ ] **Step 1: Write failing tests**
154
+
155
+ ```typescript
156
+ // tests/lib/cortex/knowledge/compat.test.ts
157
+ import { describe, it, expect } from 'vitest';
158
+ import {
159
+ layerToScope,
160
+ scopeToLayer,
161
+ scopeToLayerKey,
162
+ layerKeyToScope,
163
+ } from '@/lib/cortex/knowledge/compat';
164
+
165
+ describe('v1↔v2 Compatibility', () => {
166
+ describe('layerToScope', () => {
167
+ it('maps personal to personal scope', () => {
168
+ const scope = layerToScope('personal', null, 'default-user');
169
+ expect(scope).toEqual({ level: 'personal', entity_id: 'person-default-user' });
170
+ });
171
+
172
+ it('maps workspace to team scope', () => {
173
+ const scope = layerToScope('workspace', 42);
174
+ expect(scope).toEqual({ level: 'team', entity_id: 'team-default' });
175
+ });
176
+
177
+ it('maps team to organization scope', () => {
178
+ const scope = layerToScope('team', null);
179
+ expect(scope).toEqual({ level: 'organization', entity_id: 'organization-default' });
180
+ });
181
+ });
182
+
183
+ describe('scopeToLayer', () => {
184
+ it('maps personal scope to personal layer', () => {
185
+ expect(scopeToLayer({ level: 'personal', entity_id: 'person-alice' })).toBe('personal');
186
+ });
187
+
188
+ it('maps team scope to workspace layer', () => {
189
+ expect(scopeToLayer({ level: 'team', entity_id: 'team-platform' })).toBe('workspace');
190
+ });
191
+
192
+ it('maps department scope to team layer', () => {
193
+ expect(scopeToLayer({ level: 'department', entity_id: 'dept-eng' })).toBe('team');
194
+ });
195
+
196
+ it('maps organization scope to team layer', () => {
197
+ expect(scopeToLayer({ level: 'organization', entity_id: 'org-acme' })).toBe('team');
198
+ });
199
+ });
200
+
201
+ describe('scopeToLayerKey', () => {
202
+ it('maps personal scope to personal key', () => {
203
+ expect(scopeToLayerKey({ level: 'personal', entity_id: 'person-alice' })).toBe('personal');
204
+ });
205
+
206
+ it('maps team scope with workspace_id to workspace/id key', () => {
207
+ expect(scopeToLayerKey({ level: 'team', entity_id: 'team-platform' }, 42)).toBe('workspace/42');
208
+ });
209
+
210
+ it('maps team scope without workspace_id to team key', () => {
211
+ expect(scopeToLayerKey({ level: 'team', entity_id: 'team-platform' })).toBe('team');
212
+ });
213
+
214
+ it('maps organization scope to team key', () => {
215
+ expect(scopeToLayerKey({ level: 'organization', entity_id: 'org-acme' })).toBe('team');
216
+ });
217
+ });
218
+
219
+ describe('layerKeyToScope', () => {
220
+ it('maps personal key to personal scope', () => {
221
+ const scope = layerKeyToScope('personal', 'default-user');
222
+ expect(scope).toEqual({ level: 'personal', entity_id: 'person-default-user' });
223
+ });
224
+
225
+ it('maps workspace/id key to team scope', () => {
226
+ const scope = layerKeyToScope('workspace/42');
227
+ expect(scope).toEqual({ level: 'team', entity_id: 'team-default' });
228
+ });
229
+
230
+ it('maps team key to organization scope', () => {
231
+ const scope = layerKeyToScope('team');
232
+ expect(scope).toEqual({ level: 'organization', entity_id: 'organization-default' });
233
+ });
234
+ });
235
+ });
236
+ ```
237
+
238
+ - [ ] **Step 2: Run tests to verify they fail**
239
+
240
+ Run: `npx vitest run tests/lib/cortex/knowledge/compat.test.ts`
241
+
242
+ - [ ] **Step 3: Implement compatibility layer**
243
+
244
+ ```typescript
245
+ // src/lib/cortex/knowledge/compat.ts
246
+ import type { Layer, Scope, ScopeLevel } from './types';
247
+
248
+ /**
249
+ * Convert v1 layer to v2 scope.
250
+ * personal → personal scope, workspace → team scope, team → organization scope.
251
+ */
252
+ export function layerToScope(
253
+ layer: Layer,
254
+ workspaceId?: number | null,
255
+ userId?: string,
256
+ ): Scope {
257
+ switch (layer) {
258
+ case 'personal':
259
+ return { level: 'personal', entity_id: `person-${userId ?? 'default-user'}` };
260
+ case 'workspace':
261
+ return { level: 'team', entity_id: 'team-default' };
262
+ case 'team':
263
+ return { level: 'organization', entity_id: 'organization-default' };
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Convert v2 scope back to v1 layer (for backward compat).
269
+ * personal → personal, team → workspace, department/organization → team.
270
+ */
271
+ export function scopeToLayer(scope: Scope): Layer {
272
+ switch (scope.level) {
273
+ case 'personal': return 'personal';
274
+ case 'team': return 'workspace';
275
+ case 'department':
276
+ case 'organization': return 'team';
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Convert v2 scope to a LanceDB layer key (storage path).
282
+ * Maintains compatibility with existing store.layerPath() logic.
283
+ */
284
+ export function scopeToLayerKey(scope: Scope, workspaceId?: number | null): string {
285
+ switch (scope.level) {
286
+ case 'personal': return 'personal';
287
+ case 'team':
288
+ return workspaceId ? `workspace/${workspaceId}` : 'team';
289
+ case 'department':
290
+ case 'organization':
291
+ return 'team';
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Convert a LanceDB layer key back to a v2 scope.
297
+ */
298
+ export function layerKeyToScope(layerKey: string, userId?: string): Scope {
299
+ if (layerKey === 'personal') {
300
+ return { level: 'personal', entity_id: `person-${userId ?? 'default-user'}` };
301
+ }
302
+ if (layerKey.startsWith('workspace/')) {
303
+ return { level: 'team', entity_id: 'team-default' };
304
+ }
305
+ // 'team' key → organization scope
306
+ return { level: 'organization', entity_id: 'organization-default' };
307
+ }
308
+ ```
309
+
310
+ - [ ] **Step 4: Run tests to verify they pass**
311
+
312
+ Run: `npx vitest run tests/lib/cortex/knowledge/compat.test.ts`
313
+ Expected: PASS (10 tests)
314
+
315
+ - [ ] **Step 5: Commit**
316
+
317
+ ```bash
318
+ git add src/lib/cortex/knowledge/compat.ts tests/lib/cortex/knowledge/compat.test.ts
319
+ git commit -m "feat(cortex): add v1↔v2 layer/scope compatibility mapping"
320
+ ```
321
+
322
+ ---
323
+
324
+ ### Task 3: Evidence score computation
325
+
326
+ **Files:**
327
+ - Create: `src/lib/cortex/knowledge/evidence.ts`
328
+ - Create: `tests/lib/cortex/knowledge/evidence.test.ts`
329
+
330
+ - [ ] **Step 1: Write failing tests**
331
+
332
+ ```typescript
333
+ // tests/lib/cortex/knowledge/evidence.test.ts
334
+ import { describe, it, expect } from 'vitest';
335
+ import { computeEvidenceScore, AUTHORITY_FACTORS } from '@/lib/cortex/knowledge/evidence';
336
+
337
+ describe('computeEvidenceScore', () => {
338
+ it('returns base confidence for fresh unit with no interactions', () => {
339
+ const score = computeEvidenceScore({
340
+ baseConfidence: 0.8,
341
+ corroborations: 0,
342
+ accessCount: 0,
343
+ authorityFactor: 1.0,
344
+ contradictionCount: 0,
345
+ });
346
+ expect(score).toBeCloseTo(0.8);
347
+ });
348
+
349
+ it('increases with corroborations', () => {
350
+ const base = computeEvidenceScore({
351
+ baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
352
+ });
353
+ const withCorr = computeEvidenceScore({
354
+ baseConfidence: 0.8, corroborations: 3, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
355
+ });
356
+ expect(withCorr).toBeGreaterThan(base);
357
+ });
358
+
359
+ it('increases with access count (diminishing returns)', () => {
360
+ const low = computeEvidenceScore({
361
+ baseConfidence: 0.8, corroborations: 0, accessCount: 5, authorityFactor: 1.0, contradictionCount: 0,
362
+ });
363
+ const high = computeEvidenceScore({
364
+ baseConfidence: 0.8, corroborations: 0, accessCount: 50, authorityFactor: 1.0, contradictionCount: 0,
365
+ });
366
+ expect(high).toBeGreaterThan(low);
367
+ // Capped at 50 — going higher has no effect
368
+ const over = computeEvidenceScore({
369
+ baseConfidence: 0.8, corroborations: 0, accessCount: 100, authorityFactor: 1.0, contradictionCount: 0,
370
+ });
371
+ expect(over).toBeCloseTo(high);
372
+ });
373
+
374
+ it('decreases with contradictions', () => {
375
+ const clean = computeEvidenceScore({
376
+ baseConfidence: 0.8, corroborations: 2, accessCount: 10, authorityFactor: 1.0, contradictionCount: 0,
377
+ });
378
+ const contested = computeEvidenceScore({
379
+ baseConfidence: 0.8, corroborations: 2, accessCount: 10, authorityFactor: 1.0, contradictionCount: 2,
380
+ });
381
+ expect(contested).toBeLessThan(clean);
382
+ });
383
+
384
+ it('caps corroboration contribution at 10', () => {
385
+ const at10 = computeEvidenceScore({
386
+ baseConfidence: 0.8, corroborations: 10, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
387
+ });
388
+ const at20 = computeEvidenceScore({
389
+ baseConfidence: 0.8, corroborations: 20, accessCount: 0, authorityFactor: 1.0, contradictionCount: 0,
390
+ });
391
+ expect(at20).toBeCloseTo(at10); // no additional benefit beyond 10
392
+ });
393
+
394
+ it('is boosted by authority factor', () => {
395
+ const conversation = computeEvidenceScore({
396
+ baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: AUTHORITY_FACTORS.conversation, contradictionCount: 0,
397
+ });
398
+ const document = computeEvidenceScore({
399
+ baseConfidence: 0.8, corroborations: 0, accessCount: 0, authorityFactor: AUTHORITY_FACTORS.document, contradictionCount: 0,
400
+ });
401
+ expect(document).toBeGreaterThan(conversation);
402
+ });
403
+
404
+ it('is capped at 1.0', () => {
405
+ const score = computeEvidenceScore({
406
+ baseConfidence: 0.95, corroborations: 10, accessCount: 50, authorityFactor: 1.3, contradictionCount: 0,
407
+ });
408
+ expect(score).toBeLessThanOrEqual(1.0);
409
+ });
410
+
411
+ it('never goes below 0', () => {
412
+ const score = computeEvidenceScore({
413
+ baseConfidence: 0.1, corroborations: 0, accessCount: 0, authorityFactor: 1.0, contradictionCount: 10,
414
+ });
415
+ expect(score).toBeGreaterThanOrEqual(0);
416
+ });
417
+ });
418
+ ```
419
+
420
+ - [ ] **Step 2: Run tests to verify they fail**
421
+
422
+ Run: `npx vitest run tests/lib/cortex/knowledge/evidence.test.ts`
423
+
424
+ - [ ] **Step 3: Implement evidence score**
425
+
426
+ ```typescript
427
+ // src/lib/cortex/knowledge/evidence.ts
428
+
429
+ export const AUTHORITY_FACTORS = {
430
+ conversation: 1.0,
431
+ git_commit: 1.1,
432
+ pr_review: 1.1,
433
+ document: 1.2,
434
+ behavioral: 1.0,
435
+ distillation: 1.1,
436
+ manual: 1.3,
437
+ } as const;
438
+
439
+ export interface EvidenceScoreInput {
440
+ baseConfidence: number;
441
+ corroborations: number;
442
+ accessCount: number;
443
+ authorityFactor: number;
444
+ contradictionCount: number;
445
+ }
446
+
447
+ /**
448
+ * Compute evidence score (0-1) from knowledge unit metrics.
449
+ *
450
+ * Formula from spec:
451
+ * evidence_score = min(1.0,
452
+ * base_confidence
453
+ * × (1 + 0.1 × corroborations)
454
+ * × (1 + 0.01 × min(access_count, 50))
455
+ * × authority_factor
456
+ * ÷ (1 + 0.5 × contradiction_count)
457
+ * )
458
+ */
459
+ export function computeEvidenceScore(input: EvidenceScoreInput): number {
460
+ const { baseConfidence, corroborations, accessCount, authorityFactor, contradictionCount } = input;
461
+
462
+ const corroborationBoost = 1 + 0.1 * Math.min(corroborations, 10);
463
+ const accessBoost = 1 + 0.01 * Math.min(accessCount, 50);
464
+ const contradictionPenalty = 1 + 0.5 * contradictionCount;
465
+
466
+ const raw = (baseConfidence * corroborationBoost * accessBoost * authorityFactor) / contradictionPenalty;
467
+
468
+ return Math.max(0, Math.min(1.0, raw));
469
+ }
470
+ ```
471
+
472
+ - [ ] **Step 4: Run tests to verify they pass**
473
+
474
+ Run: `npx vitest run tests/lib/cortex/knowledge/evidence.test.ts`
475
+ Expected: PASS (7 tests)
476
+
477
+ - [ ] **Step 5: Commit**
478
+
479
+ ```bash
480
+ git add src/lib/cortex/knowledge/evidence.ts tests/lib/cortex/knowledge/evidence.test.ts
481
+ git commit -m "feat(cortex): add evidence score computation"
482
+ ```
483
+
484
+ ---
485
+
486
+ ## Chunk 2: LanceDB Schema Evolution and Store Updates
487
+
488
+ ### Task 4: Evolve Arrow schema with v2 fields and table migration
489
+
490
+ **Files:**
491
+ - Create: `src/lib/cortex/store-migration.ts`
492
+ - Modify: `src/lib/cortex/store.ts`
493
+ - Modify: `tests/lib/cortex/store.test.ts`
494
+
495
+ > **CRITICAL:** LanceDB is strict about schema — you cannot add records with columns that don't exist in the table's schema. Existing v1 tables lack the 9 new v2 columns. We must migrate existing tables by adding the new columns before any v2 writes.
496
+
497
+ - [ ] **Step 1: Read the current store.ts**
498
+
499
+ Read `src/lib/cortex/store.ts` to understand:
500
+ - The `buildSchema(dimensions)` function (Arrow field definitions)
501
+ - The `unitToRecord` serialization
502
+ - The deserialization in `search()` and `browse()`
503
+ - The `updateAccessCount()` method (delete + re-add pattern)
504
+ - How `getConnection()` opens tables
505
+
506
+ - [ ] **Step 1b: Create store-migration.ts**
507
+
508
+ ```typescript
509
+ // src/lib/cortex/store-migration.ts
510
+ import type { Table } from '@lancedb/lancedb';
511
+
512
+ /**
513
+ * V2 columns to add to existing LanceDB tables.
514
+ * Each entry: [column_name, sql_expression_for_default_value]
515
+ */
516
+ const V2_COLUMNS: [string, string][] = [
517
+ ['scope', "'null'"], // JSON string, null for v1 data
518
+ ['entity_links', "'[]'"], // JSON array string
519
+ ['evidence_score', '0.5'], // float default
520
+ ['corroborations', '0'], // int default
521
+ ['contradiction_refs', "'[]'"], // JSON array string
522
+ ['sensitivity', "'internal'"], // string default
523
+ ['creator_scope', "'null'"], // JSON string, null
524
+ ['origin', "'null'"], // JSON string, null
525
+ ['propagation_path', "'[]'"], // JSON array string
526
+ ];
527
+
528
+ /**
529
+ * Migrate a LanceDB table to v2 schema by adding missing columns.
530
+ * Safe to call repeatedly — checks column existence before adding.
531
+ */
532
+ export async function migrateTableToV2(table: Table): Promise<void> {
533
+ const schema = await table.schema;
534
+ const existingFields = new Set(schema.fields.map(f => f.name));
535
+
536
+ for (const [colName, defaultExpr] of V2_COLUMNS) {
537
+ if (!existingFields.has(colName)) {
538
+ try {
539
+ await table.addColumns([{ name: colName, valueSql: defaultExpr }]);
540
+ } catch {
541
+ // Column may have been added concurrently, ignore
542
+ }
543
+ }
544
+ }
545
+ }
546
+ ```
547
+
548
+ This uses LanceDB's `table.addColumns()` API to add nullable columns with default values to existing tables in-place, without needing to read/drop/recreate.
549
+
550
+ - [ ] **Step 2: Write a failing test for v2 fields**
551
+
552
+ Add to `tests/lib/cortex/store.test.ts`:
553
+
554
+ ```typescript
555
+ describe('CortexStore — v2 fields', () => {
556
+ let tmpDir: string;
557
+ let store: CortexStore;
558
+
559
+ beforeEach(async () => {
560
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cortex-store-'));
561
+ store = new CortexStore(tmpDir);
562
+ await store.init(384);
563
+ });
564
+
565
+ afterEach(async () => {
566
+ await store.close();
567
+ fs.rmSync(tmpDir, { recursive: true, force: true });
568
+ });
569
+
570
+ it('stores and retrieves v2 fields', async () => {
571
+ const vector = new Array(384).fill(0).map(() => Math.random());
572
+ const unit = {
573
+ id: 'v2-test-1',
574
+ vector,
575
+ text: 'Auth uses JWT with refresh tokens',
576
+ type: 'decision' as const,
577
+ layer: 'personal' as const,
578
+ workspace_id: null,
579
+ session_id: 'sess-1',
580
+ agent_type: 'claude' as const,
581
+ project_path: '/project',
582
+ file_refs: ['src/auth.ts'],
583
+ confidence: 0.85,
584
+ created: new Date().toISOString(),
585
+ source_timestamp: new Date().toISOString(),
586
+ stale_score: 0,
587
+ access_count: 0,
588
+ last_accessed: null,
589
+ metadata: {},
590
+ // v2 fields
591
+ scope: { level: 'personal' as const, entity_id: 'person-alice' },
592
+ entity_links: [
593
+ { entity_id: 'topic-auth', entity_type: 'topic', relation: 'about' as const, weight: 0.9 },
594
+ ],
595
+ evidence_score: 0.72,
596
+ corroborations: 2,
597
+ contradiction_refs: ['other-id-1'],
598
+ sensitivity: 'internal' as const,
599
+ creator_scope: null,
600
+ origin: { source_type: 'conversation' as const, source_ref: 'sess-1', creator_entity_id: 'person-alice' },
601
+ propagation_path: [],
602
+ };
603
+
604
+ await store.add('personal', unit);
605
+ const results = await store.search('personal', vector, 5);
606
+ expect(results).toHaveLength(1);
607
+
608
+ const result = results[0];
609
+ expect(result.scope).toEqual({ level: 'personal', entity_id: 'person-alice' });
610
+ expect(result.entity_links).toHaveLength(1);
611
+ expect(result.entity_links![0].entity_id).toBe('topic-auth');
612
+ expect(result.evidence_score).toBeCloseTo(0.72);
613
+ expect(result.corroborations).toBe(2);
614
+ expect(result.contradiction_refs).toEqual(['other-id-1']);
615
+ expect(result.sensitivity).toBe('internal');
616
+ expect(result.origin?.source_type).toBe('conversation');
617
+ });
618
+
619
+ it('reads v1 data with default v2 fields', async () => {
620
+ const vector = new Array(384).fill(0).map(() => Math.random());
621
+ // Store a unit WITHOUT v2 fields (simulating v1 data)
622
+ const unit = {
623
+ id: 'v1-test-1',
624
+ vector,
625
+ text: 'Old v1 knowledge',
626
+ type: 'context' as const,
627
+ layer: 'personal' as const,
628
+ workspace_id: null,
629
+ session_id: null,
630
+ agent_type: 'claude' as const,
631
+ project_path: null,
632
+ file_refs: [],
633
+ confidence: 0.6,
634
+ created: new Date().toISOString(),
635
+ source_timestamp: new Date().toISOString(),
636
+ stale_score: 0,
637
+ access_count: 0,
638
+ last_accessed: null,
639
+ metadata: {},
640
+ };
641
+
642
+ await store.add('personal', unit);
643
+ const results = await store.search('personal', vector, 5);
644
+ const result = results[0];
645
+
646
+ // v2 fields should have sensible defaults
647
+ expect(result.evidence_score).toBe(0.5);
648
+ expect(result.corroborations).toBe(0);
649
+ expect(result.contradiction_refs).toEqual([]);
650
+ expect(result.sensitivity).toBe('internal');
651
+ expect(result.entity_links).toEqual([]);
652
+ expect(result.propagation_path).toEqual([]);
653
+ });
654
+ });
655
+ ```
656
+
657
+ - [ ] **Step 3: Run tests to verify they fail**
658
+
659
+ Run: `npx vitest run tests/lib/cortex/store.test.ts`
660
+
661
+ - [ ] **Step 4: Evolve the Arrow schema**
662
+
663
+ In `src/lib/cortex/store.ts`, add new Arrow fields to the schema builder function. These are all nullable Utf8 fields (JSON-serialized for complex types) or nullable Float64/Int32 for numbers:
664
+
665
+ ```typescript
666
+ // Add after existing fields in the schema:
667
+ new arrow.Field('scope', new arrow.Utf8(), true), // JSON: { level, entity_id }
668
+ new arrow.Field('entity_links', new arrow.Utf8(), true), // JSON array
669
+ new arrow.Field('evidence_score', new arrow.Float64(), true), // nullable
670
+ new arrow.Field('corroborations', new arrow.Int32(), true), // nullable
671
+ new arrow.Field('contradiction_refs', new arrow.Utf8(), true), // JSON array
672
+ new arrow.Field('sensitivity', new arrow.Utf8(), true), // nullable
673
+ new arrow.Field('creator_scope', new arrow.Utf8(), true), // JSON or null
674
+ new arrow.Field('origin', new arrow.Utf8(), true), // JSON or null
675
+ new arrow.Field('propagation_path', new arrow.Utf8(), true), // JSON array
676
+ ```
677
+
678
+ In the `add()` method, after opening/creating the table but before `table.add([record])`, call migration:
679
+ ```typescript
680
+ import { migrateTableToV2 } from './store-migration';
681
+
682
+ // In add(), after getting/creating the table:
683
+ await migrateTableToV2(table);
684
+ ```
685
+
686
+ Also call `migrateTableToV2` in `search()` and `browse()` after getting the table, to ensure reads from v1 tables also get the new columns. Cache a Set of already-migrated table paths to avoid repeated migration checks.
687
+
688
+ Update the serialization (unitToRecord) to include v2 fields:
689
+ ```typescript
690
+ scope: unit.scope ? JSON.stringify(unit.scope) : null,
691
+ entity_links: JSON.stringify(unit.entity_links ?? []),
692
+ evidence_score: unit.evidence_score ?? 0.5,
693
+ corroborations: unit.corroborations ?? 0,
694
+ contradiction_refs: JSON.stringify(unit.contradiction_refs ?? []),
695
+ sensitivity: unit.sensitivity ?? 'internal',
696
+ creator_scope: unit.creator_scope ? JSON.stringify(unit.creator_scope) : null,
697
+ origin: unit.origin ? JSON.stringify(unit.origin) : null,
698
+ propagation_path: JSON.stringify(unit.propagation_path ?? []),
699
+ ```
700
+
701
+ **CRITICAL: Also update `updateAccessCount()`** — this method uses a delete+re-add pattern that reconstructs the record from raw fields. It must include all v2 fields in the reconstruction to avoid dropping them:
702
+
703
+ ```typescript
704
+ // In updateAccessCount(), when reconstructing the record, add:
705
+ scope: raw.scope ?? null,
706
+ entity_links: raw.entity_links ?? '[]',
707
+ evidence_score: raw.evidence_score ?? 0.5,
708
+ corroborations: raw.corroborations ?? 0,
709
+ contradiction_refs: raw.contradiction_refs ?? '[]',
710
+ sensitivity: raw.sensitivity ?? 'internal',
711
+ creator_scope: raw.creator_scope ?? null,
712
+ origin: raw.origin ?? null,
713
+ propagation_path: raw.propagation_path ?? '[]',
714
+ ```
715
+
716
+ **Also update `browse()` deserialization** — `browse()` has its own row-mapping logic separate from `search()`. Apply the same v2 field parsing to `browse()` results.
717
+
718
+ Update deserialization in BOTH `search()` and `browse()` to parse v2 fields with defaults:
719
+ ```typescript
720
+ scope: row.scope ? JSON.parse(row.scope) : undefined,
721
+ entity_links: JSON.parse(row.entity_links || '[]'),
722
+ evidence_score: row.evidence_score ?? 0.5,
723
+ corroborations: row.corroborations ?? 0,
724
+ contradiction_refs: JSON.parse(row.contradiction_refs || '[]'),
725
+ sensitivity: row.sensitivity || 'internal',
726
+ creator_scope: row.creator_scope ? JSON.parse(row.creator_scope) : null,
727
+ origin: row.origin ? JSON.parse(row.origin) : undefined,
728
+ propagation_path: JSON.parse(row.propagation_path || '[]'),
729
+ ```
730
+
731
+ - [ ] **Step 5: Run tests to verify they pass**
732
+
733
+ Run: `npx vitest run tests/lib/cortex/store.test.ts`
734
+ Expected: All tests pass (existing + 2 new)
735
+
736
+ - [ ] **Step 6: Commit**
737
+
738
+ ```bash
739
+ git add src/lib/cortex/store.ts tests/lib/cortex/store.test.ts
740
+ git commit -m "feat(cortex): evolve LanceDB schema with v2 knowledge unit fields"
741
+ ```
742
+
743
+ ---
744
+
745
+ ### Task 5: Update search and scoring for v2
746
+
747
+ **Files:**
748
+ - Modify: `src/lib/cortex/retrieval/scoring.ts`
749
+ - Modify: `src/lib/cortex/retrieval/search.ts`
750
+ - Modify: `tests/lib/cortex/retrieval/search.test.ts`
751
+
752
+ - [ ] **Step 1: Read current search.ts and scoring.ts**
753
+
754
+ Read both files to understand the current scoring formula and search layer iteration.
755
+
756
+ - [ ] **Step 2: Write a failing test for evidence-aware scoring**
757
+
758
+ Add to `tests/lib/cortex/retrieval/scoring.test.ts` (or the existing scoring test file):
759
+
760
+ ```typescript
761
+ import { computeRelevanceScore } from '@/lib/cortex/retrieval/scoring';
762
+
763
+ it('uses evidence_score when provided instead of confidence', () => {
764
+ const withConfidenceOnly = computeRelevanceScore({
765
+ similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
766
+ });
767
+ const withHighEvidence = computeRelevanceScore({
768
+ similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
769
+ evidence_score: 0.95,
770
+ });
771
+ const withLowEvidence = computeRelevanceScore({
772
+ similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
773
+ evidence_score: 0.3,
774
+ });
775
+
776
+ // evidence_score should override confidence in the formula
777
+ expect(withHighEvidence).toBeGreaterThan(withConfidenceOnly);
778
+ expect(withLowEvidence).toBeLessThan(withConfidenceOnly);
779
+ });
780
+
781
+ it('falls back to confidence when evidence_score is undefined', () => {
782
+ const result = computeRelevanceScore({
783
+ similarity: 0.9, confidence: 0.8, stale_score: 0, created: new Date().toISOString(),
784
+ });
785
+ // Should use confidence (0.8) as the evidence factor
786
+ expect(result).toBeGreaterThan(0);
787
+ });
788
+ ```
789
+
790
+ - [ ] **Step 3: Update scoring.ts to incorporate evidence_score**
791
+
792
+ Add `evidence_score` as an optional parameter to `computeRelevanceScore`:
793
+
794
+ ```typescript
795
+ export function computeRelevanceScore(params: {
796
+ similarity: number;
797
+ confidence: number;
798
+ stale_score: number;
799
+ created: string;
800
+ evidence_score?: number; // NEW: v2 evidence score
801
+ }): number {
802
+ const recencyBoost = computeRecencyBoost(params.created);
803
+ const evidence = params.evidence_score ?? params.confidence; // fallback to confidence for v1 data
804
+ return Math.min(1.0, params.similarity * evidence * (1 - params.stale_score) * recencyBoost);
805
+ }
806
+ ```
807
+
808
+ - [ ] **Step 4: Update search.ts to pass evidence_score in ALL scoring calls**
809
+
810
+ In the search method, pass `evidence_score` in BOTH the initial scoring AND the staleness recomputation:
811
+
812
+ ```typescript
813
+ // Initial scoring (in the per-layer loop):
814
+ const relevance = computeRelevanceScore({
815
+ similarity,
816
+ confidence: unit.confidence,
817
+ stale_score: unit.stale_score,
818
+ created: unit.created,
819
+ evidence_score: unit.evidence_score, // NEW
820
+ }) * weight;
821
+ ```
822
+
823
+ Also find the staleness recomputation block (where `computeStaleness` results are used to re-score) and pass `evidence_score` there too:
824
+ ```typescript
825
+ // After staleness recomputation:
826
+ r.relevance_score = computeRelevanceScore({
827
+ similarity: r.similarity,
828
+ confidence: r.confidence,
829
+ stale_score: r.stale_score,
830
+ created: r.created,
831
+ evidence_score: r.evidence_score, // NEW — must be here too
832
+ }) * (LAYER_WEIGHTS[r.layer] ?? 0.5);
833
+ ```
834
+
835
+ - [ ] **Step 5: Run tests to verify they pass**
836
+
837
+ Run: `npx vitest run tests/lib/cortex/retrieval/`
838
+ Expected: All tests pass
839
+
840
+ - [ ] **Step 6: Commit**
841
+
842
+ ```bash
843
+ git add src/lib/cortex/retrieval/scoring.ts src/lib/cortex/retrieval/search.ts tests/lib/cortex/retrieval/search.test.ts
844
+ git commit -m "feat(cortex): incorporate evidence_score into retrieval scoring"
845
+ ```
846
+
847
+ ---
848
+
849
+ ## Chunk 3: API Backward Compatibility
850
+
851
+ ### Task 6: Update knowledge API to accept both layer and scope
852
+
853
+ **Files:**
854
+ - Modify: `src/app/api/cortex/knowledge/route.ts`
855
+
856
+ - [ ] **Step 1: Read current knowledge/route.ts**
857
+
858
+ - [ ] **Step 2: Update POST handler to accept both formats**
859
+
860
+ The POST handler currently requires `layer`. Update it to:
861
+ 1. Accept `scope` as an alternative to `layer`
862
+ 2. If `scope` is provided, use it directly and derive `layer` for backward compat
863
+ 3. If only `layer` is provided, derive `scope` from it
864
+ 4. Accept new v2 fields: `sensitivity`, `origin`, `entity_links`
865
+
866
+ ```typescript
867
+ // In POST handler, after parsing body:
868
+ const { text, type, workspace_id } = body;
869
+ let { layer, scope, sensitivity, origin, entity_links } = body;
870
+
871
+ // Validate: need either layer or scope
872
+ if (!text || !type) {
873
+ return NextResponse.json({ error: 'text and type are required' }, { status: 400 });
874
+ }
875
+
876
+ if (!layer && !scope) {
877
+ return NextResponse.json({ error: 'layer or scope is required' }, { status: 400 });
878
+ }
879
+
880
+ // Resolve layer ↔ scope
881
+ if (scope && !layer) {
882
+ layer = scopeToLayer(scope);
883
+ } else if (layer && !scope) {
884
+ scope = layerToScope(layer, workspace_id);
885
+ }
886
+
887
+ // Compute layerKey from scope (or fallback to old method)
888
+ const layerKey = scope
889
+ ? scopeToLayerKey(scope, workspace_id)
890
+ : (layer === 'workspace' && workspace_id ? `workspace/${workspace_id}` : layer);
891
+ ```
892
+
893
+ Import the compat functions:
894
+ ```typescript
895
+ import { layerToScope, scopeToLayer, scopeToLayerKey } from '@/lib/cortex/knowledge/compat';
896
+ ```
897
+
898
+ Add v2 fields to the unit construction. Use `getConfidenceBase(type)` for initial evidence_score (not a flat 0.5 — per spec, evidence starts from the type's base confidence). Derive `creator_entity_id` from the authenticated user:
899
+
900
+ ```typescript
901
+ import { getConfidenceBase } from '@/lib/cortex/knowledge/types';
902
+
903
+ // In unit construction:
904
+ scope,
905
+ entity_links: entity_links ?? [],
906
+ evidence_score: getConfidenceBase(type), // NOT 0.5 — matches spec
907
+ corroborations: 0,
908
+ contradiction_refs: [],
909
+ sensitivity: sensitivity ?? 'internal',
910
+ creator_scope: null,
911
+ origin: origin ?? { source_type: 'manual', source_ref: '', creator_entity_id: `person-${user}` },
912
+ propagation_path: [],
913
+ ```
914
+
915
+ Note: `user` is already available from `getAuthUser(request)` at the top of the handler.
916
+
917
+ - [ ] **Step 3: Commit**
918
+
919
+ ```bash
920
+ git add src/app/api/cortex/knowledge/route.ts
921
+ git commit -m "feat(cortex): accept both layer and scope in knowledge API"
922
+ ```
923
+
924
+ ---
925
+
926
+ ### Task 7: Update MCP tools to accept both layer and scope
927
+
928
+ **Files:**
929
+ - Modify: `src/lib/cortex/mcp/server.ts`
930
+
931
+ - [ ] **Step 1: Read current mcp/server.ts**
932
+
933
+ Read the `cortex_teach` tool schema and handler to understand what fields are accepted.
934
+
935
+ - [ ] **Step 2: Update cortex_teach tool**
936
+
937
+ 1. Add `scope` as an optional property in the tool's input schema (alongside existing `layer`)
938
+ 2. In the handler, apply the same layer↔scope resolution logic from Task 6
939
+ 3. Add `sensitivity` and `origin` as optional properties
940
+ 4. Include v2 fields in the unit construction, using `getConfidenceBase(type)` for evidence_score (not 0.5)
941
+ 5. Derive `creator_entity_id` from the agent context (use `'person-default-user'` as placeholder since MCP tools don't have user auth context — the real entity ID will be resolved by Pillar 5)
942
+
943
+ The key change: `layer` remains supported but `scope` is preferred. If both are provided, `scope` wins.
944
+
945
+ Import compat functions:
946
+ ```typescript
947
+ import { layerToScope, scopeToLayer, scopeToLayerKey } from '../knowledge/compat';
948
+ ```
949
+
950
+ - [ ] **Step 3: Commit**
951
+
952
+ ```bash
953
+ git add src/lib/cortex/mcp/server.ts
954
+ git commit -m "feat(cortex): accept both layer and scope in MCP cortex_teach tool"
955
+ ```
956
+
957
+ ---
958
+
959
+ ### Task 8: Update learn hook for v2 compatibility
960
+
961
+ **Files:**
962
+ - Modify: `bin/cortex-learn-hook.js`
963
+
964
+ - [ ] **Step 1: Read current cortex-learn-hook.js**
965
+
966
+ - [ ] **Step 2: Add scope field alongside layer**
967
+
968
+ The hook currently POSTs `{ text, type, layer: 'personal' }`. Update both entries to also include:
969
+
970
+ ```javascript
971
+ const scope = JSON.stringify({ level: 'personal', entity_id: 'person-default-user' });
972
+
973
+ // Question entry:
974
+ const questionEntry = JSON.stringify({
975
+ text: lastExchange.question,
976
+ type: 'context',
977
+ layer: 'personal',
978
+ scope: { level: 'personal', entity_id: 'person-default-user' },
979
+ origin: { source_type: 'conversation', source_ref: sessionId || '', creator_entity_id: 'person-default-user' },
980
+ });
981
+
982
+ // Answer entry:
983
+ const answerEntry = JSON.stringify({
984
+ text: `Q: ${lastExchange.question}\nA: ${condensedAnswer}`,
985
+ type: knowledgeType,
986
+ layer: 'personal',
987
+ scope: { level: 'personal', entity_id: 'person-default-user' },
988
+ origin: { source_type: 'conversation', source_ref: sessionId || '', creator_entity_id: 'person-default-user' },
989
+ });
990
+ ```
991
+
992
+ Note: `sessionId` should be extracted from the input JSON if available (the hook receives `{ transcript_path }` — the session ID is the filename without extension).
993
+
994
+ - [ ] **Step 3: Commit**
995
+
996
+ ```bash
997
+ git add bin/cortex-learn-hook.js
998
+ git commit -m "feat(cortex): add scope and origin to learn hook knowledge entries"
999
+ ```
1000
+
1001
+ ---
1002
+
1003
+ ## Chunk 4: Pipeline Integration and Final Tests
1004
+
1005
+ ### Task 9: Update ingestion pipeline for v2 fields
1006
+
1007
+ **Files:**
1008
+ - Modify: `src/lib/cortex/ingestion/pipeline.ts`
1009
+ - Modify: `src/lib/cortex/ingestion/chunker.ts`
1010
+
1011
+ - [ ] **Step 1: Read pipeline.ts and chunker.ts**
1012
+
1013
+ - [ ] **Step 2: Update RawChunk → KnowledgeUnit mapping in pipeline**
1014
+
1015
+ In the pipeline where KnowledgeUnit is constructed from RawChunk, add v2 fields with defaults:
1016
+
1017
+ ```typescript
1018
+ const unit: KnowledgeUnit = {
1019
+ // ... existing v1 fields ...
1020
+ // v2 fields with defaults
1021
+ scope: layerToScope(chunk.layer, chunk.workspace_id),
1022
+ entity_links: [],
1023
+ evidence_score: getConfidenceBase(chunk.type), // start with base confidence
1024
+ corroborations: 0,
1025
+ contradiction_refs: [],
1026
+ sensitivity: 'internal',
1027
+ creator_scope: null,
1028
+ origin: {
1029
+ source_type: 'conversation',
1030
+ source_ref: chunk.session_id ?? '',
1031
+ creator_entity_id: 'person-default-user',
1032
+ },
1033
+ propagation_path: [],
1034
+ };
1035
+ ```
1036
+
1037
+ Import the compat function:
1038
+ ```typescript
1039
+ import { layerToScope } from '../knowledge/compat';
1040
+ ```
1041
+
1042
+ - [ ] **Step 3: Run the full cortex test suite**
1043
+
1044
+ Run: `npx vitest run tests/lib/cortex/`
1045
+ Expected: All tests pass (including existing pipeline tests)
1046
+
1047
+ - [ ] **Step 4: Commit**
1048
+
1049
+ ```bash
1050
+ git add src/lib/cortex/ingestion/pipeline.ts
1051
+ git commit -m "feat(cortex): add v2 fields to ingestion pipeline output"
1052
+ ```
1053
+
1054
+ ---
1055
+
1056
+ ### Task 10: Export knowledge/compat and evidence from knowledge index
1057
+
1058
+ **Files:**
1059
+ - Modify or create: `src/lib/cortex/knowledge/index.ts` (if a barrel exists, update it; if not, create one)
1060
+
1061
+ - [ ] **Step 1: Check if knowledge/index.ts exists**
1062
+
1063
+ Read `src/lib/cortex/knowledge/` directory to see if there's a barrel export.
1064
+
1065
+ - [ ] **Step 2: Create or update barrel export**
1066
+
1067
+ Ensure these are re-exported:
1068
+ ```typescript
1069
+ export { layerToScope, scopeToLayer, scopeToLayerKey, layerKeyToScope } from './compat';
1070
+ export { computeEvidenceScore, AUTHORITY_FACTORS } from './evidence';
1071
+ export type { EvidenceScoreInput } from './evidence';
1072
+ // Existing type exports from types.ts should already be accessible
1073
+ ```
1074
+
1075
+ - [ ] **Step 3: Run the full test suite**
1076
+
1077
+ Run: `npx vitest run tests/lib/cortex/`
1078
+ Expected: All tests pass
1079
+
1080
+ - [ ] **Step 4: Commit**
1081
+
1082
+ ```bash
1083
+ git add src/lib/cortex/knowledge/
1084
+ git commit -m "feat(cortex): export compat and evidence modules from knowledge barrel"
1085
+ ```
1086
+
1087
+ ---
1088
+
1089
+ ## Summary
1090
+
1091
+ | Task | Component | Tests | Status |
1092
+ |------|-----------|-------|--------|
1093
+ | 1 | v2 type definitions | — | |
1094
+ | 2 | v1↔v2 compatibility layer | 10 | |
1095
+ | 3 | Evidence score computation | 8 | |
1096
+ | 4 | Arrow schema evolution | 2 | |
1097
+ | 5 | Search/scoring update | 2 | |
1098
+ | 6 | Knowledge API backward compat | — | |
1099
+ | 7 | MCP tool backward compat | — | |
1100
+ | 8 | Learn hook v2 fields | — | |
1101
+ | 9 | Pipeline v2 integration | regression | |
1102
+ | 10 | Barrel export | regression | |
1103
+
1104
+ **Total: 10 tasks, ~22 new tests, 4 chunks**
1105
+
1106
+ **Key design decisions:**
1107
+ - `layer` field is KEPT on KnowledgeUnit for backward compat (intentional spec deviation — spec says "removed" but we keep it as derived field)
1108
+ - v2 fields are all optional/nullable — existing LanceDB tables migrated in-place via `addColumns()` during `store.init()`
1109
+ - `updateAccessCount()` and `browse()` updated to preserve/parse v2 fields
1110
+ - API accepts both `layer` and `scope` params — `scope` takes precedence
1111
+ - Evidence score starts at `base_confidence` and evolves with access/corroboration (computed by Pillar 6: Gravity)
1112
+
1113
+ After this plan is complete, both the Entity Graph (Pillar 1) and Knowledge Unit Evolution (Pillar 2) will be in place — enabling Pillar 3 (Context Assembly Engine) and Pillar 4 (Boundary Engine) to build on them.