@remnic/core 10.0.14 → 10.0.16

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 (366) hide show
  1. package/dist/abstraction-nodes.js +3 -2
  2. package/dist/access-admin-ops-surface.js +34 -32
  3. package/dist/access-authorization-probe.js +35 -33
  4. package/dist/access-boundary.js +34 -32
  5. package/dist/access-cli.js +90 -88
  6. package/dist/access-cli.js.map +1 -1
  7. package/dist/access-extraction-force-flush.js +34 -32
  8. package/dist/access-http-briefing.js +35 -33
  9. package/dist/access-http-query.js +36 -34
  10. package/dist/access-http.js +53 -51
  11. package/dist/access-identity-continuity-surface.js +34 -32
  12. package/dist/access-lcm-surface.js +34 -32
  13. package/dist/access-mcp.js +45 -43
  14. package/dist/access-namespace-preflight.js +34 -32
  15. package/dist/access-observe-write-category.js +4 -3
  16. package/dist/access-observe-write-surface.js +34 -32
  17. package/dist/access-offline-manifest.js +3 -2
  18. package/dist/access-operations-batch.js +37 -35
  19. package/dist/access-operations.js +44 -42
  20. package/dist/access-recall-concurrency.js +34 -32
  21. package/dist/access-recall-response.js +34 -32
  22. package/dist/access-recall-surface.js +34 -32
  23. package/dist/access-schema.js +3 -2
  24. package/dist/access-service.js +34 -32
  25. package/dist/access-surface-catalog.js +36 -34
  26. package/dist/access-surface-catalog.js.map +1 -1
  27. package/dist/active-recall.js +14 -12
  28. package/dist/active-recall.js.map +1 -1
  29. package/dist/briefing.js +10 -8
  30. package/dist/buffer.js +2 -2
  31. package/dist/calibration.d.ts.map +1 -1
  32. package/dist/calibration.js +6 -3
  33. package/dist/calibration.js.map +1 -1
  34. package/dist/causal-behavior.js +4 -3
  35. package/dist/causal-behavior.js.map +1 -1
  36. package/dist/causal-chain.js +4 -3
  37. package/dist/causal-consolidation.js +14 -12
  38. package/dist/causal-consolidation.js.map +1 -1
  39. package/dist/causal-retrieval.js +4 -3
  40. package/dist/causal-retrieval.js.map +1 -1
  41. package/dist/causal-trajectory.js +3 -2
  42. package/dist/{chunk-63B2IZYE.js → chunk-23ZQPP2G.js} +6 -1
  43. package/dist/chunk-23ZQPP2G.js.map +1 -0
  44. package/dist/{chunk-YFMBHQRG.js → chunk-2PTH4PRL.js} +2 -2
  45. package/dist/{chunk-TITG2NBS.js → chunk-2PYHLSXK.js} +2 -2
  46. package/dist/{chunk-B6O2YLUR.js → chunk-2Z5DIDQD.js} +6 -1
  47. package/dist/chunk-2Z5DIDQD.js.map +1 -0
  48. package/dist/{chunk-KH2LKDX7.js → chunk-33G67YZF.js} +2 -2
  49. package/dist/{chunk-SWIKABKI.js → chunk-3Q3XD3NO.js} +2 -2
  50. package/dist/{chunk-4KY5GSMB.js → chunk-4PDTVVSW.js} +2 -2
  51. package/dist/{chunk-HM7RHKS4.js → chunk-4RNBLLZR.js} +2 -2
  52. package/dist/{chunk-PAZ35RJ4.js → chunk-4SCZZ3U7.js} +240 -55
  53. package/dist/chunk-4SCZZ3U7.js.map +1 -0
  54. package/dist/{chunk-Y4NKEXQT.js → chunk-5ATSXCAG.js} +3 -3
  55. package/dist/{chunk-JDZFIR2S.js → chunk-5KGYTX5O.js} +2 -2
  56. package/dist/{chunk-J7JWFZHI.js → chunk-5MLGY6IY.js} +39 -39
  57. package/dist/{chunk-NW2E4CI2.js → chunk-5SMR542T.js} +2 -2
  58. package/dist/{chunk-S7LWX2PQ.js → chunk-655FVTCD.js} +2 -2
  59. package/dist/{chunk-4OSG5Y6M.js → chunk-6YEPGWUP.js} +2 -2
  60. package/dist/{chunk-W47S5TIH.js → chunk-7VQ6AI7H.js} +2 -2
  61. package/dist/{chunk-WLMZ2L5P.js → chunk-AZDTDWS2.js} +2 -2
  62. package/dist/{chunk-G7NYVKD6.js → chunk-B2NXOVZN.js} +2 -2
  63. package/dist/{chunk-N7KYEVLK.js → chunk-BK2BVLZW.js} +2 -2
  64. package/dist/{chunk-QJ622LTI.js → chunk-BQOGQULP.js} +30 -8
  65. package/dist/chunk-BQOGQULP.js.map +1 -0
  66. package/dist/{chunk-S2I7DL5Q.js → chunk-C2RW36YR.js} +2 -2
  67. package/dist/{chunk-P5NQN4JE.js → chunk-C6JMGAMO.js} +6 -2
  68. package/dist/chunk-C6JMGAMO.js.map +1 -0
  69. package/dist/{chunk-6LG7BWKW.js → chunk-CFZ4SXXH.js} +2 -2
  70. package/dist/{chunk-JQ7XU625.js → chunk-CQOIWJ5E.js} +6 -6
  71. package/dist/{chunk-FSIMZNBC.js → chunk-CXOYUANR.js} +2 -2
  72. package/dist/{chunk-BLVHDY2U.js → chunk-DOWACHYO.js} +5 -2
  73. package/dist/chunk-DOWACHYO.js.map +1 -0
  74. package/dist/{chunk-QOZJCSFO.js → chunk-DQR2LD3V.js} +2 -2
  75. package/dist/{chunk-MATDGSJ7.js → chunk-DUPHIZBY.js} +2 -2
  76. package/dist/{chunk-EBA5DA77.js → chunk-EOU6V4IN.js} +2 -2
  77. package/dist/{chunk-5WCJLQTM.js → chunk-F2772ATT.js} +2 -2
  78. package/dist/{chunk-46EST7JO.js → chunk-F2XNSIPP.js} +2 -2
  79. package/dist/{chunk-PZHQWFR3.js → chunk-G3UUAQOD.js} +2 -2
  80. package/dist/{chunk-YE36AJL7.js → chunk-GCVDFX66.js} +2 -2
  81. package/dist/{chunk-ZV65I6ME.js → chunk-GFWRXPF6.js} +29 -26
  82. package/dist/chunk-GFWRXPF6.js.map +1 -0
  83. package/dist/{chunk-T2YX56QI.js → chunk-GQJKVQJR.js} +2 -2
  84. package/dist/{chunk-I7S55EOB.js → chunk-GUY6L6LL.js} +2 -2
  85. package/dist/{chunk-L5DAHSEZ.js → chunk-GWVNGDJW.js} +2 -2
  86. package/dist/{chunk-N45NEBOD.js → chunk-GZXXPCWJ.js} +3 -3
  87. package/dist/{chunk-EPJDSQHF.js → chunk-H5IUN433.js} +2 -2
  88. package/dist/{chunk-EUAIYYYR.js → chunk-H6FREOYX.js} +7 -7
  89. package/dist/{chunk-Q4E24IRR.js → chunk-HDN7IVIO.js} +14 -11
  90. package/dist/chunk-HDN7IVIO.js.map +1 -0
  91. package/dist/{chunk-T3FMRLWQ.js → chunk-HFSPY26A.js} +2 -2
  92. package/dist/{chunk-GH7AOMJD.js → chunk-IJMDBYCO.js} +2 -2
  93. package/dist/{chunk-4IHBN6WU.js → chunk-JKMIGCK6.js} +2 -2
  94. package/dist/{chunk-ROBHL3GL.js → chunk-JWX2Q6HS.js} +2 -2
  95. package/dist/{chunk-DPR2WTN3.js → chunk-JZTEOBOR.js} +16 -16
  96. package/dist/{chunk-4O6WRBGE.js → chunk-KJXP6RUG.js} +5 -1
  97. package/dist/chunk-KJXP6RUG.js.map +1 -0
  98. package/dist/{chunk-JIHMUOOS.js → chunk-KLJVTZ3R.js} +3 -3
  99. package/dist/{chunk-FP4JYE66.js → chunk-KW4AJ7T3.js} +2 -2
  100. package/dist/{chunk-NIRQGDYC.js → chunk-L5VCT7LU.js} +5 -1
  101. package/dist/chunk-L5VCT7LU.js.map +1 -0
  102. package/dist/{chunk-QODKDRSP.js → chunk-L6AZOEXV.js} +4 -4
  103. package/dist/{chunk-CLWBFR7Q.js → chunk-LO76EF3Y.js} +1 -1
  104. package/dist/chunk-LO76EF3Y.js.map +1 -0
  105. package/dist/{chunk-LS2FHUML.js → chunk-LQ5SS4OP.js} +3 -3
  106. package/dist/{chunk-SIIRTDJ4.js → chunk-LWFWZTWX.js} +2 -2
  107. package/dist/{chunk-BMWN7B3Y.js → chunk-LXATZLSC.js} +3 -3
  108. package/dist/{chunk-O4SGYW7H.js → chunk-MAVYEZKM.js} +2 -2
  109. package/dist/{chunk-B665A6BO.js → chunk-MJIOGYKX.js} +2 -2
  110. package/dist/{chunk-RTKV5XHL.js → chunk-MO6N4QYY.js} +2 -2
  111. package/dist/{chunk-N4C7QKOG.js → chunk-MWWAQXZ6.js} +2 -2
  112. package/dist/{chunk-LCKVXX5F.js → chunk-MXV2MY6C.js} +2 -2
  113. package/dist/{chunk-FFOVKNQV.js → chunk-NAGMQXWV.js} +2 -2
  114. package/dist/{chunk-ZJVMUBYF.js → chunk-NHUX6GXA.js} +6 -6
  115. package/dist/{chunk-CB6ANA2I.js → chunk-NZCKG25S.js} +2 -2
  116. package/dist/{chunk-UMTCNEVQ.js → chunk-O2YPCFJT.js} +11 -11
  117. package/dist/{chunk-WSGPFRBH.js → chunk-OMERTLB7.js} +3 -3
  118. package/dist/{chunk-QX6JN3O4.js → chunk-PEF5LHQU.js} +6 -6
  119. package/dist/{chunk-JYZSRNR7.js → chunk-PIITB2YZ.js} +2 -2
  120. package/dist/chunk-PPUNC7UX.js +73 -0
  121. package/dist/chunk-PPUNC7UX.js.map +1 -0
  122. package/dist/{chunk-EQWEIIKQ.js → chunk-PQM3B54K.js} +6 -1
  123. package/dist/chunk-PQM3B54K.js.map +1 -0
  124. package/dist/{chunk-UQDG3YLN.js → chunk-PRU7OF3Y.js} +3 -3
  125. package/dist/{chunk-EU534WGS.js → chunk-PVHQSLNN.js} +7 -7
  126. package/dist/{chunk-TZNDKTX5.js → chunk-Q7DWEXG2.js} +37 -33
  127. package/dist/chunk-Q7DWEXG2.js.map +1 -0
  128. package/dist/{chunk-5VC7J76U.js → chunk-QPH52AZB.js} +2 -2
  129. package/dist/{chunk-XISROV24.js → chunk-QSEUUQUF.js} +2 -2
  130. package/dist/chunk-QUIRIG2P.js +31 -0
  131. package/dist/chunk-QUIRIG2P.js.map +1 -0
  132. package/dist/{chunk-FUFAXVBA.js → chunk-RI2KCQHP.js} +6 -2
  133. package/dist/chunk-RI2KCQHP.js.map +1 -0
  134. package/dist/{chunk-O2IPAX26.js → chunk-RTTPBBAN.js} +4 -4
  135. package/dist/{chunk-W5MCEVUS.js → chunk-RYYVMZBR.js} +2 -2
  136. package/dist/{chunk-ZSH2NRDV.js → chunk-TN4EA4X4.js} +2 -2
  137. package/dist/{chunk-SS3IS2JR.js → chunk-UGYUBENJ.js} +2 -2
  138. package/dist/{chunk-GELS5Z5Z.js → chunk-V3TXIXXY.js} +3 -3
  139. package/dist/{chunk-WVADKFWV.js → chunk-VNZMZPAC.js} +2 -2
  140. package/dist/{chunk-JPTPS4OB.js → chunk-VPXIKBPX.js} +2 -2
  141. package/dist/{chunk-OP6N4H6A.js → chunk-W3FVQBGF.js} +2 -2
  142. package/dist/{chunk-W3K3HITK.js → chunk-WLT6LTQP.js} +2 -2
  143. package/dist/{chunk-GMXWTJNU.js → chunk-XKRXN63M.js} +2 -2
  144. package/dist/{chunk-KR6ZKECI.js → chunk-XYGQSDTH.js} +3 -3
  145. package/dist/{chunk-22W2XWGH.js → chunk-YBO2WGCV.js} +2 -2
  146. package/dist/{chunk-P7TOIOT7.js → chunk-YR4COAEC.js} +2 -2
  147. package/dist/{chunk-6WHJ2EAB.js → chunk-Z64TS5V4.js} +2 -2
  148. package/dist/{chunk-NHLLKEKK.js → chunk-ZAJLJ35W.js} +2 -2
  149. package/dist/cli.d.ts.map +1 -1
  150. package/dist/cli.js +73 -71
  151. package/dist/coding/export-okf-codegraph.js +9 -7
  152. package/dist/coding/export-okf-codegraph.js.map +1 -1
  153. package/dist/coding/pre-action-gate.js +4 -3
  154. package/dist/commitment-ledger.js +3 -2
  155. package/dist/compounding/engine.js +11 -9
  156. package/dist/config.js +14 -12
  157. package/dist/connectors/codex-materialize-runner.js +10 -8
  158. package/dist/connectors/index.js +10 -8
  159. package/dist/consolidation-provenance-check.d.ts.map +1 -1
  160. package/dist/consolidation-provenance-check.js +2 -1
  161. package/dist/contradiction/index.js +3 -2
  162. package/dist/convergence-refresh.js +12 -10
  163. package/dist/corpus-watermark.js +12 -10
  164. package/dist/correction/correction-planner.d.ts.map +1 -1
  165. package/dist/cue-anchors.js +4 -3
  166. package/dist/deep-recall-http-glue.js +4 -3
  167. package/dist/{dreams-ledger-567VKVOU.js → dreams-ledger-UCHHRQ4R.js} +3 -2
  168. package/dist/entity-retrieval.js +10 -8
  169. package/dist/eval-trajectory-store.js +4 -3
  170. package/dist/eval-trajectory.js +4 -3
  171. package/dist/evals.js +3 -2
  172. package/dist/external-wiki-access.js +35 -33
  173. package/dist/extraction.js +14 -12
  174. package/dist/{first-start-migration-6A5BJPDW.js → first-start-migration-QVD22WWS.js} +6 -5
  175. package/dist/{first-start-migration-6A5BJPDW.js.map → first-start-migration-QVD22WWS.js.map} +1 -1
  176. package/dist/harmonic-construction.js +5 -4
  177. package/dist/harmonic-retrieval.js +14 -12
  178. package/dist/harmonic-source-lookup.js +3 -2
  179. package/dist/index.js +90 -88
  180. package/dist/json-store.d.ts.map +1 -1
  181. package/dist/json-store.js +2 -1
  182. package/dist/location/index.js +12 -10
  183. package/dist/maintenance/dreams-ledger.d.ts.map +1 -1
  184. package/dist/maintenance/memory-governance.d.ts.map +1 -1
  185. package/dist/maintenance/memory-governance.js +10 -8
  186. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +10 -8
  187. package/dist/maintenance/rebuild-memory-projection-runner.js +12 -10
  188. package/dist/maintenance/rebuild-memory-projection.js +11 -9
  189. package/dist/memory-browse-operations.js +35 -33
  190. package/dist/namespaces/migrate.js +11 -9
  191. package/dist/namespaces/search.js +7 -6
  192. package/dist/namespaces/storage.d.ts.map +1 -1
  193. package/dist/namespaces/storage.js +10 -8
  194. package/dist/objective-state-writers.js +4 -3
  195. package/dist/objective-state.js +3 -2
  196. package/dist/offline-sync-snapshot-stream.js +3 -2
  197. package/dist/offline-sync.d.ts.map +1 -1
  198. package/dist/offline-sync.js +2 -1
  199. package/dist/operator-doctor-corpus.js +13 -11
  200. package/dist/operator-toolkit.js +25 -23
  201. package/dist/orchestration/extraction-run.d.ts +6 -20
  202. package/dist/orchestration/extraction-run.d.ts.map +1 -1
  203. package/dist/orchestration/maintenance.js +20 -18
  204. package/dist/orchestrator.js +90 -88
  205. package/dist/profiling.d.ts.map +1 -1
  206. package/dist/profiling.js +2 -1
  207. package/dist/recall-navigation-operations.js +35 -33
  208. package/dist/recall-navigation.js +34 -32
  209. package/dist/{resolution-7AY36LGJ.js → resolution-ZU5BIAJA.js} +4 -3
  210. package/dist/resume-bundles.js +19 -17
  211. package/dist/retrieval-agents.d.ts +1 -1
  212. package/dist/retrieval-agents.d.ts.map +1 -1
  213. package/dist/retrieval-agents.js +7 -1
  214. package/dist/search/document-scanner.d.ts.map +1 -1
  215. package/dist/search/document-scanner.js +2 -1
  216. package/dist/search/factory.js +6 -5
  217. package/dist/search/index.js +6 -5
  218. package/dist/search/lancedb-backend.js +3 -2
  219. package/dist/search/meilisearch-backend.js +3 -2
  220. package/dist/search/orama-backend.js +3 -2
  221. package/dist/semantic-consolidation.js +11 -9
  222. package/dist/semantic-rule-promotion.js +10 -8
  223. package/dist/semantic-rule-verifier.js +10 -8
  224. package/dist/source-agent-qualifier.js +12 -10
  225. package/dist/standup/build.js +10 -8
  226. package/dist/storage/entity-canonical-id-migration.d.ts.map +1 -1
  227. package/dist/storage/entity-store.d.ts +32 -1
  228. package/dist/storage/entity-store.d.ts.map +1 -1
  229. package/dist/storage/memory-read-store.d.ts.map +1 -1
  230. package/dist/storage/supersession-audit.d.ts.map +1 -1
  231. package/dist/storage.d.ts.map +1 -1
  232. package/dist/storage.js +9 -7
  233. package/dist/support-passport/index.js +37 -35
  234. package/dist/{tier-stats-RQM76XYY.js → tier-stats-C3IAMS4X.js} +6 -5
  235. package/dist/{tier-stats-RQM76XYY.js.map → tier-stats-C3IAMS4X.js.map} +1 -1
  236. package/dist/transcript.d.ts.map +1 -1
  237. package/dist/transcript.js +2 -1
  238. package/dist/transfer/export-okf.js +10 -8
  239. package/dist/trust-zones.js +3 -2
  240. package/dist/utility-learner.js +4 -3
  241. package/dist/utility-runtime.js +5 -4
  242. package/dist/utility-telemetry.js +3 -2
  243. package/dist/utils/macos-replication-junk.d.ts +32 -0
  244. package/dist/utils/macos-replication-junk.d.ts.map +1 -0
  245. package/dist/utils/malformed-entity-record.d.ts +24 -0
  246. package/dist/utils/malformed-entity-record.d.ts.map +1 -0
  247. package/dist/verified-recall.js +10 -8
  248. package/dist/who-knows-cli.js +11 -9
  249. package/dist/who-knows.js +10 -8
  250. package/dist/work-product-ledger.js +3 -2
  251. package/package.json +2 -2
  252. package/src/calibration.ts +3 -2
  253. package/src/cli.ts +2 -2
  254. package/src/consolidation-provenance-check.ts +2 -0
  255. package/src/correction/correction-planner.ts +3 -2
  256. package/src/json-store.ts +3 -0
  257. package/src/macos-replication-junk-scanners.test.ts +275 -0
  258. package/src/maintenance/dreams-ledger.ts +2 -0
  259. package/src/maintenance/memory-governance.ts +2 -0
  260. package/src/namespaces/storage.ts +2 -0
  261. package/src/offline-sync-macos-junk.test.ts +169 -0
  262. package/src/offline-sync.ts +7 -0
  263. package/src/orchestration/extraction-run.ts +6 -20
  264. package/src/profiling.ts +2 -1
  265. package/src/retrieval-agents.ts +29 -12
  266. package/src/search/document-scanner.ts +4 -0
  267. package/src/storage/entity-canonical-id-migration.ts +56 -13
  268. package/src/storage/entity-store.ts +173 -15
  269. package/src/storage/memory-read-store.ts +30 -5
  270. package/src/storage/supersession-audit.ts +2 -0
  271. package/src/storage.ts +3 -2
  272. package/src/transcript.ts +11 -10
  273. package/src/utils/macos-replication-junk.test.ts +46 -0
  274. package/src/utils/macos-replication-junk.ts +65 -0
  275. package/src/utils/malformed-entity-record.ts +101 -0
  276. package/dist/chunk-4O6WRBGE.js.map +0 -1
  277. package/dist/chunk-63B2IZYE.js.map +0 -1
  278. package/dist/chunk-B6O2YLUR.js.map +0 -1
  279. package/dist/chunk-BLVHDY2U.js.map +0 -1
  280. package/dist/chunk-CLWBFR7Q.js.map +0 -1
  281. package/dist/chunk-EQWEIIKQ.js.map +0 -1
  282. package/dist/chunk-FUFAXVBA.js.map +0 -1
  283. package/dist/chunk-NIRQGDYC.js.map +0 -1
  284. package/dist/chunk-P5NQN4JE.js.map +0 -1
  285. package/dist/chunk-PAZ35RJ4.js.map +0 -1
  286. package/dist/chunk-Q4E24IRR.js.map +0 -1
  287. package/dist/chunk-QJ622LTI.js.map +0 -1
  288. package/dist/chunk-TZNDKTX5.js.map +0 -1
  289. package/dist/chunk-ZV65I6ME.js.map +0 -1
  290. /package/dist/{chunk-YFMBHQRG.js.map → chunk-2PTH4PRL.js.map} +0 -0
  291. /package/dist/{chunk-TITG2NBS.js.map → chunk-2PYHLSXK.js.map} +0 -0
  292. /package/dist/{chunk-KH2LKDX7.js.map → chunk-33G67YZF.js.map} +0 -0
  293. /package/dist/{chunk-SWIKABKI.js.map → chunk-3Q3XD3NO.js.map} +0 -0
  294. /package/dist/{chunk-4KY5GSMB.js.map → chunk-4PDTVVSW.js.map} +0 -0
  295. /package/dist/{chunk-HM7RHKS4.js.map → chunk-4RNBLLZR.js.map} +0 -0
  296. /package/dist/{chunk-Y4NKEXQT.js.map → chunk-5ATSXCAG.js.map} +0 -0
  297. /package/dist/{chunk-JDZFIR2S.js.map → chunk-5KGYTX5O.js.map} +0 -0
  298. /package/dist/{chunk-J7JWFZHI.js.map → chunk-5MLGY6IY.js.map} +0 -0
  299. /package/dist/{chunk-NW2E4CI2.js.map → chunk-5SMR542T.js.map} +0 -0
  300. /package/dist/{chunk-S7LWX2PQ.js.map → chunk-655FVTCD.js.map} +0 -0
  301. /package/dist/{chunk-4OSG5Y6M.js.map → chunk-6YEPGWUP.js.map} +0 -0
  302. /package/dist/{chunk-W47S5TIH.js.map → chunk-7VQ6AI7H.js.map} +0 -0
  303. /package/dist/{chunk-WLMZ2L5P.js.map → chunk-AZDTDWS2.js.map} +0 -0
  304. /package/dist/{chunk-G7NYVKD6.js.map → chunk-B2NXOVZN.js.map} +0 -0
  305. /package/dist/{chunk-N7KYEVLK.js.map → chunk-BK2BVLZW.js.map} +0 -0
  306. /package/dist/{chunk-S2I7DL5Q.js.map → chunk-C2RW36YR.js.map} +0 -0
  307. /package/dist/{chunk-6LG7BWKW.js.map → chunk-CFZ4SXXH.js.map} +0 -0
  308. /package/dist/{chunk-JQ7XU625.js.map → chunk-CQOIWJ5E.js.map} +0 -0
  309. /package/dist/{chunk-FSIMZNBC.js.map → chunk-CXOYUANR.js.map} +0 -0
  310. /package/dist/{chunk-QOZJCSFO.js.map → chunk-DQR2LD3V.js.map} +0 -0
  311. /package/dist/{chunk-MATDGSJ7.js.map → chunk-DUPHIZBY.js.map} +0 -0
  312. /package/dist/{chunk-EBA5DA77.js.map → chunk-EOU6V4IN.js.map} +0 -0
  313. /package/dist/{chunk-5WCJLQTM.js.map → chunk-F2772ATT.js.map} +0 -0
  314. /package/dist/{chunk-46EST7JO.js.map → chunk-F2XNSIPP.js.map} +0 -0
  315. /package/dist/{chunk-PZHQWFR3.js.map → chunk-G3UUAQOD.js.map} +0 -0
  316. /package/dist/{chunk-YE36AJL7.js.map → chunk-GCVDFX66.js.map} +0 -0
  317. /package/dist/{chunk-T2YX56QI.js.map → chunk-GQJKVQJR.js.map} +0 -0
  318. /package/dist/{chunk-I7S55EOB.js.map → chunk-GUY6L6LL.js.map} +0 -0
  319. /package/dist/{chunk-L5DAHSEZ.js.map → chunk-GWVNGDJW.js.map} +0 -0
  320. /package/dist/{chunk-N45NEBOD.js.map → chunk-GZXXPCWJ.js.map} +0 -0
  321. /package/dist/{chunk-EPJDSQHF.js.map → chunk-H5IUN433.js.map} +0 -0
  322. /package/dist/{chunk-EUAIYYYR.js.map → chunk-H6FREOYX.js.map} +0 -0
  323. /package/dist/{chunk-T3FMRLWQ.js.map → chunk-HFSPY26A.js.map} +0 -0
  324. /package/dist/{chunk-GH7AOMJD.js.map → chunk-IJMDBYCO.js.map} +0 -0
  325. /package/dist/{chunk-4IHBN6WU.js.map → chunk-JKMIGCK6.js.map} +0 -0
  326. /package/dist/{chunk-ROBHL3GL.js.map → chunk-JWX2Q6HS.js.map} +0 -0
  327. /package/dist/{chunk-DPR2WTN3.js.map → chunk-JZTEOBOR.js.map} +0 -0
  328. /package/dist/{chunk-JIHMUOOS.js.map → chunk-KLJVTZ3R.js.map} +0 -0
  329. /package/dist/{chunk-FP4JYE66.js.map → chunk-KW4AJ7T3.js.map} +0 -0
  330. /package/dist/{chunk-QODKDRSP.js.map → chunk-L6AZOEXV.js.map} +0 -0
  331. /package/dist/{chunk-LS2FHUML.js.map → chunk-LQ5SS4OP.js.map} +0 -0
  332. /package/dist/{chunk-SIIRTDJ4.js.map → chunk-LWFWZTWX.js.map} +0 -0
  333. /package/dist/{chunk-BMWN7B3Y.js.map → chunk-LXATZLSC.js.map} +0 -0
  334. /package/dist/{chunk-O4SGYW7H.js.map → chunk-MAVYEZKM.js.map} +0 -0
  335. /package/dist/{chunk-B665A6BO.js.map → chunk-MJIOGYKX.js.map} +0 -0
  336. /package/dist/{chunk-RTKV5XHL.js.map → chunk-MO6N4QYY.js.map} +0 -0
  337. /package/dist/{chunk-N4C7QKOG.js.map → chunk-MWWAQXZ6.js.map} +0 -0
  338. /package/dist/{chunk-LCKVXX5F.js.map → chunk-MXV2MY6C.js.map} +0 -0
  339. /package/dist/{chunk-FFOVKNQV.js.map → chunk-NAGMQXWV.js.map} +0 -0
  340. /package/dist/{chunk-ZJVMUBYF.js.map → chunk-NHUX6GXA.js.map} +0 -0
  341. /package/dist/{chunk-CB6ANA2I.js.map → chunk-NZCKG25S.js.map} +0 -0
  342. /package/dist/{chunk-UMTCNEVQ.js.map → chunk-O2YPCFJT.js.map} +0 -0
  343. /package/dist/{chunk-WSGPFRBH.js.map → chunk-OMERTLB7.js.map} +0 -0
  344. /package/dist/{chunk-QX6JN3O4.js.map → chunk-PEF5LHQU.js.map} +0 -0
  345. /package/dist/{chunk-JYZSRNR7.js.map → chunk-PIITB2YZ.js.map} +0 -0
  346. /package/dist/{chunk-UQDG3YLN.js.map → chunk-PRU7OF3Y.js.map} +0 -0
  347. /package/dist/{chunk-EU534WGS.js.map → chunk-PVHQSLNN.js.map} +0 -0
  348. /package/dist/{chunk-5VC7J76U.js.map → chunk-QPH52AZB.js.map} +0 -0
  349. /package/dist/{chunk-XISROV24.js.map → chunk-QSEUUQUF.js.map} +0 -0
  350. /package/dist/{chunk-O2IPAX26.js.map → chunk-RTTPBBAN.js.map} +0 -0
  351. /package/dist/{chunk-W5MCEVUS.js.map → chunk-RYYVMZBR.js.map} +0 -0
  352. /package/dist/{chunk-ZSH2NRDV.js.map → chunk-TN4EA4X4.js.map} +0 -0
  353. /package/dist/{chunk-SS3IS2JR.js.map → chunk-UGYUBENJ.js.map} +0 -0
  354. /package/dist/{chunk-GELS5Z5Z.js.map → chunk-V3TXIXXY.js.map} +0 -0
  355. /package/dist/{chunk-WVADKFWV.js.map → chunk-VNZMZPAC.js.map} +0 -0
  356. /package/dist/{chunk-JPTPS4OB.js.map → chunk-VPXIKBPX.js.map} +0 -0
  357. /package/dist/{chunk-OP6N4H6A.js.map → chunk-W3FVQBGF.js.map} +0 -0
  358. /package/dist/{chunk-W3K3HITK.js.map → chunk-WLT6LTQP.js.map} +0 -0
  359. /package/dist/{chunk-GMXWTJNU.js.map → chunk-XKRXN63M.js.map} +0 -0
  360. /package/dist/{chunk-KR6ZKECI.js.map → chunk-XYGQSDTH.js.map} +0 -0
  361. /package/dist/{chunk-22W2XWGH.js.map → chunk-YBO2WGCV.js.map} +0 -0
  362. /package/dist/{chunk-P7TOIOT7.js.map → chunk-YR4COAEC.js.map} +0 -0
  363. /package/dist/{chunk-6WHJ2EAB.js.map → chunk-Z64TS5V4.js.map} +0 -0
  364. /package/dist/{chunk-NHLLKEKK.js.map → chunk-ZAJLJ35W.js.map} +0 -0
  365. /package/dist/{dreams-ledger-567VKVOU.js.map → dreams-ledger-UCHHRQ4R.js.map} +0 -0
  366. /package/dist/{resolution-7AY36LGJ.js.map → resolution-ZU5BIAJA.js.map} +0 -0
