shieldcortex 4.38.0 → 4.39.0

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 (241) hide show
  1. package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
  2. package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
  3. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
  4. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
  5. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
  11. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +1 -1
  12. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  13. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  14. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.html +1 -1
  19. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.rsc +1 -1
  20. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin/__PAGE__.segment.rsc +1 -1
  21. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk/admin.segment.rsc +1 -1
  22. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  23. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_full.segment.rsc +1 -1
  24. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_head.segment.rsc +1 -1
  25. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_index.segment.rsc +1 -1
  26. package/dashboard/.next/standalone/dashboard/.next/server/app/admin.segments/_tree.segment.rsc +1 -1
  27. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.html +1 -1
  28. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.rsc +1 -1
  29. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud/__PAGE__.segment.rsc +1 -1
  30. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk/cloud.segment.rsc +1 -1
  31. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  32. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_full.segment.rsc +1 -1
  33. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_head.segment.rsc +1 -1
  34. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_index.segment.rsc +1 -1
  35. package/dashboard/.next/standalone/dashboard/.next/server/app/cloud.segments/_tree.segment.rsc +1 -1
  36. package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
  37. package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +1 -1
  38. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  39. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +1 -1
  40. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
  41. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +1 -1
  42. package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  43. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.html +1 -1
  44. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.rsc +1 -1
  45. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture/__PAGE__.segment.rsc +1 -1
  46. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory/capture.segment.rsc +1 -1
  47. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  48. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  49. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_full.segment.rsc +1 -1
  50. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_head.segment.rsc +1 -1
  51. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_index.segment.rsc +1 -1
  52. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/capture.segments/_tree.segment.rsc +1 -1
  53. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.html +1 -1
  54. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.rsc +1 -1
  55. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph/__PAGE__.segment.rsc +1 -1
  56. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory/graph.segment.rsc +1 -1
  57. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  58. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  59. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_full.segment.rsc +1 -1
  60. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_head.segment.rsc +1 -1
  61. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_index.segment.rsc +1 -1
  62. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/graph.segments/_tree.segment.rsc +1 -1
  63. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.html +1 -1
  64. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.rsc +1 -1
  65. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall/__PAGE__.segment.rsc +1 -1
  66. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory/recall.segment.rsc +1 -1
  67. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  68. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  69. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_full.segment.rsc +1 -1
  70. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_head.segment.rsc +1 -1
  71. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_index.segment.rsc +1 -1
  72. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/recall.segments/_tree.segment.rsc +1 -1
  73. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.html +1 -1
  74. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.rsc +1 -1
  75. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay/__PAGE__.segment.rsc +1 -1
  76. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory/replay.segment.rsc +1 -1
  77. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  78. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  79. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_full.segment.rsc +1 -1
  80. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_head.segment.rsc +1 -1
  81. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_index.segment.rsc +1 -1
  82. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/replay.segments/_tree.segment.rsc +1 -1
  83. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.html +1 -1
  84. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.rsc +1 -1
  85. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review/__PAGE__.segment.rsc +1 -1
  86. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory/review.segment.rsc +1 -1
  87. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  88. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  89. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_full.segment.rsc +1 -1
  90. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_head.segment.rsc +1 -1
  91. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_index.segment.rsc +1 -1
  92. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/review.segments/_tree.segment.rsc +1 -1
  93. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.html +1 -1
  94. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.rsc +1 -1
  95. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline/__PAGE__.segment.rsc +1 -1
  96. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory/timeline.segment.rsc +1 -1
  97. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  98. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  99. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_full.segment.rsc +1 -1
  100. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_head.segment.rsc +1 -1
  101. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_index.segment.rsc +1 -1
  102. package/dashboard/.next/standalone/dashboard/.next/server/app/memory/timeline.segments/_tree.segment.rsc +1 -1
  103. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.html +1 -1
  104. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.rsc +1 -1
  105. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory/__PAGE__.segment.rsc +1 -1
  106. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk/memory.segment.rsc +1 -1
  107. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  108. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_full.segment.rsc +1 -1
  109. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_head.segment.rsc +1 -1
  110. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_index.segment.rsc +1 -1
  111. package/dashboard/.next/standalone/dashboard/.next/server/app/memory.segments/_tree.segment.rsc +1 -1
  112. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.html +1 -1
  113. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.rsc +1 -1
  114. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview/__PAGE__.segment.rsc +1 -1
  115. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk/overview.segment.rsc +1 -1
  116. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  117. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_full.segment.rsc +1 -1
  118. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_head.segment.rsc +1 -1
  119. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_index.segment.rsc +1 -1
  120. package/dashboard/.next/standalone/dashboard/.next/server/app/overview.segments/_tree.segment.rsc +1 -1
  121. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.html +1 -1
  122. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.rsc +1 -1
  123. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit/__PAGE__.segment.rsc +1 -1
  124. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection/audit.segment.rsc +1 -1
  125. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  126. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  127. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_full.segment.rsc +1 -1
  128. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_head.segment.rsc +1 -1
  129. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_index.segment.rsc +1 -1
  130. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/audit.segments/_tree.segment.rsc +1 -1
  131. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.html +1 -1
  132. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.rsc +1 -1
  133. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts/__PAGE__.segment.rsc +1 -1
  134. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection/intercepts.segment.rsc +1 -1
  135. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  136. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  137. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_full.segment.rsc +1 -1
  138. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_head.segment.rsc +1 -1
  139. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_index.segment.rsc +1 -1
  140. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/intercepts.segments/_tree.segment.rsc +1 -1
  141. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.html +1 -1
  142. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.rsc +1 -1
  143. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome/__PAGE__.segment.rsc +1 -1
  144. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection/iron-dome.segment.rsc +1 -1
  145. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  146. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  147. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_full.segment.rsc +1 -1
  148. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_head.segment.rsc +1 -1
  149. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_index.segment.rsc +1 -1
  150. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/iron-dome.segments/_tree.segment.rsc +1 -1
  151. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.html +1 -1
  152. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.rsc +1 -1
  153. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies/__PAGE__.segment.rsc +1 -1
  154. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection/policies.segment.rsc +1 -1
  155. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  156. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  157. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_full.segment.rsc +1 -1
  158. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_head.segment.rsc +1 -1
  159. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_index.segment.rsc +1 -1
  160. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/policies.segments/_tree.segment.rsc +1 -1
  161. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.html +1 -1
  162. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.rsc +1 -1
  163. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine/__PAGE__.segment.rsc +1 -1
  164. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection/quarantine.segment.rsc +1 -1
  165. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  166. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  167. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_full.segment.rsc +1 -1
  168. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_head.segment.rsc +1 -1
  169. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_index.segment.rsc +1 -1
  170. package/dashboard/.next/standalone/dashboard/.next/server/app/protection/quarantine.segments/_tree.segment.rsc +1 -1
  171. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.html +1 -1
  172. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.rsc +1 -1
  173. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection/__PAGE__.segment.rsc +1 -1
  174. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk/protection.segment.rsc +1 -1
  175. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  176. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_full.segment.rsc +1 -1
  177. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_head.segment.rsc +1 -1
  178. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_index.segment.rsc +1 -1
  179. package/dashboard/.next/standalone/dashboard/.next/server/app/protection.segments/_tree.segment.rsc +1 -1
  180. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.html +1 -1
  181. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.rsc +1 -1
  182. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +1 -1
  183. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
  184. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  185. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  186. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  187. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  188. package/dashboard/.next/standalone/dashboard/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  189. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.html +1 -1
  190. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.rsc +1 -1
  191. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray/__PAGE__.segment.rsc +1 -1
  192. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain/xray.segment.rsc +1 -1
  193. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  194. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  195. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_full.segment.rsc +1 -1
  196. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_head.segment.rsc +1 -1
  197. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_index.segment.rsc +1 -1
  198. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain/xray.segments/_tree.segment.rsc +1 -1
  199. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.html +1 -1
  200. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.rsc +1 -1
  201. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain/__PAGE__.segment.rsc +1 -1
  202. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk/supply-chain.segment.rsc +1 -1
  203. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  204. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_full.segment.rsc +1 -1
  205. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_head.segment.rsc +1 -1
  206. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_index.segment.rsc +1 -1
  207. package/dashboard/.next/standalone/dashboard/.next/server/app/supply-chain.segments/_tree.segment.rsc +1 -1
  208. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.html +1 -1
  209. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.rsc +1 -1
  210. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray/__PAGE__.segment.rsc +1 -1
  211. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk/xray.segment.rsc +1 -1
  212. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/!KGRhc2hib2FyZCk.segment.rsc +1 -1
  213. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_full.segment.rsc +1 -1
  214. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_head.segment.rsc +1 -1
  215. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_index.segment.rsc +1 -1
  216. package/dashboard/.next/standalone/dashboard/.next/server/app/xray.segments/_tree.segment.rsc +1 -1
  217. package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
  218. package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
  219. package/dist/api/routes/admin.js +2 -0
  220. package/dist/api/routes/memories.js +5 -2
  221. package/dist/api/visualization-server.js +1 -0
  222. package/dist/database/inline-schema.js +6 -0
  223. package/dist/database/migrations.js +34 -0
  224. package/dist/database/schema.sql +6 -0
  225. package/dist/defence/audit/logger.js +4 -2
  226. package/dist/defence/audit/queries.js +4 -0
  227. package/dist/defence/audit/retention.js +22 -12
  228. package/dist/defence/iron-dome/audit.js +1 -0
  229. package/dist/defence/pipeline.js +4 -1
  230. package/dist/defence/tool-response-scanner.js +1 -0
  231. package/dist/defence/trust/resolve-tool-source.js +2 -0
  232. package/dist/defence/types.d.ts +10 -0
  233. package/dist/memory/lifecycle.js +5 -2
  234. package/dist/memory/store.d.ts +16 -2
  235. package/dist/memory/store.js +100 -6
  236. package/dist/tools/context.js +15 -1
  237. package/dist/tools/recall.js +9 -1
  238. package/package.json +1 -1
  239. /package/dashboard/.next/standalone/dashboard/.next/static/{PR51g0pS7Wp0zLzu2q6mQ → LfTY3B6uX3j7zNwqqgvPG}/_buildManifest.js +0 -0
  240. /package/dashboard/.next/standalone/dashboard/.next/static/{PR51g0pS7Wp0zLzu2q6mQ → LfTY3B6uX3j7zNwqqgvPG}/_clientMiddlewareManifest.json +0 -0
  241. /package/dashboard/.next/standalone/dashboard/.next/static/{PR51g0pS7Wp0zLzu2q6mQ → LfTY3B6uX3j7zNwqqgvPG}/_ssgManifest.js +0 -0
