hex-audit 0.6.2 → 0.7.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 (333) hide show
  1. package/DEMO.md +13 -0
  2. package/README.md +60 -6
  3. package/dashboard/.next/BUILD_ID +1 -1
  4. package/dashboard/.next/app-build-manifest.json +100 -89
  5. package/dashboard/.next/app-path-routes-manifest.json +1 -1
  6. package/dashboard/.next/build-manifest.json +14 -14
  7. package/dashboard/.next/next-server.js.nft.json +1 -1
  8. package/dashboard/.next/prerender-manifest.js +1 -1
  9. package/dashboard/.next/prerender-manifest.json +1 -1
  10. package/dashboard/.next/react-loadable-manifest.json +118 -118
  11. package/dashboard/.next/routes-manifest.json +1 -1
  12. package/dashboard/.next/server/app/_not-found/page.js +1 -1
  13. package/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/dashboard/.next/server/app/access/page.js +1 -1
  15. package/dashboard/.next/server/app/access/page.js.nft.json +1 -1
  16. package/dashboard/.next/server/app/access/page_client-reference-manifest.js +1 -1
  17. package/dashboard/.next/server/app/calls/page.js +1 -1
  18. package/dashboard/.next/server/app/calls/page.js.nft.json +1 -1
  19. package/dashboard/.next/server/app/calls/page_client-reference-manifest.js +1 -1
  20. package/dashboard/.next/server/app/changes/page.js +20 -0
  21. package/dashboard/.next/server/app/changes/page.js.nft.json +1 -0
  22. package/dashboard/.next/server/app/changes/page_client-reference-manifest.js +1 -0
  23. package/dashboard/.next/server/app/conformance/page.js +1 -1
  24. package/dashboard/.next/server/app/conformance/page_client-reference-manifest.js +1 -1
  25. package/dashboard/.next/server/app/diagram/page.js +1 -1
  26. package/dashboard/.next/server/app/diagram/page_client-reference-manifest.js +1 -1
  27. package/dashboard/.next/server/app/flows/page.js +1 -1
  28. package/dashboard/.next/server/app/flows/page_client-reference-manifest.js +1 -1
  29. package/dashboard/.next/server/app/functions/page.js +1 -1
  30. package/dashboard/.next/server/app/functions/page.js.nft.json +1 -1
  31. package/dashboard/.next/server/app/functions/page_client-reference-manifest.js +1 -1
  32. package/dashboard/.next/server/app/issues/page.js +6 -6
  33. package/dashboard/.next/server/app/issues/page_client-reference-manifest.js +1 -1
  34. package/dashboard/.next/server/app/notes/page.js +3 -3
  35. package/dashboard/.next/server/app/notes/page_client-reference-manifest.js +1 -1
  36. package/dashboard/.next/server/app/page.js +2 -2
  37. package/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
  38. package/dashboard/.next/server/app/progress/page.js +1 -1
  39. package/dashboard/.next/server/app/progress/page_client-reference-manifest.js +1 -1
  40. package/dashboard/.next/server/app/report/page.js +1 -1
  41. package/dashboard/.next/server/app/report/page_client-reference-manifest.js +1 -1
  42. package/dashboard/.next/server/app/stats/page.js +1 -1
  43. package/dashboard/.next/server/app/stats/page.js.nft.json +1 -1
  44. package/dashboard/.next/server/app/stats/page_client-reference-manifest.js +1 -1
  45. package/dashboard/.next/server/app-paths-manifest.json +9 -8
  46. package/dashboard/.next/server/chunks/42.js +1 -1
  47. package/dashboard/.next/server/chunks/530.js +1 -1
  48. package/dashboard/.next/server/chunks/649.js +1 -1
  49. package/dashboard/.next/server/chunks/939.js +1 -0
  50. package/dashboard/.next/server/functions-config-manifest.json +1 -1
  51. package/dashboard/.next/server/middleware-build-manifest.js +1 -1
  52. package/dashboard/.next/server/middleware-react-loadable-manifest.js +1 -1
  53. package/dashboard/.next/server/next-font-manifest.js +1 -1
  54. package/dashboard/.next/server/next-font-manifest.json +1 -1
  55. package/dashboard/.next/server/pages/500.html +1 -1
  56. package/dashboard/.next/server/pages-manifest.json +1 -1
  57. package/dashboard/.next/server/server-reference-manifest.js +1 -1
  58. package/dashboard/.next/server/server-reference-manifest.json +1 -1
  59. package/dashboard/.next/static/chunks/{1.8868c4d131111be7.js → 1.a666047ea18866fb.js} +2 -2
  60. package/dashboard/.next/static/chunks/1015.39008440ab15e196.js +226 -0
  61. package/dashboard/.next/static/chunks/1151.497fa63c5b9eba52.js +1 -0
  62. package/dashboard/.next/static/chunks/1199.f30cbfa151e56076.js +148 -0
  63. package/dashboard/.next/static/chunks/1375.64c20f1064a38a10.js +43 -0
  64. package/dashboard/.next/static/chunks/1799.8dc56017eede704e.js +9 -0
  65. package/dashboard/.next/static/chunks/20154aaa.e87f69fe10483f8b.js +1 -0
  66. package/dashboard/.next/static/chunks/2077.5603adeb156c7d10.js +1 -0
  67. package/dashboard/.next/static/chunks/2166.9f6592b9399eadd8.js +215 -0
  68. package/dashboard/.next/static/chunks/{2291.85a70cb0c228157b.js → 2291.584b42ccad079b99.js} +1 -1
  69. package/dashboard/.next/static/chunks/2325.7decd077edfb81d9.js +24 -0
  70. package/dashboard/.next/static/chunks/{2383.62c035a052272594.js → 2383.ca81f980ce6528a4.js} +1 -1
  71. package/dashboard/.next/static/chunks/2694.7dfa5fef28851903.js +1 -0
  72. package/dashboard/.next/static/chunks/275.38af87389c1d33d7.js +34 -0
  73. package/dashboard/.next/static/chunks/2781.fba46046dbf2693b.js +93 -0
  74. package/dashboard/.next/static/chunks/2805.35b4cd8a94978aaf.js +1 -0
  75. package/dashboard/.next/static/chunks/{2879.51436986f93981d9.js → 2879.74d65e33e60505ee.js} +1 -1
  76. package/dashboard/.next/static/chunks/3017.4a5312e3c20a173f.js +1 -0
  77. package/dashboard/.next/static/chunks/3205-47d09be47325709f.js +2 -0
  78. package/dashboard/.next/static/chunks/3236.eac9855778a54518.js +1 -0
  79. package/dashboard/.next/static/chunks/3480.853a445a3784642a.js +1 -0
  80. package/dashboard/.next/static/chunks/3626.c5dacee11c8fbc4d.js +64 -0
  81. package/dashboard/.next/static/chunks/3865.5e6d2d501380e03b.js +90 -0
  82. package/dashboard/.next/static/chunks/3887.073cece834a4eae2.js +1 -0
  83. package/dashboard/.next/static/chunks/3924-88d849290406ee6f.js +1 -0
  84. package/dashboard/.next/static/chunks/3948.74201b9f0672234d.js +287 -0
  85. package/dashboard/.next/static/chunks/4728.e69372b5e5b61b8d.js +24 -0
  86. package/dashboard/.next/static/chunks/4787.821a6ad2816cdc60.js +23 -0
  87. package/dashboard/.next/static/chunks/5060.47402abc10273699.js +1 -0
  88. package/dashboard/.next/static/chunks/5284.334c7c0587d5d47a.js +1 -0
  89. package/dashboard/.next/static/chunks/5715.e16b1230cc4b4652.js +115 -0
  90. package/dashboard/.next/static/chunks/6014.641a2c53ba506241.js +104 -0
  91. package/dashboard/.next/static/chunks/6024.f099c15f75aa6722.js +79 -0
  92. package/dashboard/.next/static/chunks/{6052.033a6f1013c666eb.js → 6052.3001318955e5b36c.js} +2 -2
  93. package/dashboard/.next/static/chunks/6177.a01cf0a03734cf09.js +1 -0
  94. package/dashboard/.next/static/chunks/618f8807-69fc7bb97c2b87c1.js +1 -0
  95. package/dashboard/.next/static/chunks/6434.f560693253fea8de.js +1 -0
  96. package/dashboard/.next/static/chunks/6468.976d89ba133185f1.js +77 -0
  97. package/dashboard/.next/static/chunks/6540.6f3c4f2c6877ed89.js +1 -0
  98. package/dashboard/.next/static/chunks/6549.e3c4c1766cff1449.js +1 -0
  99. package/dashboard/.next/static/chunks/690f35d0.ab57e02a04c7e9e0.js +119 -0
  100. package/dashboard/.next/static/chunks/{7020.831e16e26d91abc1.js → 7020.b718b1b9cea36e60.js} +2 -2
  101. package/dashboard/.next/static/chunks/7397-37adf76cad543297.js +1 -0
  102. package/dashboard/.next/static/chunks/7498-d1814d68ba346d13.js +1 -0
  103. package/dashboard/.next/static/chunks/7802.f0134c792fccd382.js +80 -0
  104. package/dashboard/.next/static/chunks/7973.e34032723285a616.js +79 -0
  105. package/dashboard/.next/static/chunks/{7a04ac15.1c6cea694301806c.js → 7a04ac15.e49de94ece135900.js} +1 -1
  106. package/dashboard/.next/static/chunks/8216.1138ec313908a708.js +5 -0
  107. package/dashboard/.next/static/chunks/{8233babc.780b8e272eda298f.js → 8233babc.09872dcb3ff44064.js} +1 -1
  108. package/dashboard/.next/static/chunks/{8452-e616b5f43bceb95f.js → 8452-6d77fa353402422c.js} +2 -2
  109. package/dashboard/.next/static/chunks/8645.98a43217d406500e.js +1 -0
  110. package/dashboard/.next/static/chunks/8928-fc049decdfbdaa6d.js +1 -0
  111. package/dashboard/.next/static/chunks/9173.a7160f7d0b685fa7.js +1 -0
  112. package/dashboard/.next/static/chunks/9178.998a8c49996de8e4.js +1 -0
  113. package/dashboard/.next/static/chunks/9466.a914ce0de7d3bb84.js +1 -0
  114. package/dashboard/.next/static/chunks/9660.b1c8deae2c449d14.js +1 -0
  115. package/dashboard/.next/static/chunks/{9717.6cf5c8c89403b651.js → 9717.bba51b78ebd8fd29.js} +1 -1
  116. package/dashboard/.next/static/chunks/9720.d63a0696776bcc60.js +1 -0
  117. package/dashboard/.next/static/chunks/9811.2993c4cbd28e8d1b.js +1 -0
  118. package/dashboard/.next/static/chunks/app/_not-found/page-c299b935209993df.js +1 -0
  119. package/dashboard/.next/static/chunks/app/access/page-f8403cbdfc1c176b.js +1 -0
  120. package/dashboard/.next/static/chunks/app/calls/page-41f20d01e12382ef.js +1 -0
  121. package/dashboard/.next/static/chunks/app/changes/page-82bf8b6f48cdc506.js +1 -0
  122. package/dashboard/.next/static/chunks/app/conformance/page-6bb8e3b372e38098.js +1 -0
  123. package/dashboard/.next/static/chunks/app/diagram/page-469cd7a6f183efba.js +1 -0
  124. package/dashboard/.next/static/chunks/app/flows/page-7872dd9141ba0b07.js +1 -0
  125. package/dashboard/.next/static/chunks/app/functions/page-5847bcb77a8e7edf.js +1 -0
  126. package/dashboard/.next/static/chunks/app/issues/page-1ffc64fe40439002.js +1 -0
  127. package/dashboard/.next/static/chunks/app/layout-6c6d2a0fd7c989d3.js +1 -0
  128. package/dashboard/.next/static/chunks/app/notes/page-8bcaa52304500098.js +1 -0
  129. package/dashboard/.next/static/chunks/app/page-d63800ddb072b77b.js +1 -0
  130. package/dashboard/.next/static/chunks/app/progress/page-e26554f655a62eef.js +1 -0
  131. package/dashboard/.next/static/chunks/app/report/page-18c04fb2f193b020.js +1 -0
  132. package/dashboard/.next/static/chunks/app/stats/page-67ff59fd69bed651.js +1 -0
  133. package/dashboard/.next/static/chunks/{b7167ec1.7afbab6f609e3326.js → b7167ec1.708a3d61698ca2e6.js} +1 -1
  134. package/dashboard/.next/static/chunks/c7ea4e13.3073a2f551aa5ac8.js +1 -0
  135. package/dashboard/.next/static/chunks/framework-a117d81bf1b91f9a.js +33 -0
  136. package/dashboard/.next/static/chunks/main-app-5662c64b50ba40d1.js +1 -0
  137. package/dashboard/.next/static/chunks/main-cc3a889b25e9aa68.js +1 -0
  138. package/dashboard/.next/static/chunks/pages/_app-308fef0bf9b328f2.js +1 -0
  139. package/dashboard/.next/static/chunks/pages/_error-c91b5eabd7ac9382.js +1 -0
  140. package/dashboard/.next/static/chunks/webpack-4de0e79bdd6a0418.js +1 -0
  141. package/dashboard/.next/static/css/1112cea2260b3926.css +3 -0
  142. package/dashboard/.next/static/media/39f449c8730c2295-s.woff2 +0 -0
  143. package/dashboard/.next/static/media/86f65e8637cc94e3-s.woff2 +0 -0
  144. package/dashboard/.next/static/media/8760c4774489e4ba-s.p.woff2 +0 -0
  145. package/dashboard/.next/static/media/9fabb9c65b63d798-s.woff2 +0 -0
  146. package/dashboard/.next/static/media/a1f87af3f44fadbb-s.woff2 +0 -0
  147. package/dashboard/.next/static/media/f9e1dbe9676d9bb6-s.woff2 +0 -0
  148. package/dashboard/.next/static/z5XBev05xDAkDrxWxAjNu/_buildManifest.js +1 -0
  149. package/dashboard/app/changes/ChangesClient.tsx +464 -0
  150. package/dashboard/app/changes/page.tsx +36 -0
  151. package/dashboard/app/issues/IssuesBoardClient.tsx +11 -1
  152. package/dashboard/app/layout.tsx +13 -1
  153. package/dashboard/app/notes/NotesClient.tsx +5 -0
  154. package/dashboard/app/page.tsx +42 -0
  155. package/dashboard/components/DashboardLayout.tsx +43 -18
  156. package/dist/analysis/code-model.d.ts +113 -0
  157. package/dist/analysis/code-model.d.ts.map +1 -0
  158. package/dist/analysis/code-model.js +529 -0
  159. package/dist/analysis/code-model.js.map +1 -0
  160. package/dist/analysis/diff.d.ts +64 -0
  161. package/dist/analysis/diff.d.ts.map +1 -0
  162. package/dist/analysis/diff.js +644 -0
  163. package/dist/analysis/diff.js.map +1 -0
  164. package/dist/commands/analyze.d.ts.map +1 -1
  165. package/dist/commands/analyze.js +18 -2
  166. package/dist/commands/analyze.js.map +1 -1
  167. package/dist/commands/diff.d.ts +26 -0
  168. package/dist/commands/diff.d.ts.map +1 -0
  169. package/dist/commands/diff.js +218 -0
  170. package/dist/commands/diff.js.map +1 -0
  171. package/dist/commands/init.d.ts.map +1 -1
  172. package/dist/commands/init.js +72 -9
  173. package/dist/commands/init.js.map +1 -1
  174. package/dist/commands/issue.d.ts.map +1 -1
  175. package/dist/commands/issue.js +4 -4
  176. package/dist/commands/issue.js.map +1 -1
  177. package/dist/commands/note.d.ts.map +1 -1
  178. package/dist/commands/note.js +30 -2
  179. package/dist/commands/note.js.map +1 -1
  180. package/dist/core/config.d.ts +9 -0
  181. package/dist/core/config.d.ts.map +1 -1
  182. package/dist/core/config.js +18 -0
  183. package/dist/core/config.js.map +1 -1
  184. package/dist/core/errors.d.ts +1 -1
  185. package/dist/core/errors.d.ts.map +1 -1
  186. package/dist/core/errors.js +16 -0
  187. package/dist/core/errors.js.map +1 -1
  188. package/dist/core/git.d.ts +24 -0
  189. package/dist/core/git.d.ts.map +1 -0
  190. package/dist/core/git.js +115 -0
  191. package/dist/core/git.js.map +1 -0
  192. package/dist/core/issues.d.ts +4 -2
  193. package/dist/core/issues.d.ts.map +1 -1
  194. package/dist/core/issues.js +67 -28
  195. package/dist/core/issues.js.map +1 -1
  196. package/dist/core/notes.d.ts +25 -1
  197. package/dist/core/notes.d.ts.map +1 -1
  198. package/dist/core/notes.js +34 -2
  199. package/dist/core/notes.js.map +1 -1
  200. package/dist/core/schema.d.ts +750 -53
  201. package/dist/core/schema.d.ts.map +1 -1
  202. package/dist/core/schema.js +153 -1
  203. package/dist/core/schema.js.map +1 -1
  204. package/dist/core/skills.d.ts +10 -4
  205. package/dist/core/skills.d.ts.map +1 -1
  206. package/dist/core/skills.js +100 -37
  207. package/dist/core/skills.js.map +1 -1
  208. package/dist/index.js +2 -0
  209. package/dist/index.js.map +1 -1
  210. package/dist/skills/ai-audit/LICENSE +21 -0
  211. package/dist/skills/ai-audit/SKILL.md +476 -0
  212. package/dist/skills/ai-audit/UPSTREAM.md +46 -0
  213. package/dist/skills/ai-audit/references/agent-prompts.md +133 -0
  214. package/dist/skills/ai-audit/references/assemble.sh +357 -0
  215. package/dist/skills/ai-audit/references/dedup-and-assembly.md +420 -0
  216. package/dist/skills/ai-audit/references/hacking-agents/access-control-agent.md +27 -0
  217. package/dist/skills/ai-audit/references/hacking-agents/asymmetry-agent.md +77 -0
  218. package/dist/skills/ai-audit/references/hacking-agents/boundary-agent.md +79 -0
  219. package/dist/skills/ai-audit/references/hacking-agents/economic-security-agent.md +35 -0
  220. package/dist/skills/ai-audit/references/hacking-agents/execution-trace-agent.md +33 -0
  221. package/dist/skills/ai-audit/references/hacking-agents/first-principles-agent.md +36 -0
  222. package/dist/skills/ai-audit/references/hacking-agents/flow-gap-agent.md +49 -0
  223. package/dist/skills/ai-audit/references/hacking-agents/invariant-agent.md +44 -0
  224. package/dist/skills/ai-audit/references/hacking-agents/math-precision-agent.md +48 -0
  225. package/dist/skills/ai-audit/references/hacking-agents/numerical-gap-agent.md +46 -0
  226. package/dist/skills/ai-audit/references/hacking-agents/periphery-agent.md +27 -0
  227. package/dist/skills/ai-audit/references/hacking-agents/shared-rules.md +61 -0
  228. package/dist/skills/ai-audit/references/hacking-agents/trust-gap-agent.md +40 -0
  229. package/dist/skills/ai-audit/references/hex-board.md +223 -0
  230. package/dist/skills/ai-audit/references/hex-export.sh +71 -0
  231. package/dist/skills/ai-audit/references/judging.md +75 -0
  232. package/dist/skills/ai-audit/references/report-formatting.md +385 -0
  233. package/dist/skills/ai-audit/references/report-language.md +151 -0
  234. package/dist/skills/ai-audit/references/senior-auditor-sop.md +63 -0
  235. package/dist/skills/generate-report.md +9 -3
  236. package/dist/skills/ingest-aa-report.md +11 -2
  237. package/dist/skills/init-audit.md +104 -2
  238. package/dist/skills/validate-all-findings.md +1 -1
  239. package/dist/skills/validate-finding.md +12 -7
  240. package/dist/skills/write-finding.md +8 -6
  241. package/dist/types/index.d.ts +7 -1
  242. package/dist/types/index.d.ts.map +1 -1
  243. package/package.json +2 -1
  244. package/dashboard/.next/server/app/_not-found.html +0 -1
  245. package/dashboard/.next/server/app/_not-found.meta +0 -6
  246. package/dashboard/.next/server/app/_not-found.rsc +0 -12
  247. package/dashboard/.next/server/app/diagram.html +0 -1
  248. package/dashboard/.next/server/app/diagram.meta +0 -5
  249. package/dashboard/.next/server/app/diagram.rsc +0 -10
  250. package/dashboard/.next/server/app/flows.html +0 -1
  251. package/dashboard/.next/server/app/flows.meta +0 -5
  252. package/dashboard/.next/server/app/flows.rsc +0 -10
  253. package/dashboard/.next/server/chunks/44.js +0 -1
  254. package/dashboard/.next/server/pages/404.html +0 -1
  255. package/dashboard/.next/static/ZYqkgvjnS38aMxfanyctA/_buildManifest.js +0 -1
  256. package/dashboard/.next/static/chunks/1015.3ab89142e5f44120.js +0 -226
  257. package/dashboard/.next/static/chunks/1151.b6ef5c786e587ed7.js +0 -1
  258. package/dashboard/.next/static/chunks/1199.a072929dbec89965.js +0 -148
  259. package/dashboard/.next/static/chunks/1375.d4d2f7fc9c9c2ff1.js +0 -43
  260. package/dashboard/.next/static/chunks/1799.83206776abbbf1fc.js +0 -9
  261. package/dashboard/.next/static/chunks/20154aaa.ccc347c04ab5ad4a.js +0 -1
  262. package/dashboard/.next/static/chunks/2077.7011a570c87aa7b1.js +0 -1
  263. package/dashboard/.next/static/chunks/2166.cc0fabeb2e89b840.js +0 -215
  264. package/dashboard/.next/static/chunks/2325.2c55cb9a6282ae3f.js +0 -24
  265. package/dashboard/.next/static/chunks/2694.92bbe252063e4786.js +0 -1
  266. package/dashboard/.next/static/chunks/275.0d761aa0e5b030b8.js +0 -34
  267. package/dashboard/.next/static/chunks/2781.8536b644a480aede.js +0 -93
  268. package/dashboard/.next/static/chunks/2805.a8d71d2f92bb6ba9.js +0 -1
  269. package/dashboard/.next/static/chunks/3017.e55781da9dd32d37.js +0 -1
  270. package/dashboard/.next/static/chunks/3205-728c260fbb4f89c6.js +0 -2
  271. package/dashboard/.next/static/chunks/3236.dff44fa7961d9d5e.js +0 -1
  272. package/dashboard/.next/static/chunks/3480.9451396ad7ee7613.js +0 -1
  273. package/dashboard/.next/static/chunks/3626.ba1cf848a9f2e93d.js +0 -64
  274. package/dashboard/.next/static/chunks/3865.a432a7910a2f5281.js +0 -90
  275. package/dashboard/.next/static/chunks/3887.c22cbfa3f095826c.js +0 -1
  276. package/dashboard/.next/static/chunks/3924-4a05057b5450abe1.js +0 -1
  277. package/dashboard/.next/static/chunks/3948.fe3c7d758568d98b.js +0 -287
  278. package/dashboard/.next/static/chunks/4728.07d87640a3e7dd0d.js +0 -24
  279. package/dashboard/.next/static/chunks/4787.4e5f6a0e0e40a583.js +0 -23
  280. package/dashboard/.next/static/chunks/5060.baca226af35ed016.js +0 -1
  281. package/dashboard/.next/static/chunks/5284.f949ac90c95ff143.js +0 -1
  282. package/dashboard/.next/static/chunks/5715.1524bcc9591e180b.js +0 -115
  283. package/dashboard/.next/static/chunks/6014.700ae4969b64d728.js +0 -104
  284. package/dashboard/.next/static/chunks/6024.4d23707c65514679.js +0 -79
  285. package/dashboard/.next/static/chunks/6177.e5c84cfc4c0dea51.js +0 -1
  286. package/dashboard/.next/static/chunks/618f8807-547c5614e1318888.js +0 -1
  287. package/dashboard/.next/static/chunks/6434.9481771c33195d29.js +0 -1
  288. package/dashboard/.next/static/chunks/6468.f4a3e8fa6accc6da.js +0 -77
  289. package/dashboard/.next/static/chunks/6540.86f367d7390738d4.js +0 -1
  290. package/dashboard/.next/static/chunks/6549.4d0d472df96429a5.js +0 -1
  291. package/dashboard/.next/static/chunks/690f35d0.3e40ca0930e4bbdb.js +0 -119
  292. package/dashboard/.next/static/chunks/7397-f6f4dddc7a20bfc1.js +0 -1
  293. package/dashboard/.next/static/chunks/7498-ea83cb9e30ec5491.js +0 -1
  294. package/dashboard/.next/static/chunks/7802.89aec9ee11680850.js +0 -80
  295. package/dashboard/.next/static/chunks/7973.8b526f589aca5d84.js +0 -79
  296. package/dashboard/.next/static/chunks/8216.1bead812eb126c35.js +0 -5
  297. package/dashboard/.next/static/chunks/8645.a5ca76f11edc9633.js +0 -1
  298. package/dashboard/.next/static/chunks/8928-60c623ee89d2e6ad.js +0 -1
  299. package/dashboard/.next/static/chunks/9173.2486ffca31131ec5.js +0 -1
  300. package/dashboard/.next/static/chunks/9178.469341860bf8caec.js +0 -1
  301. package/dashboard/.next/static/chunks/9466.e904660d38c03eea.js +0 -1
  302. package/dashboard/.next/static/chunks/9660.84a85811380c5f33.js +0 -1
  303. package/dashboard/.next/static/chunks/9720.67d4d0d15a96d691.js +0 -1
  304. package/dashboard/.next/static/chunks/9811.65e1d080c2d256af.js +0 -1
  305. package/dashboard/.next/static/chunks/app/_not-found/page-548ab392d0e890d1.js +0 -1
  306. package/dashboard/.next/static/chunks/app/access/page-3668562e7464eb5d.js +0 -1
  307. package/dashboard/.next/static/chunks/app/calls/page-d07f5b8664cc8303.js +0 -1
  308. package/dashboard/.next/static/chunks/app/conformance/page-2fede1d7b5f9265d.js +0 -1
  309. package/dashboard/.next/static/chunks/app/diagram/page-b228444265546495.js +0 -1
  310. package/dashboard/.next/static/chunks/app/flows/page-fa67783d8cd79cab.js +0 -1
  311. package/dashboard/.next/static/chunks/app/functions/page-686f0296639133a3.js +0 -1
  312. package/dashboard/.next/static/chunks/app/issues/page-98a298e1c1045c91.js +0 -1
  313. package/dashboard/.next/static/chunks/app/layout-49f2496c7637d931.js +0 -1
  314. package/dashboard/.next/static/chunks/app/notes/page-17af94c67ba79c00.js +0 -1
  315. package/dashboard/.next/static/chunks/app/page-24bac51dfe007c66.js +0 -1
  316. package/dashboard/.next/static/chunks/app/progress/page-427fb18da3afb061.js +0 -1
  317. package/dashboard/.next/static/chunks/app/report/page-796f2f4a8a5ac8f7.js +0 -1
  318. package/dashboard/.next/static/chunks/app/stats/page-db81f600a086f252.js +0 -1
  319. package/dashboard/.next/static/chunks/c7ea4e13.5effeeba6618bdb7.js +0 -1
  320. package/dashboard/.next/static/chunks/framework-cf6f5bdca6ba0184.js +0 -33
  321. package/dashboard/.next/static/chunks/main-63ff429eab01f5bf.js +0 -1
  322. package/dashboard/.next/static/chunks/main-app-9d2f6b8a47133e9b.js +0 -1
  323. package/dashboard/.next/static/chunks/pages/_app-6ad2b50514c24ab4.js +0 -1
  324. package/dashboard/.next/static/chunks/pages/_error-d5eb11c5c4626811.js +0 -1
  325. package/dashboard/.next/static/chunks/webpack-08869f2b18792e51.js +0 -1
  326. package/dashboard/.next/static/css/4a38d8f6f6b7a68f.css +0 -3
  327. package/dashboard/.next/static/media/438aa629764e75f3-s.woff2 +0 -0
  328. package/dashboard/.next/static/media/4c9affa5bc8f420e-s.p.woff2 +0 -0
  329. package/dashboard/.next/static/media/51251f8b9793cdb3-s.woff2 +0 -0
  330. package/dashboard/.next/static/media/875ae681bfde4580-s.woff2 +0 -0
  331. package/dashboard/.next/static/media/cc978ac5ee68c2b6-s.woff2 +0 -0
  332. package/dashboard/.next/static/media/e857b654a2caa584-s.woff2 +0 -0
  333. /package/dashboard/.next/static/{ZYqkgvjnS38aMxfanyctA → z5XBev05xDAkDrxWxAjNu}/_ssgManifest.js +0 -0