@@ -22,6 +22,11 @@ import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
22
22
  import { assertPathInsideRoot } from "../utils/path-containment.js";
23
23
  import { withEntityCanonicalMutationLock } from "./entity-canonical-id-lock.js";
24
24
  import { assertSafeEntityId } from "./entity-id-safety.js";
25
+ import { isMalformedEntityRecord } from "../utils/malformed-entity-record.js";
26
+ import {
27
+ isMacOsReplicationJunkBasename,
28
+ warnIgnoredMacOsReplicationJunk,
29
+ } from "../utils/macos-replication-junk.js";
25
30
 
26
31
  import {
27
32
  ENTITY_CANONICAL_ID_MIGRATION_FILE,
@@ -100,7 +105,7 @@ async function fingerprintEntityEntries(entitiesDir: string): Promise<string> {
100
105
  let names: string[];
101
106
  try {
102
107
  names = (await readdir(entitiesDir))
103
- .filter((name) => path.extname(name) === ".md")
108
+ .filter((name) => path.extname(name) === ".md" && !isMacOsReplicationJunkBasename(name))
104
109
  .sort();
105
110
  } catch (error) {
106
111
  if (isErrnoCode(error, "ENOENT")) return "missing";
@@ -386,10 +391,16 @@ async function readSafeEntityEntries(entitiesDir: string): Promise<string[]> {
386
391
  */
387
392
  export type BlockedEntityPairs = Map<string, string>;
388
393
 
394
+ interface EntityScanNotes {
395
+ junk: Set<string>;
396
+ malformed: Set<string>;
397
+ }
398
+
389
399
  async function discoverMappings(
390
400
  deps: EntityCanonicalIdMigrationDependencies,
391
401
  knownMappings: Readonly<Record<string, string>> = {},
392
402
  blocked: BlockedEntityPairs = new Map(),
403
+ scanNotes?: EntityScanNotes,
393
404
  ): Promise<Record<string, string>> {
394
405
  const mappings: Record<string, string> = {};
395
406
  const canonicalOwners = new Map<string, string[]>();
@@ -401,21 +412,29 @@ async function discoverMappings(
401
412
  blocked.clear();
402
413
  const entityEntries = await readSafeEntityEntries(deps.entitiesDir);
403
414
  for (const entry of entityEntries) {
415
+ // AppleDouble (`._*`) and `.DS_Store` are Finder metadata, not entity
416
+ // files. A real file that cannot be parsed is left in place: this scan
417
+ // runs during directory init, and aborting it took the daemon down.
418
+ // Skipping is the same outcome as the old throw (the file is not
419
+ // rewritten) without refusing to boot. Symlink checks above still run.
420
+ if (isMacOsReplicationJunkBasename(entry)) {
421
+ scanNotes?.junk.add(entry);
422
+ continue;
423
+ }
404
424
  if (!entry.endsWith(".md")) continue;
405
425
  const legacyId = entry.slice(0, -".md".length);
406
426
  assertSafeEntityId(legacyId);
407
427
  const legacyPath = deps.resolveEntityFilePath(legacyId);
408
428
  if (legacyPath === null) continue;
409
429
  const entityContent = await deps.readStorageSecureFile(legacyPath);
410
- if (
411
- !/^#[ \t]+[^\r\n \t]/m.test(entityContent)
412
- || !/^\*\*Type:\*\*[ \t]*[^\r\n \t]/m.test(entityContent)
413
- ) {
414
- throw new Error(`Cannot migrate malformed entity file ${entry}: missing name heading or type.`);
430
+ if (isMalformedEntityRecord(entityContent)) {
431
+ scanNotes?.malformed.add(entry);
432
+ continue;
415
433
  }
416
434
  const entity = deps.parseEntityFile(entityContent);
417
435
  if (!entity.name.trim() || !entity.type.trim()) {
418
- throw new Error(`Cannot migrate malformed entity file ${entry}: missing name or type.`);
436
+ scanNotes?.malformed.add(entry);
437
+ continue;
419
438
  }
420
439
  const canonicalId = deps.normalizeEntityName(entity.name, entity.type);
421
440
  assertSafeEntityId(canonicalId);
@@ -596,12 +615,14 @@ async function rewriteRelationshipTargets(
596
615
  let rewritten = false;
597
616
  const entries = await readSafeEntityEntries(deps.entitiesDir);
598
617
  for (const entry of entries) {
599
- if (!entry.endsWith(".md")) continue;
618
+ if (!entry.endsWith(".md") || isMacOsReplicationJunkBasename(entry)) continue;
600
619
  const entityPath = deps.resolveEntityFilePath(entry.slice(0, -".md".length));
601
620
  if (entityPath === null) continue;
602
621
  const observedEntityFingerprint = await fingerprintPath(entityPath);
603
622
  if (observedEntityFingerprint === "missing") continue;
604
- const entity = deps.parseEntityFile(await deps.readStorageSecureFile(entityPath));
623
+ const entityRaw = await deps.readStorageSecureFile(entityPath);
624
+ if (isMalformedEntityRecord(entityRaw)) continue;
625
+ const entity = deps.parseEntityFile(entityRaw);
605
626
  const relationships = entity.relationships.map((relationship) => {
606
627
  const target = mappings[relationship.target];
607
628
  return target ? { ...relationship, target } : relationship;
@@ -611,7 +632,9 @@ async function rewriteRelationshipTargets(
611
632
  deps.stateDir,
612
633
  async (refreshEntityLock) => {
613
634
  if (!(await refreshLock())) throw new Error("Lost entity canonical-id migration lock.");
614
- const latestEntity = deps.parseEntityFile(await deps.readStorageSecureFile(entityPath));
635
+ const latestRaw = await deps.readStorageSecureFile(entityPath);
636
+ if (isMalformedEntityRecord(latestRaw)) return false;
637
+ const latestEntity = deps.parseEntityFile(latestRaw);
615
638
  if ((await fingerprintPath(entityPath)) !== observedEntityFingerprint) return false;
616
639
  const latestRelationships = latestEntity.relationships.map((relationship) => {
617
640
  const target = mappings[relationship.target];
@@ -794,6 +817,15 @@ async function migrateEntityFilePair(
794
817
  const entityContent = await deps.readStorageSecureFile(legacyPath);
795
818
  await assertNotSymlink(legacyPath, legacyId);
796
819
  await assertEntityContentUnchanged(deps, legacyPath, entityContent, legacyId);
820
+ // A journal entry must not relocate Finder metadata or a record this scan
821
+ // would leave in place. readStorageSecureFile has already decrypted, so
822
+ // the check is on that plaintext. The mapping stays for a later repair.
823
+ if (
824
+ isMacOsReplicationJunkBasename(path.basename(legacyPath))
825
+ || isMalformedEntityRecord(entityContent)
826
+ ) {
827
+ return { deferred: false, progressed: false };
828
+ }
797
829
  let canonicalFingerprintAfterWrite: string | null = null;
798
830
  try {
799
831
  await deps.writeStorageSecureFile(canonicalPath, entityContent, entityEncrypted);
@@ -864,6 +896,7 @@ export async function migrateLegacyEntityCanonicalIds(
864
896
  };
865
897
  }
866
898
  const blocked: BlockedEntityPairs = new Map();
899
+ const scanNotes: EntityScanNotes = { junk: new Set(), malformed: new Set() };
867
900
  // Parks for pairs whose files are GONE, tracked separately from
868
901
  // collision parks: pruneBlocked drops these (the canonical file is gone
869
902
  // too), and the rescan's blocked.clear() would otherwise silence them
@@ -886,6 +919,16 @@ export async function migrateLegacyEntityCanonicalIds(
886
919
  + "The stale journal entries were removed; references to those legacy ids do not resolve either way.",
887
920
  );
888
921
  }
922
+ warnIgnoredMacOsReplicationJunk(deps.entitiesDir, scanNotes.junk.size, (message) => {
923
+ log.warn(`entity canonical-id migration ${message}`);
924
+ });
925
+ if (scanNotes.malformed.size > 0) {
926
+ const names = [...scanNotes.malformed].sort().join(", ");
927
+ log.warn(
928
+ `entity canonical-id migration skipped ${scanNotes.malformed.size} malformed entity file(s): ${names}. `
929
+ + "Each file was left in place; startup continues. Fix or remove the file to migrate it.",
930
+ );
931
+ }
889
932
  // Every finish() path either just rewrote references (main/reconcile
890
933
  // paths), has none to rewrite (empty mappings), or observed no marker
891
934
  // (stable no-op) — so the CONSUMED generation is removed here. A fresh
@@ -997,7 +1040,7 @@ export async function migrateLegacyEntityCanonicalIds(
997
1040
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
998
1041
  const discoveredBefore = rejectMappingCycles(
999
1042
  state.mappings,
1000
- await discoverMappings(deps, state.mappings, blocked),
1043
+ await discoverMappings(deps, state.mappings, blocked, scanNotes),
1001
1044
  );
1002
1045
  const revivedBefore = await pruneBlocked();
1003
1046
  const mergedBefore = collapseMappings(mergeDiscoveredMappings(state.mappings, discoveredBefore));
@@ -1046,7 +1089,7 @@ export async function migrateLegacyEntityCanonicalIds(
1046
1089
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
1047
1090
  const discoveredAfter = rejectMappingCycles(
1048
1091
  state.mappings,
1049
- await discoverMappings(deps, state.mappings, blocked),
1092
+ await discoverMappings(deps, state.mappings, blocked, scanNotes),
1050
1093
  );
1051
1094
  // Reconcile before declaring completion: this rescan can resolve a
1052
1095
  // park (another writer removed the legacy file), and completing
@@ -1107,7 +1150,7 @@ export async function migrateLegacyEntityCanonicalIds(
1107
1150
  if (!(await lock.refresh())) throw new Error("Lost entity canonical-id migration lock.");
1108
1151
  const discoveredAfter = rejectMappingCycles(
1109
1152
  state.mappings,
1110
- await discoverMappings(deps, state.mappings, blocked),
1153
+ await discoverMappings(deps, state.mappings, blocked, scanNotes),
1111
1154
  );
1112
1155
  // A park resolved after the rewrite pass is promoted here, and a
1113
1156
  // promotion still has to be APPLIED. Completing on `discoveredAfter`
@@ -10,12 +10,17 @@
10
10
  * - fragmented-entity merge (consolidation)
11
11
  */
12
12
 
13
- import { readdir, unlink } from "node:fs/promises";
13
+ import { lstat, readdir, realpath, unlink } from "node:fs/promises";
14
14
  import path from "node:path";
15
15
  import { checkCorpusReadAbort, type CorpusReadOptions } from "../corpus-read-cancellation.js";
16
16
  import { normalizeEntityStructuredSection, sortStructuredSectionsBySchema } from "../entity-schema.js";
17
17
  import { withEntityCanonicalMutationLock } from "./entity-canonical-id-lock.js";
18
+ import { isMalformedEntityRecord } from "../utils/malformed-entity-record.js";
18
19
  import { log } from "../logger.js";
20
+ import {
21
+ warnIgnoredMacOsReplicationJunk,
22
+ withoutMacOsReplicationJunk,
23
+ } from "../utils/macos-replication-junk.js";
19
24
  import { getCachedEntities, setCachedEntities } from "../memory-cache.js";
20
25
  import type { VersionTrigger } from "../page-versioning.js";
21
26
  import { SecureStoreLockedError } from "../secure-store/secure-fs.js";
@@ -28,6 +33,7 @@ import type {
28
33
  ScoredEntity,
29
34
  } from "../types.js";
30
35
  import { isErrnoCode } from "../utils/errno.js";
36
+ import { pathIsInside } from "../utils/path-containment.js";
31
37
  import {
32
38
  reconcileIfJournalMovedSync,
33
39
  requestEntityCanonicalIdReconcileSync,
@@ -79,6 +85,9 @@ export interface EntityStoreDeps {
79
85
  }
80
86
 
81
87
  export class EntityStore {
88
+ /** Filename → file identity of the last indexable check. Unchanged files are not reread. */
89
+ private readonly entityIndexableCache = new Map<string, { identity: string; ok: boolean }>();
90
+
82
91
  constructor(
83
92
  private readonly deps: EntityStoreDeps,
84
93
  ) {}
@@ -378,15 +387,127 @@ export class EntityStore {
378
387
  }
379
388
  }
380
389
 
381
- /** Return sorted list of entity filenames (without .md extension) */
390
+ /**
391
+ * True when `entities/` is a real directory inside this memory root.
392
+ * `realpath` on a symlinked root would treat the link target as trusted,
393
+ * so the check uses `lstat` first and refuses the scan when the root
394
+ * itself is a symlink.
395
+ */
396
+ private async isTrustedEntitiesRoot(): Promise<boolean> {
397
+ let rootStat;
398
+ try {
399
+ rootStat = await lstat(this.deps.entitiesDir);
400
+ } catch (err) {
401
+ if (isErrnoCode(err, "ENOENT")) return false;
402
+ throw err;
403
+ }
404
+ if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) return false;
405
+ let memoryRoot: string;
406
+ let entitiesReal: string;
407
+ try {
408
+ memoryRoot = await realpath(this.deps.baseDir);
409
+ entitiesReal = await realpath(this.deps.entitiesDir);
410
+ } catch (err) {
411
+ if (isErrnoCode(err, "ENOENT")) return false;
412
+ throw err;
413
+ }
414
+ return pathIsInside(memoryRoot, entitiesReal);
415
+ }
416
+
417
+ /**
418
+ * Entity directory listing with macOS replication junk removed.
419
+ * One summary warning per directory and count, shared with migration.
420
+ * A symlinked entities root yields an empty list and is not read.
421
+ */
422
+ private async readEntityDirectoryNames(): Promise<string[]> {
423
+ if (!(await this.isTrustedEntitiesRoot())) return [];
424
+ const entries = await readdir(this.deps.entitiesDir);
425
+ const { kept, ignored } = withoutMacOsReplicationJunk(entries, (name) => name);
426
+ warnIgnoredMacOsReplicationJunk(this.deps.entitiesDir, ignored, (message) => {
427
+ log.warn(`entity load ${message}`);
428
+ });
429
+ return kept;
430
+ }
431
+
432
+ /**
433
+ * A directory entry is readable only when it is a regular file.
434
+ * Symlinks, FIFOs, and devices are skipped before any read. The entities
435
+ * root is refused separately, before the directory is listed.
436
+ */
437
+ private async isContainedRegularEntityFile(file: string): Promise<boolean> {
438
+ const filePath = path.join(this.deps.entitiesDir, file);
439
+ let entryStat;
440
+ try {
441
+ entryStat = await lstat(filePath);
442
+ } catch (err) {
443
+ if (isErrnoCode(err, "ENOENT")) return false;
444
+ throw err;
445
+ }
446
+ return !entryStat.isSymbolicLink() && entryStat.isFile();
447
+ }
448
+
449
+ /**
450
+ * Malformed entity files stay on disk (startup must not relocate them)
451
+ * and stay out of merge, so a fragment merge cannot delete them.
452
+ * Unchanged files reuse the previous result so a name listing does not
453
+ * reread the whole directory on every extraction write.
454
+ */
455
+ private async isIndexableEntityMarkdown(file: string): Promise<boolean> {
456
+ const filePath = path.join(this.deps.entitiesDir, file);
457
+ let entryStat;
458
+ try {
459
+ entryStat = await lstat(filePath);
460
+ } catch (err) {
461
+ if (isErrnoCode(err, "ENOENT")) return false;
462
+ throw err;
463
+ }
464
+ if (entryStat.isSymbolicLink() || !entryStat.isFile()) return false;
465
+ const identity = `${entryStat.dev}:${entryStat.ino}:${entryStat.mtimeMs}:${entryStat.size}`;
466
+ const cached = this.entityIndexableCache.get(file);
467
+ if (cached?.identity === identity) return cached.ok;
468
+ try {
469
+ const content = await this.deps.readStorageSecureFile(filePath);
470
+ // Missing `**Type:**` still parses (type defaults to "other"). Only an
471
+ // empty name, including a tab heading, stays out of the name list.
472
+ const parsed = parseEntityFile(content, this.deps.entitySchemas);
473
+ const ok = parsed.name.trim().length > 0 && parsed.type.trim().length > 0;
474
+ this.entityIndexableCache.set(file, { identity, ok });
475
+ return ok;
476
+ } catch (err) {
477
+ if (err instanceof SecureStoreLockedError) throw err;
478
+ if (!isErrnoCode(err, "ENOENT")) throw err;
479
+ return false;
480
+ }
481
+ }
482
+
483
+ /**
484
+ * Sorted entity filenames (without .md). Malformed records stay on disk
485
+ * and are omitted, so extraction, matching, and entity list cannot reuse them.
486
+ */
382
487
  async listEntityNames(): Promise<string[]> {
383
488
  try {
384
- const entries = await readdir(this.deps.entitiesDir);
385
- return entries
386
- .filter((e) => e.endsWith(".md"))
387
- .map((e) => e.replace(".md", ""))
388
- .sort();
389
- } catch {
489
+ const entries = await this.readEntityDirectoryNames();
490
+ const mdFiles = entries.filter((e) => e.endsWith(".md"));
491
+ const names: string[] = [];
492
+ const batchSize = 100;
493
+ for (let i = 0; i < mdFiles.length; i += batchSize) {
494
+ const resolved = await Promise.all(mdFiles.slice(i, i + batchSize).map(async (file) => {
495
+ try {
496
+ if (!(await this.isIndexableEntityMarkdown(file))) return null;
497
+ } catch (err) {
498
+ if (err instanceof SecureStoreLockedError) throw err;
499
+ return null;
500
+ }
501
+ return file.slice(0, -3);
502
+ }));
503
+ for (const name of resolved) {
504
+ if (name) names.push(name);
505
+ }
506
+ }
507
+ names.sort();
508
+ return names;
509
+ } catch (err) {
510
+ if (err instanceof SecureStoreLockedError) throw err;
390
511
  return [];
391
512
  }
392
513
  }
@@ -404,8 +525,10 @@ export class EntityStore {
404
525
  // completed migration's reference scan.
405
526
  const wrote = await withEntityCanonicalMutationLock(stateDir, async () => {
406
527
  const raw = await this.readEntity(entityName);
407
- if (!raw) return false;
408
- const serialized = serializeEntityFile(parseEntityFile(raw, this.deps.entitySchemas), this.deps.entitySchemas, this.deps.okfConformanceEnabled());
528
+ if (!raw || isMalformedEntityRecord(raw)) return false;
529
+ const parsed = parseEntityFile(raw, this.deps.entitySchemas);
530
+ if (!parsed.name.trim() || !parsed.type.trim()) return false;
531
+ const serialized = serializeEntityFile(parsed, this.deps.entitySchemas, this.deps.okfConformanceEnabled());
409
532
  if (raw.trimEnd() === serialized.trimEnd()) return false;
410
533
  const filePath = this.deps.resolveEntityFilePath(entityName);
411
534
  if (filePath === null) return false;
@@ -513,7 +636,7 @@ export class EntityStore {
513
636
  if (cached) return cached;
514
637
 
515
638
  try {
516
- const entries = await readdir(this.deps.entitiesDir);
639
+ const entries = await this.readEntityDirectoryNames();
517
640
  const mdFiles = entries.filter((e) => e.endsWith(".md"));
518
641
  if (mdFiles.length === 0) return [];
519
642
 
@@ -530,6 +653,7 @@ export class EntityStore {
530
653
  const results = await Promise.all(
531
654
  batch.map(async (entry) => {
532
655
  try {
656
+ if (!(await this.isContainedRegularEntityFile(entry))) return null;
533
657
  return await this.deps.readStorageSecureFile(path.join(this.deps.entitiesDir, entry));
534
658
  } catch (err) {
535
659
  if (err instanceof SecureStoreLockedError) throw err;
@@ -539,7 +663,10 @@ export class EntityStore {
539
663
  }),
540
664
  );
541
665
  for (const content of results) {
542
- if (content !== null) entities.push(parseEntityFile(content, this.deps.entitySchemas));
666
+ if (content === null) continue;
667
+ const entity = parseEntityFile(content, this.deps.entitySchemas);
668
+ if (!entity.name.trim() || !entity.type.trim()) continue;
669
+ entities.push(entity);
543
670
  }
544
671
  }
545
672
  // A signal that fired during the last batch's await would otherwise publish
@@ -642,8 +769,13 @@ export class EntityStore {
642
769
  private async mergeFragmentedEntitiesUnlocked(): Promise<number> {
643
770
  let merged = 0;
644
771
  try {
645
- const entries = await readdir(this.deps.entitiesDir);
646
- const mdFiles = entries.filter((e) => e.endsWith(".md"));
772
+ const entries = await this.readEntityDirectoryNames();
773
+ const mdFiles: string[] = [];
774
+ for (const file of entries) {
775
+ if (!file.endsWith(".md")) continue;
776
+ if (!(await this.isIndexableEntityMarkdown(file))) continue;
777
+ mdFiles.push(file);
778
+ }
647
779
 
648
780
  // Group files by their canonical name
649
781
  const groups = new Map<string, string[]>();
@@ -660,9 +792,31 @@ export class EntityStore {
660
792
  groups.get(canonical)!.push(file);
661
793
  }
662
794
 
795
+ // A malformed or otherwise non-indexable file is absent from `files`.
796
+ // Writing the canonical path anyway would replace that file, then
797
+ // delete the fragments that still hold the only readable copy.
798
+ const canonicalDestinationOccupied = async (
799
+ canonicalName: string,
800
+ members: readonly string[],
801
+ ): Promise<boolean> => {
802
+ if (members.includes(canonicalName)) return false;
803
+ try {
804
+ await lstat(path.join(this.deps.entitiesDir, canonicalName));
805
+ return true;
806
+ } catch (err) {
807
+ if (isErrnoCode(err, "ENOENT")) return false;
808
+ throw err;
809
+ }
810
+ };
811
+
663
812
  // Merge groups with more than one file
664
813
  for (const [canonical, files] of groups) {
665
814
  if (files.length <= 1) continue;
815
+ const canonicalName = `${canonical}.md`;
816
+ if (await canonicalDestinationOccupied(canonicalName, files)) {
817
+ log.warn(`skipped entity merge into occupied ${canonicalName}`);
818
+ continue;
819
+ }
666
820
 
667
821
  // Parse all files and merge into a single EntityFile
668
822
  const mergedEntity: EntityFile = {
@@ -901,7 +1055,11 @@ export class EntityStore {
901
1055
  mergedEntity.created = mergedEntity.created || mergedEntity.updated || new Date().toISOString();
902
1056
  mergedEntity.updated = mergedEntity.updated || new Date().toISOString();
903
1057
 
904
- const canonicalPath = path.join(this.deps.entitiesDir, `${canonical}.md`);
1058
+ const canonicalPath = path.join(this.deps.entitiesDir, canonicalName);
1059
+ if (await canonicalDestinationOccupied(canonicalName, files)) {
1060
+ log.warn(`skipped entity merge into occupied ${canonicalName}`);
1061
+ continue;
1062
+ }
905
1063
  await this.deps.writeStorageSecureFile(canonicalPath, serializeEntityFile(mergedEntity, this.deps.entitySchemas, this.deps.okfConformanceEnabled()));
906
1064
  this.deps.bumpEntityMutationVersion();
907
1065
 
@@ -17,6 +17,8 @@ import { SecureStoreLockedError, readMaybeEncryptedFile } from "../secure-store/
17
17
  import { type BufferSurpriseEvent, type CompressionGuidelineOptimizerState, type MemoryFile, type PluginConfig, confidenceTier } from "../types.js";
18
18
  import { RECALL_FALLBACK_DIRS } from "../utils/category-dir.js";
19
19
  import { isErrnoCode } from "../utils/errno.js";
20
+ import { isPopulatedUnnamedEntityRecord } from "../utils/malformed-entity-record.js";
21
+ import { isMacOsReplicationJunkBasename } from "../utils/macos-replication-junk.js";
20
22
  import { assertPathInsideRoot } from "../utils/path-containment.js";
21
23
  import { isAbortError } from "../abort-error.js";
22
24
  import { checkCorpusReadAbort, type CorpusReadOptions } from "../corpus-read-cancellation.js";
@@ -97,6 +99,18 @@ function isPropagatableReadError(err: unknown): boolean {
97
99
  return typeof code === "string" && code !== "ENOENT";
98
100
  }
99
101
 
102
+ /**
103
+ * Markdown under this store's `entities/` directory. The first relative
104
+ * segment must be `entities`; a memory root whose absolute path contains
105
+ * that name is not an entity store.
106
+ */
107
+ function isStoreEntityMarkdown(baseDir: string, filePath: string): boolean {
108
+ if (!filePath.endsWith(".md")) return false;
109
+ const relative = path.relative(baseDir, filePath);
110
+ if (relative.length === 0 || relative.startsWith("..") || path.isAbsolute(relative)) return false;
111
+ return relative.split(path.sep)[0] === "entities";
112
+ }
113
+
100
114
  export class MemoryReadStore {
101
115
  constructor(
102
116
  private readonly deps: MemoryReadStoreDeps,
@@ -117,7 +131,7 @@ export class MemoryReadStore {
117
131
  try {
118
132
  const entries = await readdir(this.deps.wearablesDir, { withFileTypes: true });
119
133
  sources = entries
120
- .filter((entry) => entry.isDirectory())
134
+ .filter((entry) => entry.isDirectory() && !isMacOsReplicationJunkBasename(entry.name))
121
135
  .map((entry) => entry.name);
122
136
  } catch (err) {
123
137
  if ((err as NodeJS.ErrnoException).code === "ENOENT") return [];
@@ -134,7 +148,7 @@ export class MemoryReadStore {
134
148
  throw err;
135
149
  }
136
150
  for (const entry of entries) {
137
- if (!entry.endsWith(".md")) continue;
151
+ if (isMacOsReplicationJunkBasename(entry) || !entry.endsWith(".md")) continue;
138
152
  const date = entry.slice(0, -3);
139
153
  if (!isValidTranscriptDate(date)) continue;
140
154
  days.push({ source, date });
@@ -170,6 +184,7 @@ export class MemoryReadStore {
170
184
  // in-flight dedup, so every abandoned recall used to start another
171
185
  // full walk of it (issue #2307).
172
186
  checkCorpusReadAbort(options);
187
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
173
188
  const fullPath = path.join(dir, entry.name);
174
189
  if (entry.isDirectory()) {
175
190
  await readDir(fullPath);
@@ -287,6 +302,7 @@ export class MemoryReadStore {
287
302
  checkCorpusReadAbort(options);
288
303
  // Never follow symlinked entries out of the store.
289
304
  if (entry.isSymbolicLink()) continue;
305
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
290
306
  const fullPath = path.join(dir, entry.name);
291
307
  if (entry.isDirectory()) {
292
308
  subdirs.push(fullPath);
@@ -500,6 +516,7 @@ export class MemoryReadStore {
500
516
  const entries = await readdir(dir, { withFileTypes: true });
501
517
  const subdirs: string[] = [];
502
518
  for (const entry of entries) {
519
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
503
520
  const fullPath = path.join(dir, entry.name);
504
521
  if (entry.isDirectory()) {
505
522
  subdirs.push(fullPath);
@@ -536,6 +553,15 @@ export class MemoryReadStore {
536
553
  async readMemoryByPath(filePath: string): Promise<MemoryFile | null> {
537
554
  try {
538
555
  const raw = await readMaybeEncryptedFile(filePath, this.deps._secureStoreKey, this.deps.baseDir);
556
+ // Entity bodies with text but no name heading stay out of recall,
557
+ // including contextual QMD hits. An empty body still resolves through
558
+ // frontmatter and the canonical filename. A missing type line is still
559
+ // an entity. QMD query behavior is unchanged. Classification is
560
+ // relative to this store root: an absolute path that merely contains
561
+ // an `entities` segment is still an ordinary fact.
562
+ if (isStoreEntityMarkdown(this.deps.baseDir, filePath) && isPopulatedUnnamedEntityRecord(raw)) {
563
+ return null;
564
+ }
539
565
  // Note: the outer catch intentionally swallows most errors (ENOENT etc.)
540
566
  // but SecureStoreLockedError must propagate — see re-throw below.
541
567
  const parsed = parseFrontmatter(raw);
@@ -555,8 +581,7 @@ export class MemoryReadStore {
555
581
  // YAML frontmatter. Build a synthetic MemoryFile so entity files returned by
556
582
  // the direct retrieval agent participate in boostSearchResults and last-recall
557
583
  // tracking rather than being silently dropped.
558
- const normalizedPath = filePath.split(path.sep).join("/");
559
- if (normalizedPath.includes("/entities/") && filePath.endsWith(".md")) {
584
+ if (isStoreEntityMarkdown(this.deps.baseDir, filePath)) {
560
585
  const entity = parseEntityFile(raw, this.deps.entitySchemas);
561
586
  if (!entity.name) return null;
562
587
  const nameWithoutExt = path.basename(filePath, ".md");
@@ -859,7 +884,7 @@ export class MemoryReadStore {
859
884
  const files = await readdir(this.deps.questionsDir);
860
885
  const questions = [];
861
886
  for (const file of files) {
862
- if (!file.endsWith(".md")) continue;
887
+ if (isMacOsReplicationJunkBasename(file) || !file.endsWith(".md")) continue;
863
888
  const filePath = path.join(this.deps.questionsDir, file);
864
889
  const raw = await readMaybeEncryptedFile(filePath, this.deps._secureStoreKey, this.deps.baseDir);
865
890
  const parsed = this.deps.parseQuestionFile(raw, filePath);
@@ -5,6 +5,7 @@ import path from "node:path";
5
5
  import { stripAttributesSuffix } from "../structured-attributes.js";
6
6
  import type { MemoryFile } from "../types.js";
7
7
  import { isErrnoCode } from "../utils/errno.js";
8
+ import { isMacOsReplicationJunkBasename } from "../utils/macos-replication-junk.js";
8
9
 
9
10
  export interface SupersessionAuditLookup {
10
11
  correctionsDir: string;
@@ -27,6 +28,7 @@ export async function hasSupersessionAudit(
27
28
  }
28
29
 
29
30
  for (const entry of entries) {
31
+ if (isMacOsReplicationJunkBasename(entry.name)) continue;
30
32
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
31
33
  const memory = await lookup.readMemoryByPath(path.join(lookup.correctionsDir, entry.name));
32
34
  if (
package/src/storage.ts CHANGED
@@ -65,6 +65,7 @@ import { readEntityAliasConfigSync } from "./storage/entity-alias-config.js";
65
65
  import { assertSafeEntityId } from "./storage/entity-id-safety.js";
66
66
  export { normalizeEntityName } from "./entity-id-normalization.js";
67
67
  import { isErrnoCode } from "./utils/errno.js";
68
+ import { isMacOsReplicationJunkBasename } from "./utils/macos-replication-junk.js";
68
69
  import { getCategoryDir, categoryDirName } from "./utils/category-dir.js";
69
70
  import { decodeYamlScalar } from "./utils/yaml-scalar.js";
70
71
  import { qmdCollectionPathParts, qmdResultPathCandidates } from "./orchestration/qmd-result-resolver.js";
@@ -4882,7 +4883,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
4882
4883
 
4883
4884
  const readDir = async (dir: string) => {
4884
4885
  try {
4885
- const entries = await readdir(dir, { withFileTypes: true });
4886
+ const entries = (await readdir(dir, { withFileTypes: true })).filter((e) => !isMacOsReplicationJunkBasename(e.name));
4886
4887
  for (const entry of entries) {
4887
4888
  checkCorpusReadAbort(options);
4888
4889
  const fullPath = path.join(dir, entry.name);
@@ -7133,7 +7134,7 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
7133
7134
  const summaries: MemorySummary[] = [];
7134
7135
 
7135
7136
  for (const file of files) {
7136
- if (!file.endsWith(".json")) continue;
7137
+ if (isMacOsReplicationJunkBasename(file) || !file.endsWith(".json")) continue;
7137
7138
  const filePath = path.join(this.summariesDir, file);
7138
7139
  const raw = await this.readStorageSecureFile(filePath);
7139
7140
  summaries.push(JSON.parse(raw) as MemorySummary);