@nebulacomponents/citable 1.19.0 → 1.21.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 (360) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +12 -1
  3. package/dist/universal/.agents/skills/citable/SKILL.md +11 -2
  4. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  5. package/dist/universal/.agents/skills/citable/manifest.json +24 -12
  6. package/dist/universal/.agents/skills/citable/schemas/action-plan.schema.json +38 -1
  7. package/dist/universal/.agents/skills/citable/schemas/audit-coverage.schema.json +118 -0
  8. package/dist/universal/.agents/skills/citable/schemas/claim-evidence.schema.json +21 -0
  9. package/dist/universal/.agents/skills/citable/schemas/claim-verification.schema.json +18 -0
  10. package/dist/universal/.agents/skills/citable/schemas/collection-result.schema.json +35 -0
  11. package/dist/universal/.agents/skills/citable/schemas/config.schema.json +2 -0
  12. package/dist/universal/.agents/skills/citable/schemas/cro-report.schema.json +8 -1
  13. package/dist/universal/.agents/skills/citable/schemas/derivation.schema.json +18 -0
  14. package/dist/universal/.agents/skills/citable/schemas/external-comparison.schema.json +16 -0
  15. package/dist/universal/.agents/skills/citable/schemas/external-observation.schema.json +32 -0
  16. package/dist/universal/.agents/skills/citable/schemas/finding.schema.json +105 -2
  17. package/dist/universal/.agents/skills/citable/schemas/prompt-set.schema.json +47 -0
  18. package/dist/universal/.agents/skills/citable/schemas/remediation-verification.schema.json +12 -1
  19. package/dist/universal/.agents/skills/citable/schemas/representation-data.schema.json +21 -0
  20. package/dist/universal/.agents/skills/citable/schemas/research-dataset.schema.json +27 -0
  21. package/dist/universal/.agents/skills/citable/schemas/run.schema.json +15 -2
  22. package/dist/universal/.agents/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  23. package/dist/universal/.agents/skills/citable/schemas/search-report.schema.json +8 -1
  24. package/dist/universal/.agents/skills/citable/schemas/summary.schema.json +41 -0
  25. package/dist/universal/.claude/agents/citable/manifest.json +2 -2
  26. package/dist/universal/.claude/skills/citable/SKILL.md +11 -2
  27. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  28. package/dist/universal/.claude/skills/citable/manifest.json +24 -12
  29. package/dist/universal/.claude/skills/citable/schemas/action-plan.schema.json +38 -1
  30. package/dist/universal/.claude/skills/citable/schemas/audit-coverage.schema.json +118 -0
  31. package/dist/universal/.claude/skills/citable/schemas/claim-evidence.schema.json +21 -0
  32. package/dist/universal/.claude/skills/citable/schemas/claim-verification.schema.json +18 -0
  33. package/dist/universal/.claude/skills/citable/schemas/collection-result.schema.json +35 -0
  34. package/dist/universal/.claude/skills/citable/schemas/config.schema.json +2 -0
  35. package/dist/universal/.claude/skills/citable/schemas/cro-report.schema.json +8 -1
  36. package/dist/universal/.claude/skills/citable/schemas/derivation.schema.json +18 -0
  37. package/dist/universal/.claude/skills/citable/schemas/external-comparison.schema.json +16 -0
  38. package/dist/universal/.claude/skills/citable/schemas/external-observation.schema.json +32 -0
  39. package/dist/universal/.claude/skills/citable/schemas/finding.schema.json +105 -2
  40. package/dist/universal/.claude/skills/citable/schemas/prompt-set.schema.json +47 -0
  41. package/dist/universal/.claude/skills/citable/schemas/remediation-verification.schema.json +12 -1
  42. package/dist/universal/.claude/skills/citable/schemas/representation-data.schema.json +21 -0
  43. package/dist/universal/.claude/skills/citable/schemas/research-dataset.schema.json +27 -0
  44. package/dist/universal/.claude/skills/citable/schemas/run.schema.json +15 -2
  45. package/dist/universal/.claude/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  46. package/dist/universal/.claude/skills/citable/schemas/search-report.schema.json +8 -1
  47. package/dist/universal/.claude/skills/citable/schemas/summary.schema.json +41 -0
  48. package/dist/universal/.cursor/skills/citable/SKILL.md +11 -2
  49. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  50. package/dist/universal/.cursor/skills/citable/manifest.json +24 -12
  51. package/dist/universal/.cursor/skills/citable/schemas/action-plan.schema.json +38 -1
  52. package/dist/universal/.cursor/skills/citable/schemas/audit-coverage.schema.json +118 -0
  53. package/dist/universal/.cursor/skills/citable/schemas/claim-evidence.schema.json +21 -0
  54. package/dist/universal/.cursor/skills/citable/schemas/claim-verification.schema.json +18 -0
  55. package/dist/universal/.cursor/skills/citable/schemas/collection-result.schema.json +35 -0
  56. package/dist/universal/.cursor/skills/citable/schemas/config.schema.json +2 -0
  57. package/dist/universal/.cursor/skills/citable/schemas/cro-report.schema.json +8 -1
  58. package/dist/universal/.cursor/skills/citable/schemas/derivation.schema.json +18 -0
  59. package/dist/universal/.cursor/skills/citable/schemas/external-comparison.schema.json +16 -0
  60. package/dist/universal/.cursor/skills/citable/schemas/external-observation.schema.json +32 -0
  61. package/dist/universal/.cursor/skills/citable/schemas/finding.schema.json +105 -2
  62. package/dist/universal/.cursor/skills/citable/schemas/prompt-set.schema.json +47 -0
  63. package/dist/universal/.cursor/skills/citable/schemas/remediation-verification.schema.json +12 -1
  64. package/dist/universal/.cursor/skills/citable/schemas/representation-data.schema.json +21 -0
  65. package/dist/universal/.cursor/skills/citable/schemas/research-dataset.schema.json +27 -0
  66. package/dist/universal/.cursor/skills/citable/schemas/run.schema.json +15 -2
  67. package/dist/universal/.cursor/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  68. package/dist/universal/.cursor/skills/citable/schemas/search-report.schema.json +8 -1
  69. package/dist/universal/.cursor/skills/citable/schemas/summary.schema.json +41 -0
  70. package/dist/universal/.gemini/skills/citable/SKILL.md +11 -2
  71. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  72. package/dist/universal/.gemini/skills/citable/manifest.json +24 -12
  73. package/dist/universal/.gemini/skills/citable/schemas/action-plan.schema.json +38 -1
  74. package/dist/universal/.gemini/skills/citable/schemas/audit-coverage.schema.json +118 -0
  75. package/dist/universal/.gemini/skills/citable/schemas/claim-evidence.schema.json +21 -0
  76. package/dist/universal/.gemini/skills/citable/schemas/claim-verification.schema.json +18 -0
  77. package/dist/universal/.gemini/skills/citable/schemas/collection-result.schema.json +35 -0
  78. package/dist/universal/.gemini/skills/citable/schemas/config.schema.json +2 -0
  79. package/dist/universal/.gemini/skills/citable/schemas/cro-report.schema.json +8 -1
  80. package/dist/universal/.gemini/skills/citable/schemas/derivation.schema.json +18 -0
  81. package/dist/universal/.gemini/skills/citable/schemas/external-comparison.schema.json +16 -0
  82. package/dist/universal/.gemini/skills/citable/schemas/external-observation.schema.json +32 -0
  83. package/dist/universal/.gemini/skills/citable/schemas/finding.schema.json +105 -2
  84. package/dist/universal/.gemini/skills/citable/schemas/prompt-set.schema.json +47 -0
  85. package/dist/universal/.gemini/skills/citable/schemas/remediation-verification.schema.json +12 -1
  86. package/dist/universal/.gemini/skills/citable/schemas/representation-data.schema.json +21 -0
  87. package/dist/universal/.gemini/skills/citable/schemas/research-dataset.schema.json +27 -0
  88. package/dist/universal/.gemini/skills/citable/schemas/run.schema.json +15 -2
  89. package/dist/universal/.gemini/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  90. package/dist/universal/.gemini/skills/citable/schemas/search-report.schema.json +8 -1
  91. package/dist/universal/.gemini/skills/citable/schemas/summary.schema.json +41 -0
  92. package/dist/universal/.github/skills/citable/SKILL.md +11 -2
  93. package/dist/universal/.github/skills/citable/VERSION +1 -1
  94. package/dist/universal/.github/skills/citable/manifest.json +24 -12
  95. package/dist/universal/.github/skills/citable/schemas/action-plan.schema.json +38 -1
  96. package/dist/universal/.github/skills/citable/schemas/audit-coverage.schema.json +118 -0
  97. package/dist/universal/.github/skills/citable/schemas/claim-evidence.schema.json +21 -0
  98. package/dist/universal/.github/skills/citable/schemas/claim-verification.schema.json +18 -0
  99. package/dist/universal/.github/skills/citable/schemas/collection-result.schema.json +35 -0
  100. package/dist/universal/.github/skills/citable/schemas/config.schema.json +2 -0
  101. package/dist/universal/.github/skills/citable/schemas/cro-report.schema.json +8 -1
  102. package/dist/universal/.github/skills/citable/schemas/derivation.schema.json +18 -0
  103. package/dist/universal/.github/skills/citable/schemas/external-comparison.schema.json +16 -0
  104. package/dist/universal/.github/skills/citable/schemas/external-observation.schema.json +32 -0
  105. package/dist/universal/.github/skills/citable/schemas/finding.schema.json +105 -2
  106. package/dist/universal/.github/skills/citable/schemas/prompt-set.schema.json +47 -0
  107. package/dist/universal/.github/skills/citable/schemas/remediation-verification.schema.json +12 -1
  108. package/dist/universal/.github/skills/citable/schemas/representation-data.schema.json +21 -0
  109. package/dist/universal/.github/skills/citable/schemas/research-dataset.schema.json +27 -0
  110. package/dist/universal/.github/skills/citable/schemas/run.schema.json +15 -2
  111. package/dist/universal/.github/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  112. package/dist/universal/.github/skills/citable/schemas/search-report.schema.json +8 -1
  113. package/dist/universal/.github/skills/citable/schemas/summary.schema.json +41 -0
  114. package/dist/universal/.kiro/skills/citable/SKILL.md +11 -2
  115. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  116. package/dist/universal/.kiro/skills/citable/manifest.json +24 -12
  117. package/dist/universal/.kiro/skills/citable/schemas/action-plan.schema.json +38 -1
  118. package/dist/universal/.kiro/skills/citable/schemas/audit-coverage.schema.json +118 -0
  119. package/dist/universal/.kiro/skills/citable/schemas/claim-evidence.schema.json +21 -0
  120. package/dist/universal/.kiro/skills/citable/schemas/claim-verification.schema.json +18 -0
  121. package/dist/universal/.kiro/skills/citable/schemas/collection-result.schema.json +35 -0
  122. package/dist/universal/.kiro/skills/citable/schemas/config.schema.json +2 -0
  123. package/dist/universal/.kiro/skills/citable/schemas/cro-report.schema.json +8 -1
  124. package/dist/universal/.kiro/skills/citable/schemas/derivation.schema.json +18 -0
  125. package/dist/universal/.kiro/skills/citable/schemas/external-comparison.schema.json +16 -0
  126. package/dist/universal/.kiro/skills/citable/schemas/external-observation.schema.json +32 -0
  127. package/dist/universal/.kiro/skills/citable/schemas/finding.schema.json +105 -2
  128. package/dist/universal/.kiro/skills/citable/schemas/prompt-set.schema.json +47 -0
  129. package/dist/universal/.kiro/skills/citable/schemas/remediation-verification.schema.json +12 -1
  130. package/dist/universal/.kiro/skills/citable/schemas/representation-data.schema.json +21 -0
  131. package/dist/universal/.kiro/skills/citable/schemas/research-dataset.schema.json +27 -0
  132. package/dist/universal/.kiro/skills/citable/schemas/run.schema.json +15 -2
  133. package/dist/universal/.kiro/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  134. package/dist/universal/.kiro/skills/citable/schemas/search-report.schema.json +8 -1
  135. package/dist/universal/.kiro/skills/citable/schemas/summary.schema.json +41 -0
  136. package/dist/universal/.opencode/skills/citable/SKILL.md +11 -2
  137. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  138. package/dist/universal/.opencode/skills/citable/manifest.json +24 -12
  139. package/dist/universal/.opencode/skills/citable/schemas/action-plan.schema.json +38 -1
  140. package/dist/universal/.opencode/skills/citable/schemas/audit-coverage.schema.json +118 -0
  141. package/dist/universal/.opencode/skills/citable/schemas/claim-evidence.schema.json +21 -0
  142. package/dist/universal/.opencode/skills/citable/schemas/claim-verification.schema.json +18 -0
  143. package/dist/universal/.opencode/skills/citable/schemas/collection-result.schema.json +35 -0
  144. package/dist/universal/.opencode/skills/citable/schemas/config.schema.json +2 -0
  145. package/dist/universal/.opencode/skills/citable/schemas/cro-report.schema.json +8 -1
  146. package/dist/universal/.opencode/skills/citable/schemas/derivation.schema.json +18 -0
  147. package/dist/universal/.opencode/skills/citable/schemas/external-comparison.schema.json +16 -0
  148. package/dist/universal/.opencode/skills/citable/schemas/external-observation.schema.json +32 -0
  149. package/dist/universal/.opencode/skills/citable/schemas/finding.schema.json +105 -2
  150. package/dist/universal/.opencode/skills/citable/schemas/prompt-set.schema.json +47 -0
  151. package/dist/universal/.opencode/skills/citable/schemas/remediation-verification.schema.json +12 -1
  152. package/dist/universal/.opencode/skills/citable/schemas/representation-data.schema.json +21 -0
  153. package/dist/universal/.opencode/skills/citable/schemas/research-dataset.schema.json +27 -0
  154. package/dist/universal/.opencode/skills/citable/schemas/run.schema.json +15 -2
  155. package/dist/universal/.opencode/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  156. package/dist/universal/.opencode/skills/citable/schemas/search-report.schema.json +8 -1
  157. package/dist/universal/.opencode/skills/citable/schemas/summary.schema.json +41 -0
  158. package/dist/universal/.pi/agent/skills/citable/SKILL.md +11 -2
  159. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  160. package/dist/universal/.pi/agent/skills/citable/manifest.json +24 -12
  161. package/dist/universal/.pi/agent/skills/citable/schemas/action-plan.schema.json +38 -1
  162. package/dist/universal/.pi/agent/skills/citable/schemas/audit-coverage.schema.json +118 -0
  163. package/dist/universal/.pi/agent/skills/citable/schemas/claim-evidence.schema.json +21 -0
  164. package/dist/universal/.pi/agent/skills/citable/schemas/claim-verification.schema.json +18 -0
  165. package/dist/universal/.pi/agent/skills/citable/schemas/collection-result.schema.json +35 -0
  166. package/dist/universal/.pi/agent/skills/citable/schemas/config.schema.json +2 -0
  167. package/dist/universal/.pi/agent/skills/citable/schemas/cro-report.schema.json +8 -1
  168. package/dist/universal/.pi/agent/skills/citable/schemas/derivation.schema.json +18 -0
  169. package/dist/universal/.pi/agent/skills/citable/schemas/external-comparison.schema.json +16 -0
  170. package/dist/universal/.pi/agent/skills/citable/schemas/external-observation.schema.json +32 -0
  171. package/dist/universal/.pi/agent/skills/citable/schemas/finding.schema.json +105 -2
  172. package/dist/universal/.pi/agent/skills/citable/schemas/prompt-set.schema.json +47 -0
  173. package/dist/universal/.pi/agent/skills/citable/schemas/remediation-verification.schema.json +12 -1
  174. package/dist/universal/.pi/agent/skills/citable/schemas/representation-data.schema.json +21 -0
  175. package/dist/universal/.pi/agent/skills/citable/schemas/research-dataset.schema.json +27 -0
  176. package/dist/universal/.pi/agent/skills/citable/schemas/run.schema.json +15 -2
  177. package/dist/universal/.pi/agent/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  178. package/dist/universal/.pi/agent/skills/citable/schemas/search-report.schema.json +8 -1
  179. package/dist/universal/.pi/agent/skills/citable/schemas/summary.schema.json +41 -0
  180. package/dist/universal/.qoder/skills/citable/SKILL.md +11 -2
  181. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  182. package/dist/universal/.qoder/skills/citable/manifest.json +24 -12
  183. package/dist/universal/.qoder/skills/citable/schemas/action-plan.schema.json +38 -1
  184. package/dist/universal/.qoder/skills/citable/schemas/audit-coverage.schema.json +118 -0
  185. package/dist/universal/.qoder/skills/citable/schemas/claim-evidence.schema.json +21 -0
  186. package/dist/universal/.qoder/skills/citable/schemas/claim-verification.schema.json +18 -0
  187. package/dist/universal/.qoder/skills/citable/schemas/collection-result.schema.json +35 -0
  188. package/dist/universal/.qoder/skills/citable/schemas/config.schema.json +2 -0
  189. package/dist/universal/.qoder/skills/citable/schemas/cro-report.schema.json +8 -1
  190. package/dist/universal/.qoder/skills/citable/schemas/derivation.schema.json +18 -0
  191. package/dist/universal/.qoder/skills/citable/schemas/external-comparison.schema.json +16 -0
  192. package/dist/universal/.qoder/skills/citable/schemas/external-observation.schema.json +32 -0
  193. package/dist/universal/.qoder/skills/citable/schemas/finding.schema.json +105 -2
  194. package/dist/universal/.qoder/skills/citable/schemas/prompt-set.schema.json +47 -0
  195. package/dist/universal/.qoder/skills/citable/schemas/remediation-verification.schema.json +12 -1
  196. package/dist/universal/.qoder/skills/citable/schemas/representation-data.schema.json +21 -0
  197. package/dist/universal/.qoder/skills/citable/schemas/research-dataset.schema.json +27 -0
  198. package/dist/universal/.qoder/skills/citable/schemas/run.schema.json +15 -2
  199. package/dist/universal/.qoder/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  200. package/dist/universal/.qoder/skills/citable/schemas/search-report.schema.json +8 -1
  201. package/dist/universal/.qoder/skills/citable/schemas/summary.schema.json +41 -0
  202. package/dist/universal/.rovodev/skills/citable/SKILL.md +11 -2
  203. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  204. package/dist/universal/.rovodev/skills/citable/manifest.json +24 -12
  205. package/dist/universal/.rovodev/skills/citable/schemas/action-plan.schema.json +38 -1
  206. package/dist/universal/.rovodev/skills/citable/schemas/audit-coverage.schema.json +118 -0
  207. package/dist/universal/.rovodev/skills/citable/schemas/claim-evidence.schema.json +21 -0
  208. package/dist/universal/.rovodev/skills/citable/schemas/claim-verification.schema.json +18 -0
  209. package/dist/universal/.rovodev/skills/citable/schemas/collection-result.schema.json +35 -0
  210. package/dist/universal/.rovodev/skills/citable/schemas/config.schema.json +2 -0
  211. package/dist/universal/.rovodev/skills/citable/schemas/cro-report.schema.json +8 -1
  212. package/dist/universal/.rovodev/skills/citable/schemas/derivation.schema.json +18 -0
  213. package/dist/universal/.rovodev/skills/citable/schemas/external-comparison.schema.json +16 -0
  214. package/dist/universal/.rovodev/skills/citable/schemas/external-observation.schema.json +32 -0
  215. package/dist/universal/.rovodev/skills/citable/schemas/finding.schema.json +105 -2
  216. package/dist/universal/.rovodev/skills/citable/schemas/prompt-set.schema.json +47 -0
  217. package/dist/universal/.rovodev/skills/citable/schemas/remediation-verification.schema.json +12 -1
  218. package/dist/universal/.rovodev/skills/citable/schemas/representation-data.schema.json +21 -0
  219. package/dist/universal/.rovodev/skills/citable/schemas/research-dataset.schema.json +27 -0
  220. package/dist/universal/.rovodev/skills/citable/schemas/run.schema.json +15 -2
  221. package/dist/universal/.rovodev/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  222. package/dist/universal/.rovodev/skills/citable/schemas/search-report.schema.json +8 -1
  223. package/dist/universal/.rovodev/skills/citable/schemas/summary.schema.json +41 -0
  224. package/dist/universal/.trae/skills/citable/SKILL.md +11 -2
  225. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  226. package/dist/universal/.trae/skills/citable/manifest.json +24 -12
  227. package/dist/universal/.trae/skills/citable/schemas/action-plan.schema.json +38 -1
  228. package/dist/universal/.trae/skills/citable/schemas/audit-coverage.schema.json +118 -0
  229. package/dist/universal/.trae/skills/citable/schemas/claim-evidence.schema.json +21 -0
  230. package/dist/universal/.trae/skills/citable/schemas/claim-verification.schema.json +18 -0
  231. package/dist/universal/.trae/skills/citable/schemas/collection-result.schema.json +35 -0
  232. package/dist/universal/.trae/skills/citable/schemas/config.schema.json +2 -0
  233. package/dist/universal/.trae/skills/citable/schemas/cro-report.schema.json +8 -1
  234. package/dist/universal/.trae/skills/citable/schemas/derivation.schema.json +18 -0
  235. package/dist/universal/.trae/skills/citable/schemas/external-comparison.schema.json +16 -0
  236. package/dist/universal/.trae/skills/citable/schemas/external-observation.schema.json +32 -0
  237. package/dist/universal/.trae/skills/citable/schemas/finding.schema.json +105 -2
  238. package/dist/universal/.trae/skills/citable/schemas/prompt-set.schema.json +47 -0
  239. package/dist/universal/.trae/skills/citable/schemas/remediation-verification.schema.json +12 -1
  240. package/dist/universal/.trae/skills/citable/schemas/representation-data.schema.json +21 -0
  241. package/dist/universal/.trae/skills/citable/schemas/research-dataset.schema.json +27 -0
  242. package/dist/universal/.trae/skills/citable/schemas/run.schema.json +15 -2
  243. package/dist/universal/.trae/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  244. package/dist/universal/.trae/skills/citable/schemas/search-report.schema.json +8 -1
  245. package/dist/universal/.trae/skills/citable/schemas/summary.schema.json +41 -0
  246. package/dist/universal/.trae-cn/skills/citable/SKILL.md +11 -2
  247. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  248. package/dist/universal/.trae-cn/skills/citable/manifest.json +24 -12
  249. package/dist/universal/.trae-cn/skills/citable/schemas/action-plan.schema.json +38 -1
  250. package/dist/universal/.trae-cn/skills/citable/schemas/audit-coverage.schema.json +118 -0
  251. package/dist/universal/.trae-cn/skills/citable/schemas/claim-evidence.schema.json +21 -0
  252. package/dist/universal/.trae-cn/skills/citable/schemas/claim-verification.schema.json +18 -0
  253. package/dist/universal/.trae-cn/skills/citable/schemas/collection-result.schema.json +35 -0
  254. package/dist/universal/.trae-cn/skills/citable/schemas/config.schema.json +2 -0
  255. package/dist/universal/.trae-cn/skills/citable/schemas/cro-report.schema.json +8 -1
  256. package/dist/universal/.trae-cn/skills/citable/schemas/derivation.schema.json +18 -0
  257. package/dist/universal/.trae-cn/skills/citable/schemas/external-comparison.schema.json +16 -0
  258. package/dist/universal/.trae-cn/skills/citable/schemas/external-observation.schema.json +32 -0
  259. package/dist/universal/.trae-cn/skills/citable/schemas/finding.schema.json +105 -2
  260. package/dist/universal/.trae-cn/skills/citable/schemas/prompt-set.schema.json +47 -0
  261. package/dist/universal/.trae-cn/skills/citable/schemas/remediation-verification.schema.json +12 -1
  262. package/dist/universal/.trae-cn/skills/citable/schemas/representation-data.schema.json +21 -0
  263. package/dist/universal/.trae-cn/skills/citable/schemas/research-dataset.schema.json +27 -0
  264. package/dist/universal/.trae-cn/skills/citable/schemas/run.schema.json +15 -2
  265. package/dist/universal/.trae-cn/skills/citable/schemas/search-discovery-data.schema.json +20 -0
  266. package/dist/universal/.trae-cn/skills/citable/schemas/search-report.schema.json +8 -1
  267. package/dist/universal/.trae-cn/skills/citable/schemas/summary.schema.json +41 -0
  268. package/dist/universal/manifest.json +292 -148
  269. package/package.json +1 -1
  270. package/schemas/action-plan.schema.json +38 -1
  271. package/schemas/audit-coverage.schema.json +118 -0
  272. package/schemas/claim-evidence.schema.json +21 -0
  273. package/schemas/claim-verification.schema.json +18 -0
  274. package/schemas/collection-result.schema.json +35 -0
  275. package/schemas/config.schema.json +2 -0
  276. package/schemas/cro-report.schema.json +8 -1
  277. package/schemas/derivation.schema.json +18 -0
  278. package/schemas/external-comparison.schema.json +16 -0
  279. package/schemas/external-observation.schema.json +32 -0
  280. package/schemas/finding.schema.json +105 -2
  281. package/schemas/prompt-set.schema.json +47 -0
  282. package/schemas/remediation-verification.schema.json +12 -1
  283. package/schemas/representation-data.schema.json +21 -0
  284. package/schemas/research-dataset.schema.json +27 -0
  285. package/schemas/run.schema.json +15 -2
  286. package/schemas/search-discovery-data.schema.json +20 -0
  287. package/schemas/search-report.schema.json +8 -1
  288. package/schemas/summary.schema.json +41 -0
  289. package/skill/SKILL.md +11 -2
  290. package/src/acceptance/reproducibility.js +5 -25
  291. package/src/analysis/croRoadmap.js +3 -3
  292. package/src/analysis/strategicRoadmap.js +3 -3
  293. package/src/artifacts/interchange.js +2 -6
  294. package/src/cli/index.js +15 -3
  295. package/src/commands/actionPlan.js +46 -5
  296. package/src/commands/applyRemediation.js +5 -5
  297. package/src/commands/audit.js +75 -8
  298. package/src/commands/ciWorkflow.js +7 -2
  299. package/src/commands/compareSnapshots.js +155 -47
  300. package/src/commands/connect.js +24 -4
  301. package/src/commands/context.js +41 -2
  302. package/src/commands/croSuite.js +51 -13
  303. package/src/commands/delivery.js +7 -7
  304. package/src/commands/governance.js +9 -10
  305. package/src/commands/implementationKit.js +2 -1
  306. package/src/commands/init.js +8 -1
  307. package/src/commands/previewCro.js +1 -1
  308. package/src/commands/prioritize.js +3 -2
  309. package/src/commands/reviews.js +31 -5
  310. package/src/commands/roadmapCmd.js +7 -13
  311. package/src/commands/sweep.js +15 -2
  312. package/src/commands/verifyRemediation.js +94 -19
  313. package/src/connectors/collectionResult.js +80 -0
  314. package/src/connectors/ga4.js +46 -11
  315. package/src/connectors/gsc.js +45 -6
  316. package/src/connectors/index.js +1 -1
  317. package/src/connectors/webflow.js +140 -10
  318. package/src/connectors/wordpress.js +92 -8
  319. package/src/crawler/fetch.js +220 -24
  320. package/src/crawler/resourceValidity.js +119 -0
  321. package/src/crawler/sitemap.js +435 -16
  322. package/src/crawler/sitemapCollector.js +364 -0
  323. package/src/crawler/urlIdentity.js +97 -0
  324. package/src/detectors/agent.js +11 -0
  325. package/src/detectors/ans.js +16 -1
  326. package/src/detectors/arch.js +6 -0
  327. package/src/detectors/claim.js +9 -0
  328. package/src/detectors/crawl.js +7 -0
  329. package/src/detectors/cro.js +21 -0
  330. package/src/detectors/cwv.js +4 -0
  331. package/src/detectors/entity.js +7 -0
  332. package/src/detectors/evd.js +9 -0
  333. package/src/detectors/framework.js +28 -2
  334. package/src/detectors/geoReco.js +16 -0
  335. package/src/detectors/hreflang.js +3 -0
  336. package/src/detectors/lifeMeas.js +9 -0
  337. package/src/detectors/link.js +6 -1
  338. package/src/detectors/page.js +11 -0
  339. package/src/detectors/schemaData.js +16 -1
  340. package/src/detectors/tech.js +34 -3
  341. package/src/discovery/searchConsole.js +186 -0
  342. package/src/evidence/coverage.js +448 -0
  343. package/src/evidence/determination.js +157 -0
  344. package/src/evidence/downstream.js +110 -0
  345. package/src/evidence/external.js +251 -0
  346. package/src/evidence/hashes.js +109 -0
  347. package/src/evidence/run.js +68 -8
  348. package/src/extractor/page.js +29 -2
  349. package/src/extractor/site.js +298 -50
  350. package/src/reporting/executiveCroReport.js +36 -13
  351. package/src/reporting/executiveExport.js +45 -16
  352. package/src/reporting/executiveSearchReport.js +56 -22
  353. package/src/reporting/report.js +56 -9
  354. package/src/representation/prompts.js +117 -0
  355. package/src/representation/representation.js +186 -0
  356. package/src/shared/epistemicLanguage.js +86 -0
  357. package/src/shared/evidenceSourceResolver.js +48 -17
  358. package/src/shared/htmlEscape.js +8 -4
  359. package/src/shared/runPackageVerifier.js +99 -8
  360. package/src/shared/verifiedRunLoader.js +129 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Shared semantics for consumers that summarize or act on an evidence package.