@@ -1,2 +1,2 @@
1
- <!DOCTYPE html><!--PR51g0pS7Wp0zLzu2q6mQ--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/d878b929b21636c4.js"/><script src="/_next/static/chunks/f70f563804550a9c.js" async=""></script><script src="/_next/static/chunks/43d761df92da7cb6.js" async=""></script><script src="/_next/static/chunks/e281719dbabcca1d.js" async=""></script><script src="/_next/static/chunks/9e56d1f8f4d7adcb.js" async=""></script><script src="/_next/static/chunks/turbopack-768a6a8b9db952e0.js" async=""></script><script src="/_next/static/chunks/102f894cc892994d.js" async=""></script><script src="/_next/static/chunks/417032eeb2cd875f.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
2
- @media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/d878b929b21636c4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57043,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n3:I[27657,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n4:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"ViewportBoundary\"]\n9:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"MetadataBoundary\"]\nb:I[30687,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"PR51g0pS7Wp0zLzu2q6mQ\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/102f894cc892994d.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/417032eeb2cd875f.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",\"$undefined\"],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
1
+ <!DOCTYPE html><!--LfTY3B6uX3j7zNwqqgvPG--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/d878b929b21636c4.js"/><script src="/_next/static/chunks/f70f563804550a9c.js" async=""></script><script src="/_next/static/chunks/43d761df92da7cb6.js" async=""></script><script src="/_next/static/chunks/e281719dbabcca1d.js" async=""></script><script src="/_next/static/chunks/9e56d1f8f4d7adcb.js" async=""></script><script src="/_next/static/chunks/turbopack-768a6a8b9db952e0.js" async=""></script><script src="/_next/static/chunks/102f894cc892994d.js" async=""></script><script src="/_next/static/chunks/417032eeb2cd875f.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
2
+ @media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/d878b929b21636c4.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[57043,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n3:I[27657,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n4:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"ViewportBoundary\"]\n9:I[56978,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"MetadataBoundary\"]\nb:I[30687,[\"/_next/static/chunks/102f894cc892994d.js\",\"/_next/static/chunks/417032eeb2cd875f.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"LfTY3B6uX3j7zNwqqgvPG\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/102f894cc892994d.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/417032eeb2cd875f.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",\"$undefined\"],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
@@ -99,6 +99,8 @@ export function registerAdminRoutes(app, deps) {
99
99
  options.source = req.query.source;
100
100
  if (req.query.firewallResult)
101
101
  options.firewallResult = req.query.firewallResult;
102
+ if (req.query.operation)
103
+ options.operation = req.query.operation;
102
104
  if (req.query.limit)
103
105
  options.limit = parseInt(req.query.limit, 10);
104
106
  if (req.query.project)
@@ -587,7 +587,10 @@ export function registerMemoryRoutes(app, deps) {
587
587
  }), (req, res) => {
588
588
  try {
589
589
  const id = parseInt(req.params.id, 10);
590
- const success = deleteMemory(id);
590
+ // Attribute the dashboard delete so it lands on the provenance ledger
591
+ // (the primary human-initiated delete — the source-less exemption is only
592
+ // for internal consolidate/merge machinery).
593
+ const success = deleteMemory(id, { type: 'api', identifier: `dashboard:memory-delete:${id}` });
591
594
  if (!success) {
592
595
  return res.status(404).json({ error: 'Memory not found' });
593
596
  }
@@ -1235,7 +1238,7 @@ export function registerMemoryRoutes(app, deps) {
1235
1238
  const db = getDatabase();
1236
1239
  db.prepare(`INSERT INTO quarantine (original_title, original_content, source_type, source_identifier, reason, project, status, created_at)
1237
1240
  VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)`).run(memory.title, memory.content, 'dashboard', 'brain-control', req.body.reason || 'Manually quarantined from Brain dashboard', memory.project || null, new Date().toISOString());
1238
- deleteMemory(id);
1241
+ deleteMemory(id, { type: 'api', identifier: `dashboard:quarantine-delete:${id}` });
1239
1242
  res.json({ success: true, quarantined: id });
1240
1243
  }
1241
1244
  catch (error) {
@@ -187,6 +187,7 @@ export function handleV1Scan(req, res) {
187
187
  trust_score: 0,
188
188
  sensitivity_level: 'RESTRICTED',
189
189
  firewall_result: 'BLOCK',
190
+ operation: 'write',
190
191
  anomaly_score: 0.5,
191
192
  threat_indicators: '["config_tampering"]',
192
193
  blocked_patterns: '[]',
@@ -36,6 +36,7 @@ export function getInlineSchema() {
36
36
  trust_score REAL DEFAULT 1.0,
37
37
  sensitivity_level TEXT DEFAULT 'INTERNAL',
38
38
  source TEXT DEFAULT 'user:direct',
39
+ content_hash TEXT,
39
40
  status TEXT DEFAULT 'active' CHECK(status IN ('active', 'archived', 'suppressed', 'canonical')),
40
41
  pinned INTEGER DEFAULT 0,
41
42
  reviewed_at TIMESTAMP,
@@ -84,6 +85,8 @@ export function getInlineSchema() {
84
85
  CREATE INDEX IF NOT EXISTS idx_memories_decayed_score ON memories(decayed_score DESC);
85
86
  CREATE INDEX IF NOT EXISTS idx_memories_last_accessed ON memories(last_accessed DESC);
86
87
  CREATE INDEX IF NOT EXISTS idx_memories_updated ON memories(updated_at DESC);
88
+ CREATE INDEX IF NOT EXISTS idx_memories_source ON memories(source);
89
+ CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash);
87
90
 
88
91
  CREATE TABLE IF NOT EXISTS sessions (
89
92
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -168,6 +171,8 @@ export function getInlineSchema() {
168
171
  trust_score REAL NOT NULL,
169
172
  sensitivity_level TEXT NOT NULL DEFAULT 'INTERNAL',
170
173
  firewall_result TEXT NOT NULL CHECK(firewall_result IN ('ALLOW', 'BLOCK', 'QUARANTINE')),
174
+ operation TEXT,
175
+ content_hash TEXT,
171
176
  anomaly_score REAL DEFAULT 0.0,
172
177
  threat_indicators TEXT DEFAULT '[]',
173
178
  blocked_patterns TEXT DEFAULT '[]',
@@ -182,6 +187,7 @@ export function getInlineSchema() {
182
187
  CREATE INDEX IF NOT EXISTS idx_audit_result ON defence_audit(firewall_result);
183
188
  CREATE INDEX IF NOT EXISTS idx_audit_source ON defence_audit(source_type);
184
189
  CREATE INDEX IF NOT EXISTS idx_audit_project ON defence_audit(project);
190
+ CREATE INDEX IF NOT EXISTS idx_audit_operation ON defence_audit(operation);
185
191
 
186
192
  -- Cumulative audit aggregate (single row, id=1) — retention rollup target.
187
193
  -- See schema.sql for the rationale.
@@ -750,4 +750,38 @@ export function runMigrations(database) {
750
750
  catch (err) {
751
751
  logIfUnexpectedDdlError(err, 'mcp_tool_hashes');
752
752
  }
753
+ // Migration: provenance ledger (v4.39.0) — add an `operation` discriminator
754
+ // (read/write/delete) and a `content_hash` (write-time tamper-evidence) to
755
+ // defence_audit, a `content_hash` to memories, and an index on memories.source
756
+ // for revoke-by-source. Existing rows keep operation/content_hash NULL (legacy,
757
+ // unclassifiable). Fresh installs get these from schema.sql / inline-schema.ts.
758
+ try {
759
+ const auditCols = database.prepare("PRAGMA table_info(defence_audit)").all();
760
+ if (auditCols.length > 0) {
761
+ const auditColNames = new Set(auditCols.map((c) => c.name));
762
+ if (!auditColNames.has('operation')) {
763
+ database.exec('ALTER TABLE defence_audit ADD COLUMN operation TEXT');
764
+ }
765
+ if (!auditColNames.has('content_hash')) {
766
+ database.exec('ALTER TABLE defence_audit ADD COLUMN content_hash TEXT');
767
+ }
768
+ }
769
+ }
770
+ catch (err) {
771
+ logIfUnexpectedDdlError(err, 'defence_audit provenance columns (operation, content_hash)');
772
+ }
773
+ if (!columnNames.has('content_hash')) {
774
+ database.exec('ALTER TABLE memories ADD COLUMN content_hash TEXT');
775
+ }
776
+ // Indexes in an unconditional, self-healing block: CREATE INDEX IF NOT EXISTS
777
+ // no-ops if the column already had its index, and back-fills it if the column
778
+ // exists without it (e.g. a column added by a prior partial run).
779
+ try {
780
+ database.exec('CREATE INDEX IF NOT EXISTS idx_audit_operation ON defence_audit(operation)');
781
+ database.exec('CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash)');
782
+ database.exec('CREATE INDEX IF NOT EXISTS idx_memories_source ON memories(source)');
783
+ }
784
+ catch (err) {
785
+ logIfUnexpectedDdlError(err, 'provenance ledger indexes (audit operation, memories content_hash/source)');
786
+ }
753
787
  }
@@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS memories (
24
24
  trust_score REAL DEFAULT 1.0,
25
25
  sensitivity_level TEXT DEFAULT 'INTERNAL',
26
26
  source TEXT DEFAULT 'user:direct',
27
+ content_hash TEXT,
27
28
  status TEXT DEFAULT 'active' CHECK(status IN ('active', 'archived', 'suppressed', 'canonical')),
28
29
  pinned INTEGER DEFAULT 0,
29
30
  reviewed_at TIMESTAMP,
@@ -85,6 +86,8 @@ CREATE INDEX IF NOT EXISTS idx_memories_updated ON memories(updated_at DESC);
85
86
  CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status);
86
87
  CREATE INDEX IF NOT EXISTS idx_memories_pinned ON memories(pinned DESC);
87
88
  CREATE INDEX IF NOT EXISTS idx_memories_source_kind ON memories(source_kind);
89
+ CREATE INDEX IF NOT EXISTS idx_memories_source ON memories(source);
90
+ CREATE INDEX IF NOT EXISTS idx_memories_content_hash ON memories(content_hash);
88
91
 
89
92
  -- Session tracking for consolidation
90
93
  CREATE TABLE IF NOT EXISTS sessions (
@@ -214,6 +217,8 @@ CREATE TABLE IF NOT EXISTS defence_audit (
214
217
  trust_score REAL NOT NULL,
215
218
  sensitivity_level TEXT NOT NULL DEFAULT 'INTERNAL',
216
219
  firewall_result TEXT NOT NULL CHECK(firewall_result IN ('ALLOW', 'BLOCK', 'QUARANTINE')),
220
+ operation TEXT, -- provenance ledger: 'read' | 'write' | 'delete' (NULL on legacy rows)
221
+ content_hash TEXT, -- SHA-256 of content at write time (tamper-evidence)
217
222
  anomaly_score REAL DEFAULT 0.0,
218
223
  threat_indicators TEXT DEFAULT '[]', -- JSON array of ThreatIndicator strings
219
224
  blocked_patterns TEXT DEFAULT '[]', -- JSON array of matched patterns
@@ -228,6 +233,7 @@ CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON defence_audit(timestamp DESC);
228
233
  CREATE INDEX IF NOT EXISTS idx_audit_result ON defence_audit(firewall_result);
229
234
  CREATE INDEX IF NOT EXISTS idx_audit_source ON defence_audit(source_type);
230
235
  CREATE INDEX IF NOT EXISTS idx_audit_project ON defence_audit(project);
236
+ CREATE INDEX IF NOT EXISTS idx_audit_operation ON defence_audit(operation);
231
237
 
232
238
  -- Defence: cumulative audit aggregate (single row, id=1). Retention purges roll
233
239
  -- the to-be-deleted rows' lifetime-stat contributions into this row BEFORE
@@ -15,12 +15,12 @@ export function logAudit(entry) {
15
15
  const stmt = db.prepare(`
16
16
  INSERT INTO defence_audit (
17
17
  memory_id, project, timestamp, source_type, source_identifier,
18
- trust_score, sensitivity_level, firewall_result,
18
+ trust_score, sensitivity_level, firewall_result, operation, content_hash,
19
19
  anomaly_score, threat_indicators, blocked_patterns,
20
20
  reason, fragmentation_score, pipeline_duration_ms
21
21
  ) VALUES (
22
22
  @memory_id, @project, @timestamp, @source_type, @source_identifier,
23
- @trust_score, @sensitivity_level, @firewall_result,
23
+ @trust_score, @sensitivity_level, @firewall_result, @operation, @content_hash,
24
24
  @anomaly_score, @threat_indicators, @blocked_patterns,
25
25
  @reason, @fragmentation_score, @pipeline_duration_ms
26
26
  )
@@ -34,6 +34,8 @@ export function logAudit(entry) {
34
34
  trust_score: entry.trust_score,
35
35
  sensitivity_level: entry.sensitivity_level,
36
36
  firewall_result: entry.firewall_result,
37
+ operation: entry.operation ?? null,
38
+ content_hash: entry.content_hash ?? null,
37
39
  anomaly_score: entry.anomaly_score ?? 0,
38
40
  threat_indicators: entry.threat_indicators ?? '[]',
39
41
  blocked_patterns: entry.blocked_patterns ?? '[]',
@@ -22,6 +22,10 @@ export function queryAuditLogs(options = {}) {
22
22
  conditions.push('da.firewall_result = @firewallResult');
23
23
  params.firewallResult = options.firewallResult;
24
24
  }
25
+ if (options.operation) {
26
+ conditions.push('da.operation = @operation');
27
+ params.operation = options.operation;
28
+ }
25
29
  if (options.source) {
26
30
  conditions.push('da.source_type = @source');
27
31
  params.source = options.source;
@@ -140,22 +140,32 @@ export function purgeAuditUnderSizePressure(options = {}) {
140
140
  const total = db.prepare('SELECT COUNT(*) AS c FROM defence_audit').get().c;
141
141
  if (total <= maxRows)
142
142
  return 0;
143
- // Trim down to the cap by deleting the OLDEST rows. Find the cutoff id: keep
144
- // the newest `maxRows` by timestamp, purge everything older.
145
- const cutoffRow = db.prepare(`
146
- SELECT timestamp FROM defence_audit
147
- ORDER BY timestamp DESC
148
- LIMIT 1 OFFSET ?
149
- `).get(maxRows);
150
- if (!cutoffRow)
143
+ const over = total - maxRows;
144
+ // Forensic-aware eviction: trim the `over` oldest rows, but evict
145
+ // LOW-VALUE provenance rows first (ALLOW reads/deletes — the high-volume,
146
+ // low-forensic-value entries) and only fall back to threat rows
147
+ // (BLOCK/QUARANTINE, or anything with threat_indicators) once the low-value
148
+ // rows are exhausted. Otherwise a flood of routine reads would push the
149
+ // oldest injection/credential-leak records out from under the row cap.
150
+ const ids = db.prepare(`
151
+ SELECT id FROM defence_audit
152
+ ORDER BY
153
+ CASE WHEN firewall_result = 'ALLOW'
154
+ AND operation IN ('read', 'delete')
155
+ AND (threat_indicators IS NULL OR threat_indicators IN ('', '[]'))
156
+ THEN 0 ELSE 1 END ASC,
157
+ timestamp ASC
158
+ LIMIT ?
159
+ `).all(over).map((r) => r.id);
160
+ if (ids.length === 0)
151
161
  return 0;
152
- const where = 'timestamp <= ?';
153
- const params = [cutoffRow.timestamp];
154
- const delta = computeDelta(where, params);
162
+ const placeholders = ids.map(() => '?').join(',');
163
+ const where = `id IN (${placeholders})`;
164
+ const delta = computeDelta(where, ids);
155
165
  if (delta.total_scans === 0)
156
166
  return 0;
157
167
  rollIntoAggregate(delta);
158
- const res = db.prepare(`DELETE FROM defence_audit WHERE ${where}`).run(...params);
168
+ const res = db.prepare(`DELETE FROM defence_audit WHERE ${where}`).run(...ids);
159
169
  return Number(res.changes ?? 0);
160
170
  })();
161
171
  }
@@ -19,6 +19,7 @@ export function logIronDomeAudit(event) {
19
19
  trust_score: 0,
20
20
  sensitivity_level: 'PUBLIC',
21
21
  firewall_result: event.allowed ? 'ALLOW' : 'BLOCK',
22
+ operation: null, // iron-dome kill-switch / defence event, not a memory read/write/delete
22
23
  anomaly_score: 0,
23
24
  threat_indicators: '[]',
24
25
  blocked_patterns: '[]',
@@ -11,7 +11,7 @@ import { analyzeFirewall } from './firewall/index.js';
11
11
  import { classifySensitivity } from './sensitivity/index.js';
12
12
  import { analyzeFragmentation } from './fragmentation/index.js';
13
13
  import { scanForCredentials } from './credential-leak/index.js';
14
- import { logAudit } from './audit/index.js';
14
+ import { logAudit, createContentHash } from './audit/index.js';
15
15
  import { persistEvent } from '../api/events.js';
16
16
  import { syncToCloud } from '../cloud/sync.js';
17
17
  import { syncQuarantineToCloud } from '../cloud/quarantine-sync.js';
@@ -202,6 +202,8 @@ export function runDefencePipeline(content, title, source, config, project) {
202
202
  trust_score: trust.score,
203
203
  sensitivity_level: sensitivity.level,
204
204
  firewall_result: firewall.result,
205
+ operation: 'write',
206
+ content_hash: createContentHash(content),
205
207
  anomaly_score: firewall.anomalyScore,
206
208
  threat_indicators: JSON.stringify(firewall.threatIndicators),
207
209
  blocked_patterns: JSON.stringify(firewall.blockedPatterns),
@@ -283,6 +285,7 @@ export function runDefencePipeline(content, title, source, config, project) {
283
285
  trust_score: 0,
284
286
  sensitivity_level: 'RESTRICTED',
285
287
  firewall_result: 'BLOCK',
288
+ operation: 'write',
286
289
  anomaly_score: 1.0,
287
290
  threat_indicators: '["pipeline_error"]',
288
291
  blocked_patterns: '[]',
@@ -250,6 +250,7 @@ export function scanToolResponse(toolName, content, mode) {
250
250
  trust_score: 0.5,
251
251
  sensitivity_level: (credentials.leaked || decodedCredentialLeak) ? 'CONFIDENTIAL' : 'PUBLIC',
252
252
  firewall_result: firewallResult,
253
+ operation: 'read',
253
254
  anomaly_score: anomalyScore,
254
255
  threat_indicators: JSON.stringify(threatIndicators),
255
256
  blocked_patterns: JSON.stringify(blockedPatterns),
@@ -33,6 +33,7 @@ export function resolveToolSource(declaredSource, options) {
33
33
  trust_score: ceilingScore,
34
34
  sensitivity_level: 'PUBLIC',
35
35
  firewall_result: 'BLOCK',
36
+ operation: null, // source-resolution meta-event, not a memory read/write/delete
36
37
  anomaly_score: 0,
37
38
  threat_indicators: JSON.stringify(['privilege_escalation']),
38
39
  blocked_patterns: '[]',
@@ -62,6 +63,7 @@ export function resolveToolSource(declaredSource, options) {
62
63
  trust_score: 0,
63
64
  sensitivity_level: 'PUBLIC',
64
65
  firewall_result: 'ALLOW',
66
+ operation: null, // source-resolution meta-event, not a memory read/write/delete
65
67
  anomaly_score: 0,
66
68
  threat_indicators: '[]',
67
69
  blocked_patterns: '[]',
@@ -129,6 +129,8 @@ export interface QuarantineEntry {
129
129
  expires_at: string | null;
130
130
  audit_id: number | null;
131
131
  }
132
+ /** Operation that produced an audit row (provenance ledger discriminator). */
133
+ export type AuditOperation = 'write' | 'read' | 'delete' | 'update';
132
134
  export interface AuditEntry {
133
135
  id: number;
134
136
  memory_id: number | null;
@@ -139,6 +141,14 @@ export interface AuditEntry {
139
141
  trust_score: number;
140
142
  sensitivity_level: string;
141
143
  firewall_result: FirewallResult;
144
+ /**
145
+ * The operation that produced this row. Required on every new emission so the
146
+ * ledger is queryable by read/write/delete; `null` only on legacy rows written
147
+ * before the provenance-ledger column existed.
148
+ */
149
+ operation: AuditOperation | null;
150
+ /** SHA-256 of the content at write time (tamper-evidence); null for read/delete rows. */
151
+ content_hash?: string | null;
142
152
  anomaly_score: number;
143
153
  threat_indicators: string;
144
154
  blocked_patterns: string;
@@ -27,6 +27,7 @@ import { jaccardSimilarity } from './similarity.js';
27
27
  import { emitMemoryAccessed, emitMemoryUpdated, persistEvent, } from '../api/events.js';
28
28
  import { createMemoryLink } from './links.js';
29
29
  import { runDefencePipeline } from '../defence/index.js';
30
+ import { createContentHash } from '../defence/audit/logger.js';
30
31
  // Enrichment text is recall-query / caller-derived (attacker-influenced); scan
31
32
  // it before persisting. Trust doesn't matter here (the row keeps its own) — we
32
33
  // only act on the firewall verdict, so a low-trust web source is fine.
@@ -207,13 +208,15 @@ export function enrichMemory(memoryId, newContext, contextType = 'access') {
207
208
  if (defenceResult.firewall.result !== 'ALLOW') {
208
209
  return { enriched: false, reason: `Enrichment blocked by defence: ${defenceResult.firewall.reason}` };
209
210
  }
210
- // Update memory
211
+ // Update memory (recompute content_hash — the integrity snapshot must track
212
+ // the enriched content, not the pre-enrichment original).
211
213
  db.prepare(`
212
214
  UPDATE memories
213
215
  SET content = ?,
216
+ content_hash = ?,
214
217
  last_accessed = CURRENT_TIMESTAMP
215
218
  WHERE id = ?
216
- `).run(newContent, memoryId);
219
+ `).run(newContent, createContentHash(newContent), memoryId);
217
220
  // Update cooldown timestamp
218
221
  enrichmentTimestamps.set(memoryId, now);
219
222
  // Emit update event for dashboard
@@ -5,7 +5,7 @@
5
5
  * Handles storage, retrieval, and management of memories.
6
6
  */
7
7
  import { Memory, MemoryInput, MemoryType, MemoryConfig } from './types.js';
8
- import type { DefenceSource } from '../defence/types.js';
8
+ import type { DefenceSource, AuditOperation } from '../defence/types.js';
9
9
  export declare const MAX_CONTENT_SIZE: number;
10
10
  export declare const UNATTRIBUTED_SOURCE: DefenceSource;
11
11
  /**
@@ -20,7 +20,21 @@ export declare function getLastTruncationInfo(): {
20
20
  * Convert database row to Memory object
21
21
  */
22
22
  export declare function rowToMemory(row: Record<string, unknown>): Memory;
23
- export declare function logAccessDenial(memoryId: number, source: DefenceSource, reason: string): void;
23
+ export declare function logAccessDenial(memoryId: number, source: DefenceSource, reason: string, operation?: AuditOperation): void;
24
+ /**
25
+ * Provenance ledger: record an ALLOWED read. Emitted ONCE per tool call (not per
26
+ * row) to keep the audit table bounded — recall returns up to 50 rows, so a
27
+ * per-row emit would flood it. memory_id carries the single id for single-target
28
+ * reads; the full id list (capped) goes in blocked_patterns for forensics.
29
+ */
30
+ export declare function logAllowedRead(source: DefenceSource, tool: string, memoryIds: number[], project?: string | null): void;
31
+ /**
32
+ * Provenance ledger: record an ALLOWED delete (one row per deleted memory).
33
+ * memory_id is NULL by design — the row is emitted after the DELETE, and the
34
+ * audit.memory_id FK is ON DELETE SET NULL, so a live reference can't survive.
35
+ * The deleted id is preserved in `reason` + `blocked_patterns` for forensics.
36
+ */
37
+ export declare function logAllowedDelete(memoryId: number, source: DefenceSource, project?: string | null): void;
24
38
  /**
25
39
  * Error thrown when memory creation is paused
26
40
  */
@@ -21,7 +21,7 @@ import { syncMemoryDeleteToCloud, syncMemoryUpsertToCloud } from '../cloud/memor
21
21
  import { isFeatureEnabled } from '../license/gate.js';
22
22
  import { checkAccess } from '../defence/trust/access-control.js';
23
23
  import { scoreSource } from '../defence/trust/source-scorer.js';
24
- import { logAudit } from '../defence/audit/logger.js';
24
+ import { logAudit, createContentHash } from '../defence/audit/logger.js';
25
25
  import { dispatchWebhook } from '../events/webhooks.js';
26
26
  import { safeJsonParse } from './fts.js';
27
27
  // Internal use of the link API. links.ts also imports from store.ts (getMemoryById,
@@ -230,7 +230,7 @@ function checkRateLimit(source) {
230
230
  // ── Read-Time Access Control ──
231
231
  // Exported because search-recall.ts also calls logAccessDenial inside its
232
232
  // post-search ACL filter (cycle artifact, not intended public API).
233
- export function logAccessDenial(memoryId, source, reason) {
233
+ export function logAccessDenial(memoryId, source, reason, operation = 'read') {
234
234
  const trust = scoreSource(source).score;
235
235
  logAudit({
236
236
  memory_id: memoryId,
@@ -241,6 +241,7 @@ export function logAccessDenial(memoryId, source, reason) {
241
241
  trust_score: trust,
242
242
  sensitivity_level: 'INTERNAL',
243
243
  firewall_result: 'BLOCK',
244
+ operation,
244
245
  anomaly_score: 0,
245
246
  threat_indicators: '[]',
246
247
  blocked_patterns: '[]',
@@ -249,6 +250,58 @@ export function logAccessDenial(memoryId, source, reason) {
249
250
  pipeline_duration_ms: 0,
250
251
  });
251
252
  }
253
+ /**
254
+ * Provenance ledger: record an ALLOWED read. Emitted ONCE per tool call (not per
255
+ * row) to keep the audit table bounded — recall returns up to 50 rows, so a
256
+ * per-row emit would flood it. memory_id carries the single id for single-target
257
+ * reads; the full id list (capped) goes in blocked_patterns for forensics.
258
+ */
259
+ export function logAllowedRead(source, tool, memoryIds, project) {
260
+ if (memoryIds.length === 0)
261
+ return;
262
+ logAudit({
263
+ memory_id: memoryIds.length === 1 ? memoryIds[0] : null,
264
+ project: project ?? null,
265
+ timestamp: new Date().toISOString(),
266
+ source_type: source.type,
267
+ source_identifier: source.identifier,
268
+ trust_score: scoreSource(source).score,
269
+ sensitivity_level: 'INTERNAL',
270
+ firewall_result: 'ALLOW',
271
+ operation: 'read',
272
+ anomaly_score: 0,
273
+ threat_indicators: '[]',
274
+ blocked_patterns: JSON.stringify(memoryIds.slice(0, 50)),
275
+ reason: `read ${memoryIds.length} memor${memoryIds.length === 1 ? 'y' : 'ies'} via ${tool}`,
276
+ fragmentation_score: null,
277
+ pipeline_duration_ms: null,
278
+ });
279
+ }
280
+ /**
281
+ * Provenance ledger: record an ALLOWED delete (one row per deleted memory).
282
+ * memory_id is NULL by design — the row is emitted after the DELETE, and the
283
+ * audit.memory_id FK is ON DELETE SET NULL, so a live reference can't survive.
284
+ * The deleted id is preserved in `reason` + `blocked_patterns` for forensics.
285
+ */
286
+ export function logAllowedDelete(memoryId, source, project) {
287
+ logAudit({
288
+ memory_id: null,
289
+ project: project ?? null,
290
+ timestamp: new Date().toISOString(),
291
+ source_type: source.type,
292
+ source_identifier: source.identifier,
293
+ trust_score: scoreSource(source).score,
294
+ sensitivity_level: 'INTERNAL',
295
+ firewall_result: 'ALLOW',
296
+ operation: 'delete',
297
+ anomaly_score: 0,
298
+ threat_indicators: '[]',
299
+ blocked_patterns: JSON.stringify([memoryId]),
300
+ reason: `deleted memory #${memoryId}`,
301
+ fragmentation_score: null,
302
+ pipeline_duration_ms: null,
303
+ });
304
+ }
252
305
  /**
253
306
  * Filter raw DB rows by access control before converting to Memory objects.
254
307
  * Returns only rows the source is allowed to read.
@@ -324,6 +377,7 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
324
377
  trust_score: scoreSource(source).score,
325
378
  sensitivity_level: 'INTERNAL',
326
379
  firewall_result: 'BLOCK',
380
+ operation: 'write',
327
381
  anomaly_score: 1.0,
328
382
  threat_indicators: JSON.stringify(['rate_limit_exceeded']),
329
383
  blocked_patterns: '[]',
@@ -413,8 +467,11 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
413
467
  // defenceResult is always set now (every write is scanned), so always stamp
414
468
  // the pipeline's real trust + sensitivity alongside the resolved source —
415
469
  // no source-less branch can default to trust 1.0 / unscanned INTERNAL.
416
- db.prepare(`UPDATE memories SET trust_score = ?, sensitivity_level = ?, source = ? WHERE id = ?`)
417
- .run(defenceResult.trust.score, defenceResult.sensitivity.level, sourceDetails.sourceValue, result.lastInsertRowid);
470
+ db.prepare(`UPDATE memories SET trust_score = ?, sensitivity_level = ?, source = ?, content_hash = ? WHERE id = ?`)
471
+ // content_hash = SHA-256 of the SUBMITTED content (a write-time provenance
472
+ // snapshot), matching the write-audit row in pipeline.ts. Consistent for
473
+ // >10KB memories too (where the STORED content is truncated).
474
+ .run(defenceResult.trust.score, defenceResult.sensitivity.level, sourceDetails.sourceValue, createContentHash(input.content), result.lastInsertRowid);
418
475
  return result.lastInsertRowid;
419
476
  })();
420
477
  const memory = getMemoryById(insertedId);
@@ -701,6 +758,14 @@ export function updateMemory(id, updates) {
701
758
  if (embeddedTextChanged) {
702
759
  fields.push('embedding = NULL');
703
760
  }
761
+ // STALENESS: content_hash is a write-time integrity snapshot. When content
762
+ // changes it must be recomputed in the SAME UPDATE — otherwise the stored hash
763
+ // refers to the old content and any tamper check false-positives on a
764
+ // legitimately-edited memory.
765
+ if (updates.content !== undefined) {
766
+ fields.push('content_hash = ?');
767
+ values.push(createContentHash(updates.content));
768
+ }
704
769
  if (fields.length === 0)
705
770
  return existing;
706
771
  values.push(id);
@@ -721,6 +786,28 @@ export function updateMemory(id, updates) {
721
786
  console.error('[shieldcortex] Entity extraction refresh failed:', e);
722
787
  }
723
788
  }
789
+ // Provenance ledger: a content/title change is an update-class mutation.
790
+ if (updates.content !== undefined || updates.title !== undefined) {
791
+ const changed = [updates.title !== undefined ? 'title' : null, updates.content !== undefined ? 'content' : null].filter(Boolean).join('+');
792
+ logAudit({
793
+ memory_id: id,
794
+ project: updatedMemory.project ?? null,
795
+ timestamp: new Date().toISOString(),
796
+ source_type: 'cli',
797
+ source_identifier: 'memory-update',
798
+ trust_score: updatedMemory.trustScore ?? 1,
799
+ sensitivity_level: updatedMemory.sensitivityLevel ?? 'INTERNAL',
800
+ firewall_result: 'ALLOW',
801
+ operation: 'update',
802
+ content_hash: updates.content !== undefined ? createContentHash(updates.content) : null,
803
+ anomaly_score: 0,
804
+ threat_indicators: '[]',
805
+ blocked_patterns: '[]',
806
+ reason: `updated memory #${id} (${changed})`,
807
+ fragmentation_score: null,
808
+ pipeline_duration_ms: null,
809
+ });
810
+ }
724
811
  // Emit event for real-time dashboard (in-process)
725
812
  emitMemoryUpdated(updatedMemory);
726
813
  // Persist event for cross-process IPC (MCP → Dashboard)
@@ -804,6 +891,7 @@ export function mergeMemories(keptId, removedId, options, source = { type: 'cli'
804
891
  db.prepare(`
805
892
  UPDATE memories
806
893
  SET content = ?,
894
+ content_hash = ?,
807
895
  tags = ?,
808
896
  salience = ?,
809
897
  project = ?,
@@ -822,7 +910,7 @@ export function mergeMemories(keptId, removedId, options, source = { type: 'cli'
822
910
  embedding = NULL,
823
911
  updated_at = CURRENT_TIMESTAMP
824
912
  WHERE id = ?
825
- `).run(mergedContent, JSON.stringify(mergedTags), mergedSalience, mergedProject, JSON.stringify(mergedMetadata), mergedScope, mergedTransferable ? 1 : 0, mergedStatus, mergedPinned ? 1 : 0, mergedReviewedBy, new Date().toISOString(), mergedTrustScore, mergedSensitivity, mergedCloudExcluded ? 1 : 0, mergedAccessCount, mergedLastAccessed, kept.id);
913
+ `).run(mergedContent, createContentHash(mergedContent), JSON.stringify(mergedTags), mergedSalience, mergedProject, JSON.stringify(mergedMetadata), mergedScope, mergedTransferable ? 1 : 0, mergedStatus, mergedPinned ? 1 : 0, mergedReviewedBy, new Date().toISOString(), mergedTrustScore, mergedSensitivity, mergedCloudExcluded ? 1 : 0, mergedAccessCount, mergedLastAccessed, kept.id);
826
914
  const updatedMemory = getMemoryById(kept.id);
827
915
  try {
828
916
  const extraction = extractFromMemory(updatedMemory.title, updatedMemory.content, updatedMemory.category);
@@ -856,7 +944,7 @@ export function deleteMemory(id, source) {
856
944
  if (row) {
857
945
  const policy = checkAccess({ id: row.id, source: row.source, sensitivity_level: row.sensitivity_level }, source, 'delete');
858
946
  if (!policy.canDelete) {
859
- logAccessDenial(id, source, policy.reason);
947
+ logAccessDenial(id, source, policy.reason, 'delete');
860
948
  return false;
861
949
  }
862
950
  }
@@ -874,6 +962,12 @@ export function deleteMemory(id, source) {
874
962
  const result = db.prepare('DELETE FROM memories WHERE id = ?').run(id);
875
963
  // Emit event for real-time dashboard (in-process)
876
964
  if (result.changes > 0 && memory) {
965
+ // Provenance ledger: record the allowed delete (one row per memory) when the
966
+ // caller is attributed. Internal source-less deletes (merge/consolidation)
967
+ // are machinery, not user actions, so they're not audited here.
968
+ if (source) {
969
+ logAllowedDelete(id, source, memory.project ?? null);
970
+ }
877
971
  if (isFeatureEnabled('cloud_sync')) {
878
972
  syncMemoryDeleteToCloud(memory);
879
973
  syncGraphDeleteForMemoryToCloud(memory);