@@ -0,0 +1,133 @@
1
+ # Agent prompt templates — Turn 3a
2
+
3
+ The two prompts the orchestrator gives to the 12 agents. Agents 1–9 get the
4
+ single-specialty prompt; agents 10–12 get the gap-hunter prompt.
5
+
6
+ Both are verbatim text with values substituted in. Substitute `{bundle_dir}`,
7
+ the agent number `N`, and the bundle's real line count. Change nothing else.
8
+
9
+ The orchestrator reads this file in **Turn 2**, in the same parallel message
10
+ that reads `report-formatting.md` and `judging.md`.
11
+
12
+ ---
13
+
14
+ ## Single-specialty prompt
15
+
16
+ **Turn 3a-i — Single-specialty prompt template (agents 1–9, substitute real values):**
17
+
18
+ ```
19
+ You are an attacker. Your specialty, mindset, source, and output rules
20
+ are in your bundle. Read it fully before producing findings.
21
+
22
+ Read first:
23
+ - {bundle_dir}/agent-N-bundle.md (XXXX lines) — source + SOP + specialty + shared rules.
24
+
25
+ The bundle contains all in-scope source. Do NOT re-read in-scope files
26
+ for the initial scan. Use Read/Grep only for cross-file searches or
27
+ out-of-scope context (interfaces/, mocks/, test/, and dependency
28
+ sources under node_modules/ or lib/ — read a base contract when the
29
+ behaviour it inherits matters).
30
+
31
+ You are READ-ONLY inside the audited repository. Never create, edit or
32
+ delete a file there — not a Foundry PoC, not a test, not a scratch note,
33
+ not even one you intend to delete afterwards. An audit that changes the
34
+ code it is measuring is not an audit. Write proof-of-concept code in your
35
+ own scratchpad, or quote it in your finding as text.
36
+
37
+ What a finding looks like:
38
+ - file, function
39
+ - root cause — the one-sentence code-level defect
40
+ - minimal fix — the smallest change that eliminates the defect
41
+ - proof — concrete numbers, a trace, or quoted code
42
+
43
+ Without concrete proof, it's a LEAD, not a finding. Leads are honest
44
+ about what you couldn't verify — they're not failures, they're
45
+ calibration. Emit them.
46
+
47
+ Don't skim. Don't trust your first read. Trust your discomfort.
48
+
49
+ Write every description in Simplified Technical English — the rules are
50
+ in your bundle, in "Report language". One sentence, 25 words or fewer,
51
+ active voice, no metaphor, and it names who acts and what they get.
52
+ Your bug_class label, the identifiers and any code you quote are data:
53
+ write those exactly as the source and the output rules require.
54
+
55
+ This is a differential audit. Your bundle carries "Differential audit —
56
+ focus": the source is the head version of the changed and impacted files
57
+ only. Spend your effort on the changed code and the flows that pass
58
+ through it. Report a bug in unchanged code only when the change makes it
59
+ reachable or worse, and say how. Other in-scope files were audited before;
60
+ Read them for context when a flow leaves your bundle.
61
+
62
+ Your bundle ends with "Known findings — ground already walked". Obey it:
63
+ spend your effort on new ground, report every bug you find in full —
64
+ the listed ones included — and reuse its bug-class labels for the same
65
+ class of bug in the same function.
66
+
67
+ Output format: see shared-rules.md inside your bundle.
68
+ ```
69
+
70
+ The "differential audit" paragraph is included **only in a differential audit** (`{mode}` is `diff`, `diff-focus.md` appended). The "Known findings" paragraph is included **only when memory is on and `known-findings.md` was appended**. On a plain scan the prompt is byte-identical to the one it has always been — a paragraph about a section that is not there would send agents hunting for it.
71
+
72
+ The READ-ONLY paragraph is **unconditional** — every agent, every mode, every pass. It is here because a real scan proved it necessary: an agent built Foundry proof-of-concept files inside the audited repository and deleted them afterwards. It left the tree clean and the stored SHA honest, and it was still wrong. A later editor must not make it conditional, and must not soften it into a preference.
73
+
74
+ ## Gap-hunter prompt
75
+
76
+ **Turn 3a-ii — Gap-hunter prompt template (agents 10–12, substitute real values):**
77
+
78
+ ```
79
+ You are an attacker. Your gap-hunter specialty, mindset, source, and
80
+ output rules are in your bundle. Read it fully before producing findings.
81
+
82
+ Read first:
83
+ - {bundle_dir}/agent-N-bundle.md (XXXX lines) — source + SOP + gap-hunter specialty + shared rules.
84
+
85
+ The bundle contains all in-scope source. Do NOT re-read in-scope files
86
+ for the initial scan. Use Read/Grep only for cross-file searches or
87
+ out-of-scope context (interfaces/, mocks/, test/, and dependency
88
+ sources under node_modules/ or lib/ — read a base contract when the
89
+ behaviour it inherits matters).
90
+
91
+ You are READ-ONLY inside the audited repository. Never create, edit or
92
+ delete a file there — not a Foundry PoC, not a test, not a scratch note,
93
+ not even one you intend to delete afterwards. An audit that changes the
94
+ code it is measuring is not an audit. Write proof-of-concept code in your
95
+ own scratchpad, or quote it in your finding as text.
96
+
97
+ What a finding looks like:
98
+ - file, function
99
+ - seam — which two or three lenses combine
100
+ - root cause — the one-sentence code-level defect that lives at the seam
101
+ - minimal fix — the smallest change that eliminates the defect
102
+ - proof — concrete numbers, a trace, or quoted code showing the seam
103
+
104
+ Without concrete proof of the seam, it's a LEAD, not a finding.
105
+ Leads are honest about what you couldn't verify — they're not failures,
106
+ they're calibration. Emit them.
107
+
108
+ Don't skim. Don't trust your first read. Trust your discomfort.
109
+
110
+ Write every description in Simplified Technical English — the rules are
111
+ in your bundle, in "Report language". One sentence, 25 words or fewer,
112
+ active voice, no metaphor, and it names who acts and what they get.
113
+ Your bug_class label, the identifiers and any code you quote are data:
114
+ write those exactly as the source and the output rules require.
115
+
116
+ This is a differential audit. Your bundle carries "Differential audit —
117
+ focus": the source is the head version of the changed and impacted files
118
+ only. Spend your effort on the changed code and the flows that pass
119
+ through it. Report a bug in unchanged code only when the change makes it
120
+ reachable or worse, and say how. Other in-scope files were audited before;
121
+ Read them for context when a flow leaves your bundle.
122
+
123
+ Your bundle ends with "Known findings — ground already walked". Obey it:
124
+ spend your effort on new ground, report every bug you find in full —
125
+ the listed ones included — and reuse its bug-class labels for the same
126
+ class of bug in the same function.
127
+
128
+ Output format: see shared-rules.md inside your bundle (gap-hunter-specific
129
+ output fields are in your specialty file).
130
+ ```
131
+
132
+ The same two paragraphs, under the same conditions as Turn 3a-i: the differential paragraph only in a differential audit, the known-findings paragraph only with memory on and the file appended.
133
+
@@ -0,0 +1,357 @@
1
+ #!/usr/bin/env bash
2
+ # THE ASSEMBLER. It writes the whole ai-audit report. SKILL.md Turn 5 runs it.
3
+ #
4
+ # This is the only producer of a report in this skill. The orchestrator does not compose one,
5
+ # and must not be re-taught to: an orchestrator under context pressure is the thing that
6
+ # failed. Every finding this scan gated is in a run file; this script prints all of them or
7
+ # says out loud that it could not.
8
+ #
9
+ # assemble.sh --dir .hex/ai-audit/runs/{stamp}
10
+ #
11
+ # Reads ONE directory and writes {dir}/full-report.md — the complete report, banner line down
12
+ # to the disclaimer, ready to print word for word. No model judgment runs in here.
13
+ #
14
+ # reads dir/run-K.md the run files (ticket 01 shape), one per pass, model-written
15
+ # dir/scope.tsv key <TAB> value, append-only, LAST LINE PER KEY WINS
16
+ # dir/memory-before.tsv the pruned photocopy — its PRESENCE is not the memory flag,
17
+ # scope.tsv's `mem_before` key is
18
+ # dir/source-names.tsv normalised <TAB> as spelled in the source
19
+ # writes dir/full-report.md
20
+ # dir/winners.tsv (Hex) one row per key, the cross-run winner — Turn 6's input
21
+ #
22
+ # The model types the markers, so it can mistype one. The assembler CHECKS them and prints
23
+ # the disagreement into the Scope table. A broken run file becomes a visible line in the
24
+ # report, never a silent loss.
25
+ #
26
+ # Written to .part and moved into place on exit 0, so a half-report never exists.
27
+ set -euo pipefail
28
+
29
+ dir=
30
+ while [ $# -gt 0 ]; do
31
+ case "$1" in
32
+ --dir) dir=$2; shift 2 ;;
33
+ *) echo "assemble.sh: unknown argument $1" >&2; exit 2 ;;
34
+ esac
35
+ done
36
+ [ -d "$dir" ] || { echo "assemble.sh: no such directory $dir" >&2; exit 2; }
37
+
38
+ out="$dir/full-report.md"
39
+ work="$(mktemp -d)"
40
+ trap 'rm -rf "$work"' EXIT
41
+
42
+ THRESHOLD=75 # judging.md sets it. Named there and read here; never a second opinion.
43
+
44
+ # ---------------------------------------------------------------- scope.tsv, last wins
45
+ # An absent key gives an absent row. That is what keeps a plain scan's table at four rows.
46
+ # A missing scope.tsv is every key missing at once — the same path, no special case. It must
47
+ # not be a non-zero exit either: `set -e` would turn one absent label into no report at all.
48
+ scope() {
49
+ [ -f "$dir/scope.tsv" ] || return 0
50
+ awk -F'\t' -v k="$1" '$1==k { v=$2 } END { print v }' "$dir/scope.tsv"
51
+ }
52
+
53
+ name=$(scope name); [ -n "$name" ] || name='**name missing**'
54
+ mode=$(scope mode); [ -n "$mode" ] || mode='**Mode missing**'
55
+ passes_planned=$(scope passes_planned)
56
+ mem_before=$(scope mem_before)
57
+ mem_after=$(scope mem_after)
58
+ mem_sha=$(scope mem_sha)
59
+
60
+ memory_on=0; [ -n "$mem_before" ] && memory_on=1
61
+ if [ "$memory_on" = 1 ] && [ ! -f "$dir/memory-before.tsv" ]; then
62
+ echo "assemble.sh: memory is on but $dir/memory-before.tsv is missing — Turn 5 did not copy it" >&2
63
+ memory_on=0
64
+ fi
65
+
66
+ # run files in PASS order. A plain glob puts run-10 before run-2, which is a real 10-pass bug.
67
+ runs=()
68
+ while IFS= read -r f; do runs+=("$f"); done < <(
69
+ ls "$dir"/run-*.md 2>/dev/null | sed 's/.*run-\([0-9]*\)\.md/\1 &/' | sort -n | cut -d' ' -f2)
70
+ N=${#runs[@]}
71
+
72
+ # ---------------------------------------------------------------- index every block
73
+ # key conf kind agents file pass start end bodystart bodyend title loc leadbody
74
+ #
75
+ # A FINDING and a LEAD are NOT the same shape on disk, and one geometry read over both is what
76
+ # produced `- **- **Title**` rows and a "Body missing" line under leads that had a body:
77
+ #
78
+ # FINDING LEAD
79
+ # +0 <!--F ...--> +0 <!--F ...-->
80
+ # +1 +1
81
+ # +2 [95] **1. T** +2 - **T** — `loc` · TAG — smells — why not verified
82
+ # +3 +3
83
+ # +4 `loc` · Conf +4 <!--/F-->
84
+ # +5
85
+ # +6 body …
86
+ #
87
+ # Read with the finding geometry, a lead put its WHOLE formatted line in `title` (which the
88
+ # emitter then wrapped in `- **…**` a second time), found no backticks at +4 so `loc` came out
89
+ # empty, and had no body region at all. Each kind now gets its own reader.
90
+ #
91
+ # **No field is ever emitted empty** — `-` stands in. `read` below splits on IFS=$'\t', and a
92
+ # tab is IFS *whitespace*, so bash collapses `\t\t` into one delimiter and every later field
93
+ # shifts left by one. That is how a lead's memory tag ended up printed as its location.
94
+ : > "$work/index.tsv"
95
+ for f in ${runs[@]+"${runs[@]}"}; do
96
+ awk -v F="$f" '
97
+ /^<!--RUN / { line=$0; sub(/[[:space:]]*-->[[:space:]]*$/, "", line)
98
+ n=split(line, a, /[[:space:]]+/)
99
+ for (i=2; i<=n; i++) { eq=index(a[i],"="); if (substr(a[i],1,eq-1)=="pass") pass=substr(a[i],eq+1) } }
100
+ /^<!--F / {
101
+ key=""; conf=""; kind=""; agents=""
102
+ line = $0
103
+ sub(/[[:space:]]*-->[[:space:]]*$/, "", line) # terminator off BEFORE splitting
104
+ n = split(line, a, /[[:space:]]+/)
105
+ for (i = 2; i <= n; i++) {
106
+ eq = index(a[i], "="); nm = substr(a[i], 1, eq-1); v = substr(a[i], eq+1)
107
+ if (nm == "key") key = v; else if (nm == "conf") conf = v
108
+ else if (nm == "kind") kind = v; else if (nm == "agents") agents = v
109
+ }
110
+ if (conf == "") conf = "-" # a LEAD is not scored
111
+ start = NR; title = ""; loc = ""; lbody = ""
112
+ next
113
+ }
114
+ kind != "LEAD" && start && NR == start + 2 { t = $0; sub(/^\[[0-9]+\] /, "", t); sub(/^\*\*/, "", t); sub(/\*\*$/, "", t); title = t }
115
+ kind != "LEAD" && start && NR == start + 4 { l = $0; if (match(l, /`[^`]*`/)) loc = substr(l, RSTART+1, RLENGTH-2) }
116
+
117
+ # A lead is one line. Split it here, once, so the emitter formats leads and findings with
118
+ # the same fields instead of re-printing a line that is already formatted.
119
+ # `match` + RSTART/RLENGTH, never index()+a literal width: the separator is an em dash,
120
+ # 3 bytes and 1 character, and the two disagree across awks and locales.
121
+ kind == "LEAD" && start && NR == start + 2 && /^- \*\*/ {
122
+ l = $0
123
+ sub(/^- \*\*/, "", l)
124
+ if (match(l, /\*\* — /)) { title = substr(l, 1, RSTART-1); l = substr(l, RSTART+RLENGTH) }
125
+ else { title = l; l = "" }
126
+ if (match(l, /^`[^`]*`/)) { loc = substr(l, RSTART+1, RLENGTH-2); l = substr(l, RSTART+RLENGTH) }
127
+ # What is left is " · NEW — body" or " — body". Either way the body starts after the
128
+ # first " — ". The inline tag is DROPPED: the assembler derives the memory tag itself
129
+ # from memory-before.tsv, and two sources for one fact is how they come to disagree.
130
+ if (match(l, / — /)) l = substr(l, RSTART+RLENGTH); else l = ""
131
+ lbody = l
132
+ }
133
+ /^<!--\/F-->/ && start {
134
+ if (title == "") title = "-"
135
+ if (loc == "") loc = "-"
136
+ if (lbody == "") lbody = "-"
137
+ print key "\t" conf "\t" kind "\t" agents "\t" F "\t" pass "\t" start "\t" NR "\t" (start+6) "\t" (NR-1) "\t" title "\t" loc "\t" lbody
138
+ start = 0; kind = ""
139
+ }
140
+ ' "$f" >> "$work/index.tsv"
141
+ done
142
+
143
+ # ---------------------------------------------------------------- the structure check
144
+ # The model typed these markers. When the counts disagree, a finding was raised and cannot be
145
+ # read — say so IN the report. The report may print less than the scan found; it may never
146
+ # claim to print more.
147
+ #
148
+ # No run file at all is the same rule at its limit: pass 1 produced nothing, so the scan
149
+ # reviewed nothing. That is a REPORT, not an exit — SKILL.md Turn 3b routes a real scan down
150
+ # here, and a shell error in place of a report is the one outcome this skill must never have.
151
+ # The row is necessary because the Passes row is suppressed on a 1-pass scan, so without it
152
+ # nothing in the report would say the pass died.
153
+ broken=
154
+ if [ "$N" = 0 ]; then
155
+ broken="⚠️ No pass produced a run file. This scan reviewed nothing."
156
+ echo "assemble.sh: NO RUN FILES — $broken" >&2
157
+ else
158
+ opens=$(cat "${runs[@]}" | grep -c '^<!--F ' || :)
159
+ closes=$(cat "${runs[@]}" | grep -c '^<!--/F-->' || :)
160
+ indexed=$(wc -l < "$work/index.tsv" | tr -d ' ')
161
+ if [ "$opens" != "$closes" ] || [ "$opens" != "$indexed" ]; then
162
+ broken="⚠️ $opens findings marked, $indexed readable. $(( opens - indexed )) could not be read and are missing below. See the run files."
163
+ echo "assemble.sh: STRUCTURE BROKEN — $broken" >&2
164
+ fi
165
+ fi
166
+
167
+ # ---------------------------------------------------------------- dedup across runs
168
+ # One winner per key: strongest kind, then highest confidence, then the LATER pass — a later
169
+ # pass read the ledger every earlier pass wrote, so it is the better-informed write-up.
170
+ # k counts every run that raised the key, in either section.
171
+ sort -t $'\t' -k1,1 "$work/index.tsv" | awk -F'\t' '
172
+ function rank(k) { return (k == "FINDING") ? 1 : 0 }
173
+ {
174
+ if (!(($5 SUBSEP $1) in seenrun)) { seenrun[$5 SUBSEP $1]=1; k[$1]++ }
175
+ c = ($2 == "-") ? -1 : $2 + 0
176
+ if (!($1 in best) || rank($3) > br[$1] || (rank($3) == br[$1] && c > bc[$1]) \
177
+ || (rank($3) == br[$1] && c == bc[$1] && $6 + 0 >= bp[$1])) {
178
+ best[$1] = $0; br[$1] = rank($3); bc[$1] = c; bp[$1] = $6 + 0
179
+ }
180
+ }
181
+ END { for (key in best) print k[key] "\t" best[key] }
182
+ ' > "$work/merged.tsv"
183
+
184
+ # ---------------------------------------------------------------- the memory tag
185
+ # Derived here from memory-before.tsv, not carried in the marker. One source: the report and
186
+ # the ledger cannot disagree because both read the same photocopy.
187
+ # KNOWN (n scans) — the STORED count plus one; this scan has just found it again.
188
+ if [ "$memory_on" = 1 ]; then
189
+ awk -F'\t' -v OFS='\t' '
190
+ FILENAME==ARGV[1] { if (FNR>1) sc[$1]=$3; next }
191
+ { print $0, ($2 in sc) ? "KNOWN (" sc[$2]+1 " scans)" : "NEW" }
192
+ ' "$dir/memory-before.tsv" "$work/merged.tsv" > "$work/merged.tagged.tsv"
193
+ else
194
+ awk -F'\t' -v OFS='\t' '{ print $0, "" }' "$work/merged.tsv" > "$work/merged.tagged.tsv"
195
+ fi
196
+
197
+ # columns now: 1 k · 2 key · 3 conf · 4 kind · 5 agents · 6 file · 7 pass · 8 start · 9 end
198
+ # 10 bodystart · 11 bodyend · 12 title · 13 loc · 14 leadbody · 15 memtag
199
+ # 12, 13 and 14 are never empty — `-` stands in, because IFS=$'\t' collapses adjacent tabs.
200
+ sort -t $'\t' -k4,4 -k3,3nr -k2,2 "$work/merged.tagged.tsv" > "$work/sorted.tsv"
201
+ # Hex: persist the winners before the work dir is deleted. Same 15 columns as above, FINDINGs
202
+ # first, highest confidence first. hex-export.sh reads it; nothing in this script reads it back.
203
+ cp "$work/sorted.tsv" "$dir/winners.tsv"
204
+ awk -F'\t' '$4=="FINDING"' "$work/sorted.tsv" > "$work/findings.tsv"
205
+ awk -F'\t' '$4=="LEAD"' "$work/sorted.tsv" > "$work/leads.tsv"
206
+
207
+ nfind=$(wc -l < "$work/findings.tsv" | tr -d ' ')
208
+ nlead=$(wc -l < "$work/leads.tsv" | tr -d ' ')
209
+
210
+ # ---------------------------------------------------------------- emit
211
+ R="$work/report.md"
212
+ : > "$R"
213
+ say() { printf '%s\n' "$1" >> "$R"; }
214
+ rule() { say ""; say "---"; say ""; }
215
+ row() { printf '| %s | %s |\n' "$1" "$2" >> "$R"; }
216
+
217
+ say "# 🔐 Security Review — $name"
218
+ rule
219
+ say "## Scope"
220
+ say ""
221
+ row "" ""
222
+ row "---" "---"
223
+ row "**Mode**" "$mode"
224
+
225
+ # Files reviewed — 3 per line, in source.md order, joined with `<br>`. One `files` key holds
226
+ # them space separated; shell does the wrapping.
227
+ files=$(scope files | tr ' ' '\n' | awk 'NF { printf "`%s`", $0; if (++n % 3 == 0) printf "<br>"; else printf " · " }' \
228
+ | sed -e 's/ · $//' -e 's/<br>$//')
229
+ row "**Files reviewed**" "$files"
230
+ row "**Confidence threshold (1-100)**" "$THRESHOLD"
231
+
232
+ # The Passes cell is COMPOSED from facts, never written as prose by a model.
233
+ if [ -n "$passes_planned" ] && [ "$passes_planned" -gt 1 ] 2>/dev/null; then
234
+ short=""
235
+ for k in $(seq 1 "$passes_planned"); do
236
+ a=$(scope "pass_${k}_agents"); fail=$(scope "pass_${k}_failed")
237
+ if [ -n "$fail" ]; then short="${short:+$short, }pass $k failed"
238
+ elif [ -n "$a" ] && [ "$a" != "12/12" ]; then short="${short:+$short, }pass $k ran $a agents"; fi
239
+ done
240
+ if [ "$N" -lt "$passes_planned" ]; then cell="$N of $passes_planned"; else cell="$passes_planned"; fi
241
+ [ -n "$short" ] && cell="$cell ($short)"
242
+ row "**Passes**" "$cell"
243
+ fi
244
+ [ "$memory_on" = 1 ] && row "**Memory**" "$mem_before records before this scan · $mem_after after · \`$mem_sha\`"
245
+ [ -n "$broken" ] && row "**Run files**" "$broken"
246
+ rule
247
+
248
+ say "## Findings"
249
+ say ""
250
+
251
+ emit_body() { # file bodystart bodyend — copied through, never re-worded
252
+ awk -v s="$2" -v e="$3" 'NR>=s && NR<=e' "$1" \
253
+ | awk '{ lines[++n] = $0 } END {
254
+ b=1; while (b<=n && lines[b]=="") b++
255
+ while (n>=b && lines[n]=="") n--
256
+ for (i=b; i<=n; i++) print lines[i] }'
257
+ }
258
+
259
+ i=0
260
+ while IFS=$'\t' read -r k key conf kind agents file pass start end bstart bend title loc lbody memtag; do
261
+ i=$((i+1))
262
+ [ "$title" = "-" ] && title="**Title missing** — the block's title line could not be read"
263
+ if [ "$loc" = "-" ]; then meta="**location missing**"; else meta="\`$loc\`"; fi
264
+ say "[$conf] **$i. $title**"
265
+ say ""
266
+ meta="$meta · Confidence: $conf"
267
+ [ "$N" -gt 1 ] && meta="$meta · seen in $k/$N runs"
268
+ [ -n "$memtag" ] && meta="$meta · $memtag"
269
+ say "$meta"
270
+ say ""
271
+ body=$(emit_body "$file" "$bstart" "$bend")
272
+ if [ -z "$body" ]; then
273
+ say "**Body missing** — pass $pass raised this finding and wrote no description."
274
+ else
275
+ printf '%s\n' "$body" >> "$R"
276
+ fi
277
+ rule
278
+ done < "$work/findings.tsv"
279
+
280
+ if [ "$nfind" = 0 ]; then
281
+ # An empty table with a header row and no rows under it is not a report of nothing, it is a
282
+ # report that looks broken. Say it in words instead.
283
+ say "_None — this scan raised no findings._"
284
+ rule
285
+ else
286
+ say "Findings List"
287
+ say ""
288
+ say "| # | Confidence | Title |"
289
+ say "|---|---|---|"
290
+ i=0; sep=0
291
+ while IFS=$'\t' read -r k key conf kind agents file pass start end bstart bend title loc lbody memtag; do
292
+ i=$((i+1))
293
+ if [ "$sep" = 0 ] && [ "$conf" -lt "$THRESHOLD" ]; then
294
+ say "| | | **Below Confidence Threshold** |"; sep=1
295
+ fi
296
+ say "| $i | [$conf] | $title |"
297
+ done < "$work/findings.tsv"
298
+ rule
299
+ fi
300
+
301
+ say "## Leads"
302
+ say ""
303
+ say "_Vulnerability trails with concrete code smells where the full exploit path could not be completed in one analysis pass. These are not false positives — they are high-signal leads for manual review. Not scored._"
304
+ say ""
305
+ [ "$nlead" = 0 ] && say "_None._"
306
+ while IFS=$'\t' read -r k key conf kind agents file pass start end bstart bend title loc lbody memtag; do
307
+ seg=""
308
+ [ "$N" -gt 1 ] && seg="$seg · seen in $k/$N runs"
309
+ [ -n "$memtag" ] && seg="$seg · $memtag"
310
+ # The body was parsed out of the lead's own line by the indexer. Do NOT read it back out of
311
+ # the run file here: a lead has no body region, so emit_body returned nothing and every lead
312
+ # got the "Body missing" line whether or not it had one.
313
+ [ "$title" = "-" ] && title="**Title missing** — the lead's line could not be read"
314
+ if [ "$loc" = "-" ]; then locmd="**location missing**"; else locmd="\`$loc\`"; fi
315
+ [ "$lbody" = "-" ] && lbody="**Body missing** — pass $pass raised this lead and wrote no description."
316
+ say "- **$title** — $locmd$seg — $lbody"
317
+ done < "$work/leads.tsv"
318
+
319
+ # ---------------------------------------------------------------- Known from earlier scans
320
+ # The keys this scan raised come from the index — the run files are the record, so no separate
321
+ # run-keys.tsv or scan-rows.tsv has to be carried in.
322
+ if [ "$memory_on" = 1 ]; then
323
+ held=$(( $(wc -l < "$dir/memory-before.tsv") - 1 ))
324
+ if [ "$held" -gt 0 ]; then
325
+ tail -n +2 "$dir/memory-before.tsv" | cut -f1 | sort -u > "$work/keys-before.txt"
326
+ cut -f1 "$work/index.tsv" | sort -u > "$work/keys-scan.txt"
327
+ comm -23 "$work/keys-before.txt" "$work/keys-scan.txt" > "$work/keys-left.txt"
328
+ rule
329
+ say "## Known from earlier scans"
330
+ say ""
331
+ say "_Recorded by earlier scans of this repo, not raised again by this one. Not re-checked — a record here may be fixed, or may still be live and missed. \`.hex/ai-audit/memory.tsv\`._"
332
+ say ""
333
+ if [ -s "$work/keys-left.txt" ]; then
334
+ say "| Scans | Kind | Location | Title |"
335
+ say "|---|---|---|---|"
336
+ awk -F'\t' '
337
+ FILENAME==ARGV[1] { nm[$1]=$2; next }
338
+ FILENAME==ARGV[2] { if (FNR>1) { sc[$1]=$3; ti[$1]=$5; ki[$1]=$6 } ; next }
339
+ {
340
+ split($1, p, "|")
341
+ c = (p[1] in nm) ? nm[p[1]] : p[1] # print-as-stored when the segment is not in the map
342
+ f = (p[2] in nm) ? nm[p[2]] : p[2]
343
+ print "| " sc[$1] " | " ki[$1] " | `" c "." f "` | " ti[$1] " |"
344
+ }
345
+ ' "$dir/source-names.tsv" "$dir/memory-before.tsv" "$work/keys-left.txt" >> "$R"
346
+ else
347
+ say "_None — every record in the ledger was raised again by this scan._"
348
+ fi
349
+ fi
350
+ fi
351
+
352
+ rule
353
+ say "> ⚠️ This review was performed by an AI assistant. AI analysis can never verify the complete absence of vulnerabilities and no guarantee of security is given. Team security reviews, bug bounty programs, and on-chain monitoring are strongly recommended."
354
+
355
+ cp "$R" "$out.part"
356
+ mv "$out.part" "$out"
357
+ echo "assembled $out — $nfind findings, $nlead leads, $N run files"