3
+ * A consumer may describe the evaluated subset, but may not widen it to the
4
+ * requested scope when collection was incomplete or empty.
5
+ */
6
+ const DETERMINATION_STATUSES = new Set(['supported', 'qualified', 'indeterminate', 'not_applicable']);
7
+ import { validateAgainst } from '../shared/schemaValidator.js';
8
+
9
+ function populations(coverage) {
10
+ return coverage?.populations && typeof coverage.populations === 'object'
11
+ ? coverage.populations : {};
12
+ }
13
+
14
+ function contractStatus(coverage) {
15
+ if (!coverage || typeof coverage !== 'object') return { valid: false, errors: ['coverage artifact unavailable'] };
16
+ const result = validateAgainst('audit-coverage.schema.json', coverage);
17
+ return { valid: result.valid, errors: result.errors || [] };
18
+ }
19
+
20
+ export function coverageDenominator(coverage) {
21
+ const value = populations(coverage).evaluated;
22
+ return Number.isInteger(value) && value > 0 ? value : 0;
23
+ }
24
+
25
+ export function completeLocalCoverage(pages, baseUrl = 'https://example.test') {
26
+ const origin = new URL(baseUrl).origin;
27
+ const resources = pages.map((page, index) => ({
28
+ resource_id: `LOCAL-${index + 1}`,
29
+ normalized_url: page.url || `${origin}/page-${index + 1}`,
30
+ original_urls: [page.url || `${origin}/page-${index + 1}`],
31
+ state: 'evaluated',
32
+ evaluation: {},
33
+ }));
34
+ const n = resources.length;
35
+ return {
36
+ schema_version: 1,
37
+ normalization_version: 'url-identity-v1',
38
+ requested_scope: { start_url: `${origin}/`, origin, max_pages: 500, time_budget_seconds: 1800 },
39
+ discovery: { status: 'complete', methods: ['built_output'], limitations: [] },
40
+ populations: { discovered: n, eligible: n, excluded: 0, attempted: n, retrieved: n, valid_resource: n, evaluated: n, valid_but_unevaluated: 0, failed: 0, indeterminate: 0, unvisited: 0 },
41
+ resources,
42
+ stop_reason: 'frontier_exhausted',
43
+ coverage_status: 'complete',
44
+ reconciliation: { valid: true, errors: [] },
45
+ limitations: [],
46
+ };
47
+ }
48
+
49
+ export function downstreamStatus(coverage) {
50
+ if (!coverage) return 'indeterminate';
51
+ const contract = contractStatus(coverage);
52
+ const denominator = coverageDenominator(coverage);
53
+ const p = populations(coverage);
54
+ const completePopulation = p.failed === 0 && p.indeterminate === 0 && p.unvisited === 0 && p.valid_but_unevaluated === 0;
55
+ if (coverage.coverage_status === 'complete' && denominator > 0 && completePopulation && contract.valid && coverage.reconciliation?.valid === true) return 'supported';
56
+ if (coverage.coverage_status === 'truncated' && denominator > 0
57
+ && contract.valid && coverage.reconciliation?.valid === true) return 'qualified';
58
+ return 'indeterminate';
59
+ }
60
+
61
+ export function coverageLimitations(coverage) {
62
+ if (!coverage) return ['coverage artifact unavailable; scope is not established'];
63
+ const p = populations(coverage);
64
+ const limitations = Array.isArray(coverage.limitations) ? [...coverage.limitations] : [];
65
+ const contract = contractStatus(coverage);
66
+ if (!contract.valid) limitations.push('coverage artifact does not satisfy the coverage contract');
67
+ if (coverage.coverage_status !== 'complete') {
68
+ limitations.push(`coverage is ${coverage.coverage_status || 'unknown'}; conclusions are limited to evaluated resources`);
69
+ }
70
+ for (const key of ['failed', 'indeterminate', 'unvisited', 'valid_but_unevaluated']) {
71
+ if (Number.isInteger(p[key]) && p[key] > 0) limitations.push(`${p[key]} ${key} resource(s) omitted from determinations`);
72
+ }
73
+ return [...new Set(limitations)];
74
+ }
75
+
76
+ export function downstreamEnvelope(coverage, extra = {}) {
77
+ const p = populations(coverage);
78
+ const denominator = coverageDenominator(coverage);
79
+ const status = downstreamStatus(coverage);
80
+ if (!DETERMINATION_STATUSES.has(status)) throw new Error(`invalid downstream determination status: ${status}`);
81
+ return {
82
+ coverage_status: coverage?.coverage_status || 'indeterminate',
83
+ determination_status: status,
84
+ evidence_scope: {
85
+ requirement: 'evaluated_subset',
86
+ satisfaction: status,
87
+ coverage_ref: coverage ? 'coverage.json' : null,
88
+ resource_ids: Array.isArray(coverage?.resources)
89
+ ? coverage.resources.map((resource) => resource.resource_id).filter(Boolean)
90
+ : [],
91
+ population: denominator > 0 ? 'evaluated_subset' : 'none_observed',
92
+ evaluated: denominator,
93
+ eligible: Number.isInteger(p.eligible) ? p.eligible : null,
94
+ excluded: Number.isInteger(p.excluded) ? p.excluded : null,
95
+ failed: Number.isInteger(p.failed) ? p.failed : null,
96
+ indeterminate: Number.isInteger(p.indeterminate) ? p.indeterminate : null,
97
+ unvisited: Number.isInteger(p.unvisited) ? p.unvisited : null,
98
+ denominator,
99
+ },
100
+ limitations: coverageLimitations(coverage),
101
+ ...extra,
102
+ };
103
+ }
104
+
105
+ /** Return null for empty evidence; never divide by a convenient zero. */
106
+ export function scoreFromCoverage(numerator, coverage, { scale = 100 } = {}) {
107
+ const denominator = coverageDenominator(coverage);
108
+ if (!Number.isFinite(numerator) || denominator === 0) return null;
109
+ return Math.round((numerator / denominator) * scale);
110
+ }
@@ -0,0 +1,251 @@
1
+ import { canonicalEvidenceJson, createEvidenceHashes } from './hashes.js';
2
+ import { sha256 } from '../shared/io.js';
3
+ import { validateAgainst } from '../shared/schemaValidator.js';
4
+
5
+ const OBSERVATION_SCHEMA = 'external-observation.schema.json';
6
+ const DATASET_SCHEMA = 'research-dataset.schema.json';
7
+ const DERIVATION_SCHEMA = 'derivation.schema.json';
8
+ const CLAIM_SCHEMA = 'claim-evidence.schema.json';
9
+ const COMPARISON_SCHEMA = 'external-comparison.schema.json';
10
+ const VERIFICATION_SCHEMA = 'claim-verification.schema.json';
11
+
12
+ function without(value, key) {
13
+ const copy = { ...value };
14
+ delete copy[key];
15
+ return copy;
16
+ }
17
+
18
+ function integrity(value, key) {
19
+ return sha256(canonicalEvidenceJson(without(value, key)));
20
+ }
21
+
22
+ function validate(schema, value, label) {
23
+ const result = validateAgainst(schema, value);
24
+ if (!result.valid) throw new Error(`${label} violates contract: ${result.errors.join('; ')}`);
25
+ return value;
26
+ }
27
+
28
+ export function createExternalObservation(input) {
29
+ const item = { ...input };
30
+ item.evidence_hash = integrity(item, 'evidence_hash');
31
+ return validate(OBSERVATION_SCHEMA, item, 'external observation');
32
+ }
33
+
34
+ export function verifyExternalObservation(item) {
35
+ const failures = [];
36
+ const check = validateAgainst(OBSERVATION_SCHEMA, item);
37
+ if (!check.valid) failures.push(...check.errors);
38
+ if (item?.evidence_hash !== integrity(item || {}, 'evidence_hash')) failures.push('evidence hash is inconsistent');
39
+ return { valid: failures.length === 0, failures };
40
+ }
41
+
42
+ export function createResearchDataset(input, { previous = null } = {}) {
43
+ const item = { ...input };
44
+ item.dataset_hash = integrity(item, 'dataset_hash');
45
+ validate(DATASET_SCHEMA, item, 'research dataset');
46
+ if (previous && previous.dataset_id === item.dataset_id && previous.dataset_version === item.dataset_version
47
+ && previous.dataset_hash !== item.dataset_hash) {
48
+ throw new Error('research dataset version is immutable; create a new dataset_version');
49
+ }
50
+ return item;
51
+ }
52
+
53
+ export function verifyResearchDataset(item, { previous = null } = {}) {
54
+ const failures = [];
55
+ const check = validateAgainst(DATASET_SCHEMA, item);
56
+ if (!check.valid) failures.push(...check.errors);
57
+ if (item?.dataset_hash !== integrity(item || {}, 'dataset_hash')) failures.push('dataset hash is inconsistent');
58
+ if (previous && previous.dataset_id === item?.dataset_id && previous.dataset_version === item?.dataset_version
59
+ && previous.dataset_hash !== item?.dataset_hash) failures.push('research dataset version is immutable');
60
+ if (failures.length) throw new Error(`research dataset verification failed: ${failures.join('; ')}`);
61
+ return { valid: true, failures: [] };
62
+ }
63
+
64
+ export function createDerivation(input) {
65
+ const item = { ...input };
66
+ item.derivation_hash = integrity(item, 'derivation_hash');
67
+ return validate(DERIVATION_SCHEMA, item, 'derivation');
68
+ }
69
+
70
+ function verifyDerivation(item) {
71
+ const check = validateAgainst(DERIVATION_SCHEMA, item);
72
+ if (!check.valid || item.derivation_hash !== integrity(item, 'derivation_hash')) return false;
73
+ return true;
74
+ }
75
+
76
+ export function createEvidenceClaim(input) {
77
+ const item = { ...input };
78
+ item.claim_hash = integrity(item, 'claim_hash');
79
+ return validate(CLAIM_SCHEMA, item, 'claim evidence');
80
+ }
81
+
82
+ function verifyClaimIdentity(item) {
83
+ const check = validateAgainst(CLAIM_SCHEMA, item);
84
+ return check.valid && item.claim_hash === integrity(item, 'claim_hash');
85
+ }
86
+
87
+ function valueAt(object, path) {
88
+ return String(path).split('.').reduce((value, key) => value == null ? undefined : value[key], object);
89
+ }
90
+
91
+ function reason(code, message) {
92
+ return { code, message };
93
+ }
94
+
95
+ function evaluatePredicate(assertion, observations) {
96
+ if (!observations.length) return { status: 'NOT_OBSERVED', reasons: [reason('observation_missing', 'No referenced observation was available.')] };
97
+ const results = observations.map((item) => valueAt(item, assertion.path) === assertion.value);
98
+ if (results.every(Boolean)) return { status: 'SUPPORTED', reasons: [] };
99
+ if (results.some(Boolean)) return { status: 'PARTIALLY_SUPPORTED', reasons: [reason('predicate_partial', 'The predicate matched only part of the referenced population.')] };
100
+ return { status: 'CONTRADICTED', reasons: [reason('predicate_contradicted', 'In-scope evidence establishes an incompatible predicate value.')] };
101
+ }
102
+
103
+ function evaluateAssertion(assertion, observations, derivations) {
104
+ if (!assertion || typeof assertion !== 'object') return { status: 'INDETERMINATE', reasons: [reason('assertion_missing', 'The claim has no structured assertion.')] };
105
+ if (assertion.type === 'predicate' || assertion.type === 'all') return evaluatePredicate(assertion, observations);
106
+ if (assertion.type === 'count') {
107
+ const derivation = derivations[0];
108
+ if (!derivation || !verifyDerivation(derivation)) return { status: 'INDETERMINATE', reasons: [reason('derivation_unavailable', 'The referenced derivation is missing or unverifiable.')] };
109
+ if (derivation.result?.count === assertion.expected) return { status: 'SUPPORTED', reasons: [] };
110
+ return { status: 'CONTRADICTED', reasons: [reason('count_contradicted', 'The preserved derivation result differs from the claimed value.')] };
111
+ }
112
+ if (assertion.type === 'compound') {
113
+ const results = (assertion.assertions || []).map((part) => evaluateAssertion(part, observations, derivations));
114
+ if (!results.length) return { status: 'INDETERMINATE', reasons: [reason('compound_empty', 'The compound claim has no components.')] };
115
+ const reasons = results.flatMap((item) => item.reasons);
116
+ if (results.every((item) => item.status === 'SUPPORTED')) return { status: 'SUPPORTED', reasons };
117
+ if (results.some((item) => item.status === 'CONTRADICTED')) return { status: 'PARTIALLY_SUPPORTED', reasons: [...reasons, reason('compound_component_unsupported', 'At least one compound component is contradicted.')] };
118
+ if (results.some((item) => item.status === 'SUPPORTED')) return { status: 'PARTIALLY_SUPPORTED', reasons: [...reasons, reason('compound_component_unsupported', 'At least one compound component is unsupported.')] };
119
+ return { status: results.some((item) => item.status === 'NOT_OBSERVED') ? 'NOT_OBSERVED' : 'UNSUPPORTED', reasons };
120
+ }
121
+ return { status: 'INDETERMINATE', reasons: [reason('assertion_unsupported', `Assertion type ${assertion.type || 'unknown'} is not supported.`)] };
122
+ }
123
+
124
+ function scopeSupport(claim, datasets, observations) {
125
+ const scope = claim.declared_scope;
126
+ if (scope.generalization === 'universal') return { status: 'UNSUPPORTED', reasons: [reason('generalization_outside_population', 'The evidence population does not support a universal claim.')] };
127
+ if (scope.type === 'observation' && scope.observation_reference
128
+ && !(claim.observation_references || []).includes(scope.observation_reference)) {
129
+ return { status: 'INDETERMINATE', reasons: [reason('scope_reference_mismatch', 'The declared observation scope is not among the claim evidence references.')] };
130
+ }
131
+ if (scope.type === 'dataset' && scope.dataset_reference
132
+ && !(claim.dataset_references || []).includes(scope.dataset_reference)) {
133
+ return { status: 'INDETERMINATE', reasons: [reason('scope_reference_mismatch', 'The declared dataset scope is not among the claim evidence references.')] };
134
+ }
135
+ if (scope.type === 'dataset') {
136
+ const dataset = datasets[0];
137
+ if (!dataset || !verifyDatasetSafe(dataset)) return { status: 'INDETERMINATE', reasons: [reason('dataset_unavailable', 'The declared dataset is missing or unverifiable.')] };
138
+ if (dataset.coverage_status !== 'complete_for_declared_population') return { status: 'PARTIALLY_SUPPORTED', reasons: [reason('dataset_coverage_incomplete', `Dataset coverage is ${dataset.coverage_status}, not complete for the declared population.`)] };
139
+ const referenced = new Set(claim.observation_references || []);
140
+ const missingMembers = (dataset.observation_references || []).filter((id) => !referenced.has(id));
141
+ if (missingMembers.length) return { status: 'PARTIALLY_SUPPORTED', reasons: [reason('dataset_members_missing', `The claim does not reference every observation in the declared dataset: ${missingMembers.join(', ')}`)] };
142
+ }
143
+ if (!observations.length) return { status: 'NOT_OBSERVED', reasons: [reason('observation_missing', 'The declared scope has no observed members.')] };
144
+ return { status: 'SUPPORTED', reasons: [] };
145
+ }
146
+
147
+ function verifyDatasetSafe(dataset) {
148
+ try { return verifyResearchDataset(dataset).valid; } catch { return false; }
149
+ }
150
+
151
+ function datasetReference(dataset) {
152
+ return `${dataset.dataset_id}@${dataset.dataset_version}`;
153
+ }
154
+
155
+ function resolveDatasetReference(reference, datasets) {
156
+ const exact = datasets.filter((item) => datasetReference(item) === reference);
157
+ if (exact.length === 1) return exact[0];
158
+ // Legacy id-only references remain valid only while the id has one version.
159
+ // Once versions diverge, silently selecting one would rewrite historical
160
+ // claim meaning.
161
+ if (!String(reference).includes('@')) {
162
+ const byId = datasets.filter((item) => item.dataset_id === reference);
163
+ return byId.length === 1 ? byId[0] : null;
164
+ }
165
+ return null;
166
+ }
167
+
168
+ function combine(proposition, scope) {
169
+ if (proposition.status === 'NOT_OBSERVED') return 'NOT_OBSERVED';
170
+ if (proposition.status === 'INDETERMINATE' || scope.status === 'INDETERMINATE') return 'INDETERMINATE';
171
+ if (proposition.status === 'CONTRADICTED') return 'CONTRADICTED';
172
+ if (proposition.status === 'PARTIALLY_SUPPORTED' || scope.status === 'PARTIALLY_SUPPORTED' || scope.status === 'UNSUPPORTED') return 'PARTIALLY_SUPPORTED';
173
+ if (proposition.status === 'UNSUPPORTED') return 'UNSUPPORTED';
174
+ return 'SUPPORTED';
175
+ }
176
+
177
+ export function verifyClaim(claim, { observations = [], datasets = [], derivations = [] } = {}) {
178
+ if (!verifyClaimIdentity(claim)) {
179
+ return {
180
+ claim_id: claim?.claim_id || 'unknown', claim_version: claim?.claim_version || 1,
181
+ overall: 'INDETERMINATE', proposition_support: 'INDETERMINATE', scope_support: 'INDETERMINATE',
182
+ reasons: [reason('claim_unverifiable', 'Claim identity, schema, or integrity hash could not be verified.')],
183
+ lineage: { claim_reference: claim?.claim_id || 'unknown', observation_references: claim?.observation_references || [], dataset_references: claim?.dataset_references || [], derivation_references: claim?.derivation_references || [] }, limitations: ['Claim evidence could not be verified.'],
184
+ };
185
+ }
186
+ const byId = new Map(observations.map((item) => [item.observation_id, item]));
187
+ const referenced = (claim.observation_references || []).map((id) => byId.get(id)).filter(Boolean);
188
+ const missing = (claim.observation_references || []).filter((id) => !byId.has(id));
189
+ const integrityFailure = referenced.some((item) => !verifyExternalObservation(item).valid);
190
+ let proposition;
191
+ if (integrityFailure) proposition = { status: 'INDETERMINATE', reasons: [reason('evidence_unverifiable', 'Referenced observation integrity verification failed.')] };
192
+ else if (missing.length) proposition = { status: 'NOT_OBSERVED', reasons: [reason('observation_missing', `Missing referenced observations: ${missing.join(', ')}`)] };
193
+ else proposition = evaluateAssertion(claim.assertion, referenced, (claim.derivation_references || []).map((id) => derivations.find((item) => item.derivation_id === id)).filter(Boolean));
194
+ const selectedDatasets = (claim.dataset_references || []).map((reference) => resolveDatasetReference(reference, datasets)).filter(Boolean);
195
+ const missingDatasets = (claim.dataset_references || []).filter((reference) => !resolveDatasetReference(reference, datasets));
196
+ const scope = scopeSupport(claim, selectedDatasets, referenced);
197
+ if (missingDatasets.length && claim.declared_scope.type === 'dataset') {
198
+ scope.status = 'INDETERMINATE';
199
+ scope.reasons.push(reason('dataset_reference_ambiguous_or_missing', `Dataset references could not be resolved exactly: ${missingDatasets.join(', ')}`));
200
+ }
201
+ const result = {
202
+ claim_id: claim.claim_id, claim_version: claim.claim_version, overall: combine(proposition, scope),
203
+ proposition_support: proposition.status, scope_support: scope.status,
204
+ reasons: [...proposition.reasons, ...scope.reasons],
205
+ lineage: { claim_reference: claim.claim_id, observation_references: claim.observation_references || [], dataset_references: claim.dataset_references || [], derivation_references: claim.derivation_references || [] },
206
+ limitations: claim.limitations || [],
207
+ };
208
+ return validate(VERIFICATION_SCHEMA, result, 'claim verification');
209
+ }
210
+
211
+ const COMPARISON_DIMENSIONS = ['source', 'subject', 'collector', 'parser', 'configuration', 'population', 'normalization', 'dataset_version', 'derivation_version'];
212
+
213
+ function dimensionValue(item, dimension) {
214
+ if (dimension === 'source') return item.source?.provider;
215
+ if (dimension === 'subject') return item.subject?.id;
216
+ if (dimension === 'collector') return `${item.collector?.id || ''}@${item.collector?.version || ''}` || null;
217
+ if (dimension === 'parser') return item.parser ? `${item.parser.id}@${item.parser.version}` : null;
218
+ if (dimension === 'configuration') return item.configuration ? `${item.configuration.id}@${item.configuration.version}` : null;
219
+ if (dimension === 'population') return item.population?.declared?.id || item.declared_population?.id;
220
+ if (dimension === 'normalization') return item.normalization ? `${item.normalization.method}@${item.normalization.version}` : null;
221
+ if (dimension === 'dataset_version') return item.dataset_id ? `${item.dataset_id}@${item.dataset_version}` : null;
222
+ if (dimension === 'derivation_version') return item.derivation_id ? `${item.derivation_id}@${item.derivation_version}` : null;
223
+ return null;
224
+ }
225
+
226
+ function compareItems(left, right, leftReference, rightReference, dimensionsToCompare = COMPARISON_DIMENSIONS) {
227
+ const dimensions = {};
228
+ for (const key of dimensionsToCompare) {
229
+ const a = dimensionValue(left, key); const b = dimensionValue(right, key);
230
+ dimensions[key] = a == null || b == null ? 'missing' : a === b ? 'match' : 'mismatch';
231
+ }
232
+ const mismatches = Object.values(dimensions).filter((x) => x === 'mismatch').length;
233
+ const missing = Object.values(dimensions).filter((x) => x === 'missing').length;
234
+ const status = mismatches ? 'NOT_COMPARABLE' : missing ? 'PARTIALLY_COMPARABLE' : 'COMPARABLE';
235
+ const result = { comparison_id: `CMP-${sha256(canonicalEvidenceJson({ leftReference, rightReference, dimensions })).slice(0, 16)}`, left_reference: leftReference, right_reference: rightReference, status, dimensions, limitations: status === 'COMPARABLE' ? [] : ['No delta should be generalized beyond the aligned dimensions.'] };
236
+ return validate(COMPARISON_SCHEMA, result, 'external comparison');
237
+ }
238
+
239
+ export function compareExternalObservations(left, right) {
240
+ if (!verifyExternalObservation(left).valid || !verifyExternalObservation(right).valid) {
241
+ return { comparison_id: `CMP-${sha256(`${left?.observation_id || ''}:${right?.observation_id || ''}`).slice(0, 16)}`, left_reference: left?.observation_id || 'unknown', right_reference: right?.observation_id || 'unknown', status: 'INDETERMINATE', dimensions: {}, limitations: ['Observation integrity could not be verified.'] };
242
+ }
243
+ return compareItems(left, right, left.observation_id, right.observation_id,
244
+ ['source', 'subject', 'collector', 'parser', 'configuration', 'population']);
245
+ }
246
+
247
+ export function compareResearchDatasets(left, right) {
248
+ if (!verifyDatasetSafe(left) || !verifyDatasetSafe(right)) return { comparison_id: 'CMP-invalid', left_reference: left?.dataset_id || 'unknown', right_reference: right?.dataset_id || 'unknown', status: 'INDETERMINATE', dimensions: {}, limitations: ['Dataset integrity could not be verified.'] };
249
+ return compareItems(left, right, `${left.dataset_id}@${left.dataset_version}`, `${right.dataset_id}@${right.dataset_version}`,
250
+ ['dataset_version', 'normalization', 'population']);
251
+ }
@@ -0,0 +1,109 @@
1
+ import { sha256 } from '../shared/io.js';
2
+
3
+ export const EVIDENCE_HASH_SCHEMA_VERSION = 'evidence-hashes-v1';
4
+
5
+ /**
6
+ * Canonical JSON used for evidence representations. Object key order is not
7
+ * evidence; array order is preserved because it can be meaningful (for
8
+ * example, JSON-LD graph order and an evaluator's finding order).
9
+ */
10
+ export function canonicalEvidenceJson(value) {
11
+ if (Array.isArray(value)) return `[${value.map(canonicalEvidenceJson).join(',')}]`;
12
+ if (value && typeof value === 'object') {
13
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalEvidenceJson(value[key])}`).join(',')}}`;
14
+ }
15
+ return JSON.stringify(value);
16
+ }
17
+
18
+ function bytes(value) {
19
+ if (Buffer.isBuffer(value)) return value;
20
+ if (value instanceof Uint8Array) return Buffer.from(value);
21
+ return Buffer.from(String(value ?? ''), 'utf8');
22
+ }
23
+
24
+ function hashBytes(value) {
25
+ return sha256(bytes(value));
26
+ }
27
+
28
+ function hashCanonical(value) {
29
+ return sha256(canonicalEvidenceJson(value));
30
+ }
31
+
32
+ /** Normalize only extraction whitespace; do not remove content or metadata. */
33
+ export function normalizeExtractedText(value) {
34
+ return String(value ?? '').replace(/\s+/g, ' ').trim();
35
+ }
36
+
37
+ /**
38
+ * Build named hashes for representations that are actually available.
39
+ * Null means that representation was not observed; it is never synthesized
40
+ * from another layer.
41
+ */
42
+ export function createEvidenceHashes({
43
+ responseBody,
44
+ extractedText,
45
+ structuredData,
46
+ renderedDom,
47
+ evidence,
48
+ artifact,
49
+ } = {}) {
50
+ return {
51
+ hash_schema_version: EVIDENCE_HASH_SCHEMA_VERSION,
52
+ response_body_hash: responseBody == null ? null : hashBytes(responseBody),
53
+ rendered_dom_hash: renderedDom == null ? null : hashBytes(renderedDom),
54
+ extracted_text_hash: extractedText == null ? null : hashBytes(normalizeExtractedText(extractedText)),
55
+ structured_data_hash: structuredData == null ? null : hashCanonical(structuredData),
56
+ evidence_hash: evidence == null ? null : hashCanonical(evidence),
57
+ artifact_hash: artifact == null ? null : hashCanonical(artifact),
58
+ };
59
+ }
60
+
61
+ /** Explicit legacy meaning for snapshots and connector payloads during migration. */
62
+ export const LEGACY_CONTENT_HASH_SEMANTICS = 'extracted_text_v1';
63
+
64
+ /**
65
+ * Canonical shape of the persisted pages/index.json record. The artifact hash
66
+ * is intentionally excluded so the hash does not contain itself; verification
67
+ * recomputes this exact record shape and compares it with the stored claim.
68
+ */
69
+ export function pageArtifactRecord(page) {
70
+ return {
71
+ url: page.url,
72
+ status: page.status,
73
+ title: page.title,
74
+ canonicals: page.canonicals,
75
+ noindex: page.noindex,
76
+ wordCount: page.wordCount,
77
+ sourceFile: page.sourceFile,
78
+ requested_url: page.requestedUrl ?? null,
79
+ effective_url: page.url,
80
+ declared_canonical_url: page.canonicals?.[0] ?? null,
81
+ resource_id: page.urlIdentity?.resource_id ?? null,
82
+ url_identity: page.urlIdentity ?? null,
83
+ hash_schema_version: page.hash_schema_version ?? null,
84
+ response_body_hash: page.response_body_hash ?? null,
85
+ rendered_dom_hash: page.rendered_dom_hash ?? null,
86
+ extracted_text_hash: page.extracted_text_hash ?? null,
87
+ structured_data_hash: page.structured_data_hash ?? null,
88
+ evidence_hash: page.evidence_hash ?? null,
89
+ contentHash: page.extracted_text_hash ?? null,
90
+ hash_semantics: LEGACY_CONTENT_HASH_SEMANTICS,
91
+ };
92
+ }
93
+
94
+ export function hashPageArtifact(page) {
95
+ return hashCanonical(pageArtifactRecord(page));
96
+ }
97
+
98
+ /** Bind a determination/finding to the representation its hash actually covers. */
99
+ export function evidenceIdentity(hashes, representation) {
100
+ const field = `${representation}_hash`;
101
+ const hash = hashes?.[field];
102
+ if (!['response_body', 'rendered_dom', 'extracted_text', 'structured_data', 'evidence', 'artifact'].includes(representation)) {
103
+ throw new TypeError(`unknown evidence representation: ${representation}`);
104
+ }
105
+ if (typeof hash !== 'string' || !/^[a-f0-9]{64}$/.test(hash)) {
106
+ throw new Error(`evidence representation is unavailable: ${representation}`);
107
+ }
108
+ return { hash_schema_version: hashes.hash_schema_version ?? EVIDENCE_HASH_SCHEMA_VERSION, representation, hash };
109
+ }
@@ -23,6 +23,26 @@ function gitInfo(root) {
23
23
  }
24
24
  }
25
25
 
26
+ function assertSafeArtifactPath(runDir, relativePath) {
27
+ if (typeof relativePath !== 'string' || !relativePath || path.isAbsolute(relativePath) || relativePath.includes('\\')) {
28
+ throw new Error(`unsafe artifact path: ${relativePath}`);
29
+ }
30
+ const parts = relativePath.split('/');
31
+ if (parts.some((part) => !part || part === '.' || part === '..')) throw new Error(`unsafe artifact path: ${relativePath}`);
32
+ let current = runDir;
33
+ for (const part of parts) {
34
+ current = path.join(current, part);
35
+ if (!fs.existsSync(current)) continue;
36
+ const stat = fs.lstatSync(current);
37
+ if (stat.isSymbolicLink()) throw new Error(`artifact path contains symbolic link: ${relativePath}`);
38
+ }
39
+ }
40
+
41
+ function fsyncPath(file) {
42
+ const handle = fs.openSync(file, 'r');
43
+ try { fs.fsyncSync(handle); } finally { fs.closeSync(handle); }
44
+ }
45
+
26
46
  /** Create a run evidence package under <root>/.citable/runs/<run-id>/. */
27
47
  export function createRun(root, { command, argv = [], target, locale = process.env.LANG || 'en', jurisdiction = null, configHash = null }) {
28
48
  const runId = newRunId(command);
@@ -30,6 +50,7 @@ export function createRun(root, { command, argv = [], target, locale = process.e
30
50
  fs.mkdirSync(dir, { recursive: true });
31
51
  const git = gitInfo(root);
32
52
  const manifest = {
53
+ schema_version: 2,
33
54
  run_id: runId,
34
55
  command,
35
56
  argv,
@@ -50,6 +71,9 @@ export function createRun(root, { command, argv = [], target, locale = process.e
50
71
  errors: [],
51
72
  warnings: [],
52
73
  status: 'incomplete',
74
+ execution_status: 'completed',
75
+ coverage_status: 'not_applicable',
76
+ determination_status: 'not_applicable',
53
77
  };
54
78
  return {
55
79
  runId,
@@ -59,6 +83,7 @@ export function createRun(root, { command, argv = [], target, locale = process.e
59
83
  manifest.input_hashes[name] = sha256(typeof content === 'string' ? content : JSON.stringify(content));
60
84
  },
61
85
  writeArtifact(relPath, data) {
86
+ assertSafeArtifactPath(dir, relPath);
62
87
  const file = path.join(dir, relPath);
63
88
  fs.mkdirSync(path.dirname(file), { recursive: true });
64
89
  if (typeof data === 'string' || Buffer.isBuffer(data)) fs.writeFileSync(file, data);
@@ -70,18 +95,53 @@ export function createRun(root, { command, argv = [], target, locale = process.e
70
95
  manifest.status = status;
71
96
  const { valid, errors } = validateAgainst('run.schema.json', manifest);
72
97
  if (!valid) throw new Error(`run manifest invalid: ${errors.join('; ')}`);
73
- writeJson(path.join(dir, 'manifest.json'), manifest);
98
+ const stage = `${dir}.sealing-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
99
+ fs.rmSync(stage, { recursive: true, force: true });
100
+ fs.cpSync(dir, stage, { recursive: true, dereference: false, errorOnExist: true });
101
+ writeJson(path.join(stage, 'manifest.json'), manifest);
102
+ const summaryFile = path.join(stage, 'summary.json');
103
+ if (fs.existsSync(summaryFile)) {
104
+ // Keep the persisted ordering contract deterministic even on filesystems
105
+ // with coarse timestamp resolution or delayed copy metadata updates.
106
+ const now = new Date(Date.now() + 1000);
107
+ fs.utimesSync(summaryFile, now, now);
108
+ }
74
109
  // checksums over every artifact in the package
75
- const checksums = {};
110
+ const checksumEntries = [];
76
111
  const walk = (d) => {
77
- for (const name of fs.readdirSync(d)) {
78
- const p = path.join(d, name);
79
- if (fs.statSync(p).isDirectory()) walk(p);
80
- else if (name !== 'checksums.json') checksums[path.relative(dir, p)] = sha256File(p);
112
+ for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
113
+ const p = path.join(d, entry.name);
114
+ if (entry.isSymbolicLink()) throw new Error(`staging package contains symbolic link: ${path.relative(stage, p)}`);
115
+ if (entry.isDirectory()) walk(p);
116
+ else if (entry.isFile() && entry.name !== 'checksums.json') checksumEntries.push([path.relative(stage, p).split(path.sep).join('/'), sha256File(p)]);
117
+ else if (!entry.isFile()) throw new Error(`staging package contains unsupported entry: ${path.relative(stage, p)}`);
118
+ }
119
+ };
120
+ walk(stage);
121
+ const checksums = Object.fromEntries(checksumEntries.sort(([a], [b]) => a.localeCompare(b)));
122
+ writeJson(path.join(stage, 'checksums.json'), checksums);
123
+ const fsyncTree = (directory) => {
124
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
125
+ const file = path.join(directory, entry.name);
126
+ if (entry.isSymbolicLink()) throw new Error(`staging package contains symbolic link: ${path.relative(stage, file)}`);
127
+ if (entry.isDirectory()) fsyncTree(file);
128
+ else if (entry.isFile()) fsyncPath(file);
81
129
  }
130
+ fsyncPath(directory);
82
131
  };
83
- walk(dir);
84
- writeJson(path.join(dir, 'checksums.json'), checksums);
132
+ fsyncTree(stage);
133
+ const parent = path.dirname(dir);
134
+ const displaced = `${dir}.partial-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
135
+ fs.renameSync(dir, displaced);
136
+ try {
137
+ fs.renameSync(stage, dir);
138
+ fs.rmSync(displaced, { recursive: true, force: true });
139
+ fsyncPath(parent);
140
+ } catch (error) {
141
+ if (!fs.existsSync(dir) && fs.existsSync(displaced)) fs.renameSync(displaced, dir);
142
+ fs.rmSync(stage, { recursive: true, force: true });
143
+ throw error;
144
+ }
85
145
  return dir;
86
146
  },
87
147
  };
@@ -1,10 +1,11 @@
1
1
  import { parse } from 'node-html-parser';
2
+ import { createEvidenceHashes, hashPageArtifact } from '../evidence/hashes.js';
2
3
 
3
4
  /**
4
5
  * Extract a PageModel from raw HTML plus transport metadata.
5
6
  * Everything downstream (detectors, inspect, schema) consumes this model.
6
7
  */
7
- export function extractPage({ url, html, status = 200, headers = {}, sourceFile = null, redirectChain = [] }) {
8
+ export function extractPage({ url, html, responseBody = null, status = 200, headers = {}, sourceFile = null, redirectChain = [], renderedDom = null }) {
8
9
  const root = parse(html, { comment: true });
9
10
  const head = root.querySelector('head');
10
11
 
@@ -282,7 +283,7 @@ export function extractPage({ url, html, status = 200, headers = {}, sourceFile
282
283
  };
283
284
  walkDom(root, 1);
284
285
 
285
- return {
286
+ const page = {
286
287
  url,
287
288
  sourceFile,
288
289
  status,
@@ -323,4 +324,30 @@ export function extractPage({ url, html, status = 200, headers = {}, sourceFile
323
324
  domNodeCount,
324
325
  maxDomDepth,
325
326
  };
327
+
328
+ // Keep representation identity explicit. These hashes deliberately do not
329
+ // share a generic `contentHash`: raw response bytes, extracted text,
330
+ // structured data, evaluator evidence, and the persisted page artifact are
331
+ // different claims and may change independently.
332
+ const hashes = createEvidenceHashes({
333
+ responseBody: responseBody ?? html,
334
+ renderedDom,
335
+ extractedText: text,
336
+ structuredData: jsonLd.length
337
+ ? jsonLd.map(({ parsed, blocks, parseError }) => ({ parsed, blocks, parseError }))
338
+ : null,
339
+ evidence: {
340
+ extracted_text: text,
341
+ headings,
342
+ paragraphs,
343
+ structured_data: jsonLd.map(({ parsed, blocks, parseError }) => ({ parsed, blocks, parseError })),
344
+ },
345
+ // This is replaced after URL/resource metadata is attached; keeping the
346
+ // field null here prevents a pre-persistence model from being presented as
347
+ // the persisted artifact identity.
348
+ artifact: null,
349
+ });
350
+ const withHashes = { ...page, ...hashes };
351
+ withHashes.artifact_hash = hashPageArtifact(withHashes);
352
+ return withHashes;
326
353
  }