@nebulacomponents/citable 1.11.0 → 1.13.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 (397) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.md +29 -2
  3. package/dist/universal/.agents/skills/citable/SKILL.md +14 -1
  4. package/dist/universal/.agents/skills/citable/VERSION +1 -1
  5. package/dist/universal/.agents/skills/citable/commands/README.md +2 -1
  6. package/dist/universal/.agents/skills/citable/commands/artifact-interchange.md +28 -0
  7. package/dist/universal/.agents/skills/citable/commands/field-validation.md +71 -0
  8. package/dist/universal/.agents/skills/citable/commands/observe-and-act.md +13 -1
  9. package/dist/universal/.agents/skills/citable/manifest.json +30 -10
  10. package/dist/universal/.agents/skills/citable/references/aeo-geo-validation.md +1 -1
  11. package/dist/universal/.agents/skills/citable/references/capability-boundaries.md +3 -0
  12. package/dist/universal/.agents/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  13. package/dist/universal/.agents/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  14. package/dist/universal/.agents/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  15. package/dist/universal/.agents/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  16. package/dist/universal/.agents/skills/citable/schemas/assumption.schema.json +119 -0
  17. package/dist/universal/.agents/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  18. package/dist/universal/.agents/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  19. package/dist/universal/.agents/skills/citable/schemas/customer-outcome.schema.json +119 -0
  20. package/dist/universal/.agents/skills/citable/schemas/decision.schema.json +154 -0
  21. package/dist/universal/.agents/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  22. package/dist/universal/.agents/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  23. package/dist/universal/.agents/skills/citable/schemas/initiative.schema.json +185 -0
  24. package/dist/universal/.agents/skills/citable/schemas/kpi.schema.json +108 -0
  25. package/dist/universal/.agents/skills/citable/schemas/observation.schema.json +1 -1
  26. package/dist/universal/.agents/skills/citable/schemas/release-manifest.schema.json +74 -0
  27. package/dist/universal/.agents/skills/citable/schemas/release-state.schema.json +40 -0
  28. package/dist/universal/.agents/skills/citable/schemas/risk.schema.json +172 -0
  29. package/dist/universal/.agents/skills/citable/schemas/scenario.schema.json +165 -0
  30. package/dist/universal/.agents/skills/citable/schemas/variance.schema.json +112 -0
  31. package/dist/universal/.claude/skills/citable/SKILL.md +14 -1
  32. package/dist/universal/.claude/skills/citable/VERSION +1 -1
  33. package/dist/universal/.claude/skills/citable/commands/README.md +2 -1
  34. package/dist/universal/.claude/skills/citable/commands/artifact-interchange.md +28 -0
  35. package/dist/universal/.claude/skills/citable/commands/field-validation.md +71 -0
  36. package/dist/universal/.claude/skills/citable/commands/observe-and-act.md +13 -1
  37. package/dist/universal/.claude/skills/citable/manifest.json +30 -10
  38. package/dist/universal/.claude/skills/citable/references/aeo-geo-validation.md +1 -1
  39. package/dist/universal/.claude/skills/citable/references/capability-boundaries.md +3 -0
  40. package/dist/universal/.claude/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  41. package/dist/universal/.claude/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  42. package/dist/universal/.claude/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  43. package/dist/universal/.claude/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  44. package/dist/universal/.claude/skills/citable/schemas/assumption.schema.json +119 -0
  45. package/dist/universal/.claude/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  46. package/dist/universal/.claude/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  47. package/dist/universal/.claude/skills/citable/schemas/customer-outcome.schema.json +119 -0
  48. package/dist/universal/.claude/skills/citable/schemas/decision.schema.json +154 -0
  49. package/dist/universal/.claude/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  50. package/dist/universal/.claude/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  51. package/dist/universal/.claude/skills/citable/schemas/initiative.schema.json +185 -0
  52. package/dist/universal/.claude/skills/citable/schemas/kpi.schema.json +108 -0
  53. package/dist/universal/.claude/skills/citable/schemas/observation.schema.json +1 -1
  54. package/dist/universal/.claude/skills/citable/schemas/release-manifest.schema.json +74 -0
  55. package/dist/universal/.claude/skills/citable/schemas/release-state.schema.json +40 -0
  56. package/dist/universal/.claude/skills/citable/schemas/risk.schema.json +172 -0
  57. package/dist/universal/.claude/skills/citable/schemas/scenario.schema.json +165 -0
  58. package/dist/universal/.claude/skills/citable/schemas/variance.schema.json +112 -0
  59. package/dist/universal/.cursor/skills/citable/SKILL.md +14 -1
  60. package/dist/universal/.cursor/skills/citable/VERSION +1 -1
  61. package/dist/universal/.cursor/skills/citable/commands/README.md +2 -1
  62. package/dist/universal/.cursor/skills/citable/commands/artifact-interchange.md +28 -0
  63. package/dist/universal/.cursor/skills/citable/commands/field-validation.md +71 -0
  64. package/dist/universal/.cursor/skills/citable/commands/observe-and-act.md +13 -1
  65. package/dist/universal/.cursor/skills/citable/manifest.json +30 -10
  66. package/dist/universal/.cursor/skills/citable/references/aeo-geo-validation.md +1 -1
  67. package/dist/universal/.cursor/skills/citable/references/capability-boundaries.md +3 -0
  68. package/dist/universal/.cursor/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  69. package/dist/universal/.cursor/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  70. package/dist/universal/.cursor/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  71. package/dist/universal/.cursor/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  72. package/dist/universal/.cursor/skills/citable/schemas/assumption.schema.json +119 -0
  73. package/dist/universal/.cursor/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  74. package/dist/universal/.cursor/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  75. package/dist/universal/.cursor/skills/citable/schemas/customer-outcome.schema.json +119 -0
  76. package/dist/universal/.cursor/skills/citable/schemas/decision.schema.json +154 -0
  77. package/dist/universal/.cursor/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  78. package/dist/universal/.cursor/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  79. package/dist/universal/.cursor/skills/citable/schemas/initiative.schema.json +185 -0
  80. package/dist/universal/.cursor/skills/citable/schemas/kpi.schema.json +108 -0
  81. package/dist/universal/.cursor/skills/citable/schemas/observation.schema.json +1 -1
  82. package/dist/universal/.cursor/skills/citable/schemas/release-manifest.schema.json +74 -0
  83. package/dist/universal/.cursor/skills/citable/schemas/release-state.schema.json +40 -0
  84. package/dist/universal/.cursor/skills/citable/schemas/risk.schema.json +172 -0
  85. package/dist/universal/.cursor/skills/citable/schemas/scenario.schema.json +165 -0
  86. package/dist/universal/.cursor/skills/citable/schemas/variance.schema.json +112 -0
  87. package/dist/universal/.gemini/skills/citable/SKILL.md +14 -1
  88. package/dist/universal/.gemini/skills/citable/VERSION +1 -1
  89. package/dist/universal/.gemini/skills/citable/commands/README.md +2 -1
  90. package/dist/universal/.gemini/skills/citable/commands/artifact-interchange.md +28 -0
  91. package/dist/universal/.gemini/skills/citable/commands/field-validation.md +71 -0
  92. package/dist/universal/.gemini/skills/citable/commands/observe-and-act.md +13 -1
  93. package/dist/universal/.gemini/skills/citable/manifest.json +30 -10
  94. package/dist/universal/.gemini/skills/citable/references/aeo-geo-validation.md +1 -1
  95. package/dist/universal/.gemini/skills/citable/references/capability-boundaries.md +3 -0
  96. package/dist/universal/.gemini/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  97. package/dist/universal/.gemini/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  98. package/dist/universal/.gemini/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  99. package/dist/universal/.gemini/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  100. package/dist/universal/.gemini/skills/citable/schemas/assumption.schema.json +119 -0
  101. package/dist/universal/.gemini/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  102. package/dist/universal/.gemini/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  103. package/dist/universal/.gemini/skills/citable/schemas/customer-outcome.schema.json +119 -0
  104. package/dist/universal/.gemini/skills/citable/schemas/decision.schema.json +154 -0
  105. package/dist/universal/.gemini/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  106. package/dist/universal/.gemini/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  107. package/dist/universal/.gemini/skills/citable/schemas/initiative.schema.json +185 -0
  108. package/dist/universal/.gemini/skills/citable/schemas/kpi.schema.json +108 -0
  109. package/dist/universal/.gemini/skills/citable/schemas/observation.schema.json +1 -1
  110. package/dist/universal/.gemini/skills/citable/schemas/release-manifest.schema.json +74 -0
  111. package/dist/universal/.gemini/skills/citable/schemas/release-state.schema.json +40 -0
  112. package/dist/universal/.gemini/skills/citable/schemas/risk.schema.json +172 -0
  113. package/dist/universal/.gemini/skills/citable/schemas/scenario.schema.json +165 -0
  114. package/dist/universal/.gemini/skills/citable/schemas/variance.schema.json +112 -0
  115. package/dist/universal/.github/skills/citable/SKILL.md +14 -1
  116. package/dist/universal/.github/skills/citable/VERSION +1 -1
  117. package/dist/universal/.github/skills/citable/commands/README.md +2 -1
  118. package/dist/universal/.github/skills/citable/commands/artifact-interchange.md +28 -0
  119. package/dist/universal/.github/skills/citable/commands/field-validation.md +71 -0
  120. package/dist/universal/.github/skills/citable/commands/observe-and-act.md +13 -1
  121. package/dist/universal/.github/skills/citable/manifest.json +30 -10
  122. package/dist/universal/.github/skills/citable/references/aeo-geo-validation.md +1 -1
  123. package/dist/universal/.github/skills/citable/references/capability-boundaries.md +3 -0
  124. package/dist/universal/.github/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  125. package/dist/universal/.github/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  126. package/dist/universal/.github/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  127. package/dist/universal/.github/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  128. package/dist/universal/.github/skills/citable/schemas/assumption.schema.json +119 -0
  129. package/dist/universal/.github/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  130. package/dist/universal/.github/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  131. package/dist/universal/.github/skills/citable/schemas/customer-outcome.schema.json +119 -0
  132. package/dist/universal/.github/skills/citable/schemas/decision.schema.json +154 -0
  133. package/dist/universal/.github/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  134. package/dist/universal/.github/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  135. package/dist/universal/.github/skills/citable/schemas/initiative.schema.json +185 -0
  136. package/dist/universal/.github/skills/citable/schemas/kpi.schema.json +108 -0
  137. package/dist/universal/.github/skills/citable/schemas/observation.schema.json +1 -1
  138. package/dist/universal/.github/skills/citable/schemas/release-manifest.schema.json +74 -0
  139. package/dist/universal/.github/skills/citable/schemas/release-state.schema.json +40 -0
  140. package/dist/universal/.github/skills/citable/schemas/risk.schema.json +172 -0
  141. package/dist/universal/.github/skills/citable/schemas/scenario.schema.json +165 -0
  142. package/dist/universal/.github/skills/citable/schemas/variance.schema.json +112 -0
  143. package/dist/universal/.kiro/skills/citable/SKILL.md +14 -1
  144. package/dist/universal/.kiro/skills/citable/VERSION +1 -1
  145. package/dist/universal/.kiro/skills/citable/commands/README.md +2 -1
  146. package/dist/universal/.kiro/skills/citable/commands/artifact-interchange.md +28 -0
  147. package/dist/universal/.kiro/skills/citable/commands/field-validation.md +71 -0
  148. package/dist/universal/.kiro/skills/citable/commands/observe-and-act.md +13 -1
  149. package/dist/universal/.kiro/skills/citable/manifest.json +30 -10
  150. package/dist/universal/.kiro/skills/citable/references/aeo-geo-validation.md +1 -1
  151. package/dist/universal/.kiro/skills/citable/references/capability-boundaries.md +3 -0
  152. package/dist/universal/.kiro/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  153. package/dist/universal/.kiro/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  154. package/dist/universal/.kiro/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  155. package/dist/universal/.kiro/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  156. package/dist/universal/.kiro/skills/citable/schemas/assumption.schema.json +119 -0
  157. package/dist/universal/.kiro/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  158. package/dist/universal/.kiro/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  159. package/dist/universal/.kiro/skills/citable/schemas/customer-outcome.schema.json +119 -0
  160. package/dist/universal/.kiro/skills/citable/schemas/decision.schema.json +154 -0
  161. package/dist/universal/.kiro/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  162. package/dist/universal/.kiro/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  163. package/dist/universal/.kiro/skills/citable/schemas/initiative.schema.json +185 -0
  164. package/dist/universal/.kiro/skills/citable/schemas/kpi.schema.json +108 -0
  165. package/dist/universal/.kiro/skills/citable/schemas/observation.schema.json +1 -1
  166. package/dist/universal/.kiro/skills/citable/schemas/release-manifest.schema.json +74 -0
  167. package/dist/universal/.kiro/skills/citable/schemas/release-state.schema.json +40 -0
  168. package/dist/universal/.kiro/skills/citable/schemas/risk.schema.json +172 -0
  169. package/dist/universal/.kiro/skills/citable/schemas/scenario.schema.json +165 -0
  170. package/dist/universal/.kiro/skills/citable/schemas/variance.schema.json +112 -0
  171. package/dist/universal/.opencode/skills/citable/SKILL.md +14 -1
  172. package/dist/universal/.opencode/skills/citable/VERSION +1 -1
  173. package/dist/universal/.opencode/skills/citable/commands/README.md +2 -1
  174. package/dist/universal/.opencode/skills/citable/commands/artifact-interchange.md +28 -0
  175. package/dist/universal/.opencode/skills/citable/commands/field-validation.md +71 -0
  176. package/dist/universal/.opencode/skills/citable/commands/observe-and-act.md +13 -1
  177. package/dist/universal/.opencode/skills/citable/manifest.json +30 -10
  178. package/dist/universal/.opencode/skills/citable/references/aeo-geo-validation.md +1 -1
  179. package/dist/universal/.opencode/skills/citable/references/capability-boundaries.md +3 -0
  180. package/dist/universal/.opencode/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  181. package/dist/universal/.opencode/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  182. package/dist/universal/.opencode/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  183. package/dist/universal/.opencode/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  184. package/dist/universal/.opencode/skills/citable/schemas/assumption.schema.json +119 -0
  185. package/dist/universal/.opencode/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  186. package/dist/universal/.opencode/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  187. package/dist/universal/.opencode/skills/citable/schemas/customer-outcome.schema.json +119 -0
  188. package/dist/universal/.opencode/skills/citable/schemas/decision.schema.json +154 -0
  189. package/dist/universal/.opencode/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  190. package/dist/universal/.opencode/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  191. package/dist/universal/.opencode/skills/citable/schemas/initiative.schema.json +185 -0
  192. package/dist/universal/.opencode/skills/citable/schemas/kpi.schema.json +108 -0
  193. package/dist/universal/.opencode/skills/citable/schemas/observation.schema.json +1 -1
  194. package/dist/universal/.opencode/skills/citable/schemas/release-manifest.schema.json +74 -0
  195. package/dist/universal/.opencode/skills/citable/schemas/release-state.schema.json +40 -0
  196. package/dist/universal/.opencode/skills/citable/schemas/risk.schema.json +172 -0
  197. package/dist/universal/.opencode/skills/citable/schemas/scenario.schema.json +165 -0
  198. package/dist/universal/.opencode/skills/citable/schemas/variance.schema.json +112 -0
  199. package/dist/universal/.pi/agent/skills/citable/SKILL.md +14 -1
  200. package/dist/universal/.pi/agent/skills/citable/VERSION +1 -1
  201. package/dist/universal/.pi/agent/skills/citable/commands/README.md +2 -1
  202. package/dist/universal/.pi/agent/skills/citable/commands/artifact-interchange.md +28 -0
  203. package/dist/universal/.pi/agent/skills/citable/commands/field-validation.md +71 -0
  204. package/dist/universal/.pi/agent/skills/citable/commands/observe-and-act.md +13 -1
  205. package/dist/universal/.pi/agent/skills/citable/manifest.json +30 -10
  206. package/dist/universal/.pi/agent/skills/citable/references/aeo-geo-validation.md +1 -1
  207. package/dist/universal/.pi/agent/skills/citable/references/capability-boundaries.md +3 -0
  208. package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  209. package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  210. package/dist/universal/.pi/agent/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  211. package/dist/universal/.pi/agent/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  212. package/dist/universal/.pi/agent/skills/citable/schemas/assumption.schema.json +119 -0
  213. package/dist/universal/.pi/agent/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  214. package/dist/universal/.pi/agent/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  215. package/dist/universal/.pi/agent/skills/citable/schemas/customer-outcome.schema.json +119 -0
  216. package/dist/universal/.pi/agent/skills/citable/schemas/decision.schema.json +154 -0
  217. package/dist/universal/.pi/agent/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  218. package/dist/universal/.pi/agent/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  219. package/dist/universal/.pi/agent/skills/citable/schemas/initiative.schema.json +185 -0
  220. package/dist/universal/.pi/agent/skills/citable/schemas/kpi.schema.json +108 -0
  221. package/dist/universal/.pi/agent/skills/citable/schemas/observation.schema.json +1 -1
  222. package/dist/universal/.pi/agent/skills/citable/schemas/release-manifest.schema.json +74 -0
  223. package/dist/universal/.pi/agent/skills/citable/schemas/release-state.schema.json +40 -0
  224. package/dist/universal/.pi/agent/skills/citable/schemas/risk.schema.json +172 -0
  225. package/dist/universal/.pi/agent/skills/citable/schemas/scenario.schema.json +165 -0
  226. package/dist/universal/.pi/agent/skills/citable/schemas/variance.schema.json +112 -0
  227. package/dist/universal/.qoder/skills/citable/SKILL.md +14 -1
  228. package/dist/universal/.qoder/skills/citable/VERSION +1 -1
  229. package/dist/universal/.qoder/skills/citable/commands/README.md +2 -1
  230. package/dist/universal/.qoder/skills/citable/commands/artifact-interchange.md +28 -0
  231. package/dist/universal/.qoder/skills/citable/commands/field-validation.md +71 -0
  232. package/dist/universal/.qoder/skills/citable/commands/observe-and-act.md +13 -1
  233. package/dist/universal/.qoder/skills/citable/manifest.json +30 -10
  234. package/dist/universal/.qoder/skills/citable/references/aeo-geo-validation.md +1 -1
  235. package/dist/universal/.qoder/skills/citable/references/capability-boundaries.md +3 -0
  236. package/dist/universal/.qoder/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  237. package/dist/universal/.qoder/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  238. package/dist/universal/.qoder/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  239. package/dist/universal/.qoder/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  240. package/dist/universal/.qoder/skills/citable/schemas/assumption.schema.json +119 -0
  241. package/dist/universal/.qoder/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  242. package/dist/universal/.qoder/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  243. package/dist/universal/.qoder/skills/citable/schemas/customer-outcome.schema.json +119 -0
  244. package/dist/universal/.qoder/skills/citable/schemas/decision.schema.json +154 -0
  245. package/dist/universal/.qoder/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  246. package/dist/universal/.qoder/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  247. package/dist/universal/.qoder/skills/citable/schemas/initiative.schema.json +185 -0
  248. package/dist/universal/.qoder/skills/citable/schemas/kpi.schema.json +108 -0
  249. package/dist/universal/.qoder/skills/citable/schemas/observation.schema.json +1 -1
  250. package/dist/universal/.qoder/skills/citable/schemas/release-manifest.schema.json +74 -0
  251. package/dist/universal/.qoder/skills/citable/schemas/release-state.schema.json +40 -0
  252. package/dist/universal/.qoder/skills/citable/schemas/risk.schema.json +172 -0
  253. package/dist/universal/.qoder/skills/citable/schemas/scenario.schema.json +165 -0
  254. package/dist/universal/.qoder/skills/citable/schemas/variance.schema.json +112 -0
  255. package/dist/universal/.rovodev/skills/citable/SKILL.md +14 -1
  256. package/dist/universal/.rovodev/skills/citable/VERSION +1 -1
  257. package/dist/universal/.rovodev/skills/citable/commands/README.md +2 -1
  258. package/dist/universal/.rovodev/skills/citable/commands/artifact-interchange.md +28 -0
  259. package/dist/universal/.rovodev/skills/citable/commands/field-validation.md +71 -0
  260. package/dist/universal/.rovodev/skills/citable/commands/observe-and-act.md +13 -1
  261. package/dist/universal/.rovodev/skills/citable/manifest.json +30 -10
  262. package/dist/universal/.rovodev/skills/citable/references/aeo-geo-validation.md +1 -1
  263. package/dist/universal/.rovodev/skills/citable/references/capability-boundaries.md +3 -0
  264. package/dist/universal/.rovodev/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  265. package/dist/universal/.rovodev/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  266. package/dist/universal/.rovodev/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  267. package/dist/universal/.rovodev/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  268. package/dist/universal/.rovodev/skills/citable/schemas/assumption.schema.json +119 -0
  269. package/dist/universal/.rovodev/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  270. package/dist/universal/.rovodev/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  271. package/dist/universal/.rovodev/skills/citable/schemas/customer-outcome.schema.json +119 -0
  272. package/dist/universal/.rovodev/skills/citable/schemas/decision.schema.json +154 -0
  273. package/dist/universal/.rovodev/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  274. package/dist/universal/.rovodev/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  275. package/dist/universal/.rovodev/skills/citable/schemas/initiative.schema.json +185 -0
  276. package/dist/universal/.rovodev/skills/citable/schemas/kpi.schema.json +108 -0
  277. package/dist/universal/.rovodev/skills/citable/schemas/observation.schema.json +1 -1
  278. package/dist/universal/.rovodev/skills/citable/schemas/release-manifest.schema.json +74 -0
  279. package/dist/universal/.rovodev/skills/citable/schemas/release-state.schema.json +40 -0
  280. package/dist/universal/.rovodev/skills/citable/schemas/risk.schema.json +172 -0
  281. package/dist/universal/.rovodev/skills/citable/schemas/scenario.schema.json +165 -0
  282. package/dist/universal/.rovodev/skills/citable/schemas/variance.schema.json +112 -0
  283. package/dist/universal/.trae/skills/citable/SKILL.md +14 -1
  284. package/dist/universal/.trae/skills/citable/VERSION +1 -1
  285. package/dist/universal/.trae/skills/citable/commands/README.md +2 -1
  286. package/dist/universal/.trae/skills/citable/commands/artifact-interchange.md +28 -0
  287. package/dist/universal/.trae/skills/citable/commands/field-validation.md +71 -0
  288. package/dist/universal/.trae/skills/citable/commands/observe-and-act.md +13 -1
  289. package/dist/universal/.trae/skills/citable/manifest.json +30 -10
  290. package/dist/universal/.trae/skills/citable/references/aeo-geo-validation.md +1 -1
  291. package/dist/universal/.trae/skills/citable/references/capability-boundaries.md +3 -0
  292. package/dist/universal/.trae/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  293. package/dist/universal/.trae/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  294. package/dist/universal/.trae/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  295. package/dist/universal/.trae/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  296. package/dist/universal/.trae/skills/citable/schemas/assumption.schema.json +119 -0
  297. package/dist/universal/.trae/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  298. package/dist/universal/.trae/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  299. package/dist/universal/.trae/skills/citable/schemas/customer-outcome.schema.json +119 -0
  300. package/dist/universal/.trae/skills/citable/schemas/decision.schema.json +154 -0
  301. package/dist/universal/.trae/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  302. package/dist/universal/.trae/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  303. package/dist/universal/.trae/skills/citable/schemas/initiative.schema.json +185 -0
  304. package/dist/universal/.trae/skills/citable/schemas/kpi.schema.json +108 -0
  305. package/dist/universal/.trae/skills/citable/schemas/observation.schema.json +1 -1
  306. package/dist/universal/.trae/skills/citable/schemas/release-manifest.schema.json +74 -0
  307. package/dist/universal/.trae/skills/citable/schemas/release-state.schema.json +40 -0
  308. package/dist/universal/.trae/skills/citable/schemas/risk.schema.json +172 -0
  309. package/dist/universal/.trae/skills/citable/schemas/scenario.schema.json +165 -0
  310. package/dist/universal/.trae/skills/citable/schemas/variance.schema.json +112 -0
  311. package/dist/universal/.trae-cn/skills/citable/SKILL.md +14 -1
  312. package/dist/universal/.trae-cn/skills/citable/VERSION +1 -1
  313. package/dist/universal/.trae-cn/skills/citable/commands/README.md +2 -1
  314. package/dist/universal/.trae-cn/skills/citable/commands/artifact-interchange.md +28 -0
  315. package/dist/universal/.trae-cn/skills/citable/commands/field-validation.md +71 -0
  316. package/dist/universal/.trae-cn/skills/citable/commands/observe-and-act.md +13 -1
  317. package/dist/universal/.trae-cn/skills/citable/manifest.json +30 -10
  318. package/dist/universal/.trae-cn/skills/citable/references/aeo-geo-validation.md +1 -1
  319. package/dist/universal/.trae-cn/skills/citable/references/capability-boundaries.md +3 -0
  320. package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-corpus.schema.json +168 -0
  321. package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-run-context.schema.json +17 -0
  322. package/dist/universal/.trae-cn/skills/citable/schemas/acceptance-run-receipt.schema.json +88 -0
  323. package/dist/universal/.trae-cn/skills/citable/schemas/artifact-interchange.schema.json +58 -0
  324. package/dist/universal/.trae-cn/skills/citable/schemas/assumption.schema.json +119 -0
  325. package/dist/universal/.trae-cn/skills/citable/schemas/browser-evidence-plan.schema.json +76 -0
  326. package/dist/universal/.trae-cn/skills/citable/schemas/corpus-publication-receipt.schema.json +24 -0
  327. package/dist/universal/.trae-cn/skills/citable/schemas/customer-outcome.schema.json +119 -0
  328. package/dist/universal/.trae-cn/skills/citable/schemas/decision.schema.json +154 -0
  329. package/dist/universal/.trae-cn/skills/citable/schemas/deployment-receipt.schema.json +51 -0
  330. package/dist/universal/.trae-cn/skills/citable/schemas/field-validation-metrics.schema.json +15 -0
  331. package/dist/universal/.trae-cn/skills/citable/schemas/initiative.schema.json +185 -0
  332. package/dist/universal/.trae-cn/skills/citable/schemas/kpi.schema.json +108 -0
  333. package/dist/universal/.trae-cn/skills/citable/schemas/observation.schema.json +1 -1
  334. package/dist/universal/.trae-cn/skills/citable/schemas/release-manifest.schema.json +74 -0
  335. package/dist/universal/.trae-cn/skills/citable/schemas/release-state.schema.json +40 -0
  336. package/dist/universal/.trae-cn/skills/citable/schemas/risk.schema.json +172 -0
  337. package/dist/universal/.trae-cn/skills/citable/schemas/scenario.schema.json +165 -0
  338. package/dist/universal/.trae-cn/skills/citable/schemas/variance.schema.json +112 -0
  339. package/dist/universal/manifest.json +363 -123
  340. package/package.json +12 -1
  341. package/release/surfaces.json +21 -0
  342. package/schemas/acceptance-corpus.schema.json +168 -0
  343. package/schemas/acceptance-run-context.schema.json +17 -0
  344. package/schemas/acceptance-run-receipt.schema.json +88 -0
  345. package/schemas/artifact-interchange.schema.json +58 -0
  346. package/schemas/assumption.schema.json +119 -0
  347. package/schemas/browser-evidence-plan.schema.json +76 -0
  348. package/schemas/corpus-publication-receipt.schema.json +24 -0
  349. package/schemas/customer-outcome.schema.json +119 -0
  350. package/schemas/decision.schema.json +154 -0
  351. package/schemas/deployment-receipt.schema.json +51 -0
  352. package/schemas/field-validation-metrics.schema.json +15 -0
  353. package/schemas/initiative.schema.json +185 -0
  354. package/schemas/kpi.schema.json +108 -0
  355. package/schemas/observation.schema.json +1 -1
  356. package/schemas/release-manifest.schema.json +74 -0
  357. package/schemas/release-state.schema.json +40 -0
  358. package/schemas/risk.schema.json +172 -0
  359. package/schemas/scenario.schema.json +165 -0
  360. package/schemas/variance.schema.json +112 -0
  361. package/scripts/release-governance.js +123 -0
  362. package/skill/SKILL.md +14 -1
  363. package/skill/commands/README.md +2 -1
  364. package/skill/commands/artifact-interchange.md +28 -0
  365. package/skill/commands/field-validation.md +71 -0
  366. package/skill/commands/observe-and-act.md +13 -1
  367. package/skill/references/aeo-geo-validation.md +1 -1
  368. package/skill/references/capability-boundaries.md +3 -0
  369. package/src/acceptance/reproducibility.js +180 -0
  370. package/src/artifacts/interchange.js +179 -0
  371. package/src/cli/index.js +149 -4
  372. package/src/commands/assumptionAudit.js +111 -0
  373. package/src/commands/audit.js +6 -0
  374. package/src/commands/boardReport.js +251 -0
  375. package/src/commands/competitiveIntel.js +124 -0
  376. package/src/commands/corpus.js +322 -0
  377. package/src/commands/decisionMemo.js +202 -0
  378. package/src/commands/executive.js +167 -0
  379. package/src/commands/executiveReview.js +206 -0
  380. package/src/commands/init.js +14 -1
  381. package/src/commands/kpi.js +86 -0
  382. package/src/commands/monitor.js +9 -0
  383. package/src/commands/observe.js +202 -30
  384. package/src/commands/outcomes.js +113 -0
  385. package/src/commands/prioritize.js +108 -0
  386. package/src/commands/risk.js +104 -0
  387. package/src/commands/scenario.js +98 -0
  388. package/src/commands/variance.js +102 -0
  389. package/src/detectors/framework.js +37 -0
  390. package/src/detectors/page.js +10 -10
  391. package/src/detectors/tech.js +5 -3
  392. package/src/extractor/site.js +21 -6
  393. package/src/observations/browserJourney.js +167 -0
  394. package/src/observations/media.js +8 -1
  395. package/src/registries/index.js +107 -6
  396. package/src/release/governance.js +331 -0
  397. package/src/shared/asOf.js +18 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * scenario command — Scenario War Room
3
+ *
4
+ * Models compound risks with cascade analysis and early-warning triggers.
5
+ * Maximum 3 variables per scenario. Requires explicit hedges with cost,
6
+ * impact, owner, and deadline — not just worst-case narratives.
7
+ *
8
+ * Usage:
9
+ * citable scenario list
10
+ * citable scenario show <scenario_id>
11
+ * citable scenario validate
12
+ * citable scenario triggers — early-warning trigger summary
13
+ */
14
+ import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
15
+ import { validateAgainst } from '../shared/schemaValidator.js';
16
+ import path from 'node:path';
17
+
18
+
19
+ export async function scenarioCommand(args, root = process.cwd()) {
20
+ const [subcommand, ...rest] = args;
21
+ const file = path.join(contextDir(root), 'scenarios.yaml');
22
+
23
+ switch (subcommand) {
24
+ case 'show': return scenarioShow(file, rest[0]);
25
+ case 'validate': return scenarioValidate(file);
26
+ case 'triggers': return scenarioTriggers(file);
27
+ default: return scenarioList(file);
28
+ }
29
+ }
30
+
31
+ function load(file) {
32
+ return loadRegistryFile(file, 'scenarios');
33
+ }
34
+
35
+ function scenarioList(file) {
36
+ const data = load(file);
37
+ return {
38
+ scenarios: data.entries.map(s => ({
39
+ scenario_id: s.scenario_id,
40
+ title: s.title,
41
+ variables: (s.variables ?? []).length,
42
+ cascade_steps: (s.cascade_analysis ?? []).length,
43
+ hedges: (s.hedges ?? []).length,
44
+ early_warnings: (s.early_warning_triggers ?? []).length,
45
+ owner: s.owner,
46
+ })),
47
+ total: data.entries.length,
48
+ };
49
+ }
50
+
51
+ function scenarioShow(file, id) {
52
+ if (!id) return { error: 'scenario_id required' };
53
+ const data = load(file);
54
+ const s = data.entries.find(e => e.scenario_id === id);
55
+ if (!s) return { error: `Scenario not found: ${id}` };
56
+ return { scenario: s };
57
+ }
58
+
59
+ function scenarioTriggers(file) {
60
+ const data = load(file);
61
+ return {
62
+ triggers: data.entries.flatMap(s =>
63
+ (s.early_warning_triggers ?? []).map(t => ({
64
+ scenario_id: s.scenario_id, title: s.title, trigger: t,
65
+ }))
66
+ ),
67
+ total_scenarios: data.entries.length,
68
+ };
69
+ }
70
+
71
+ function scenarioValidate(file) {
72
+ const data = load(file);
73
+ const problems = [...registryLoadProblems(data)];
74
+ const { valid, errors } = validateAgainst('scenario.schema.json', data);
75
+ if (!valid) problems.push(...errors);
76
+
77
+ for (const s of data.entries) {
78
+ // Variables capped at 3
79
+ if ((s.variables ?? []).length > 3)
80
+ problems.push(`${s.scenario_id}: maximum 3 variables per scenario — combine compound drivers into a single variable`);
81
+ // Cascade analysis required (not just isolated risk statements)
82
+ if (!s.cascade_analysis || s.cascade_analysis.length === 0)
83
+ problems.push(`${s.scenario_id}: cascade_analysis required — scenarios must show cascading effects, not isolated risks`);
84
+ // All three states required
85
+ if (!s.states?.base || !s.states?.stress || !s.states?.severe)
86
+ problems.push(`${s.scenario_id}: all three states (base, stress, severe) required`);
87
+ // Hedges must have all required fields
88
+ for (const h of s.hedges ?? []) {
89
+ if (!h.cost || !h.impact || !h.owner || !h.deadline)
90
+ problems.push(`${s.scenario_id} hedge "${h.action}": cost, impact, owner, and deadline all required`);
91
+ }
92
+ // Early-warning triggers required
93
+ if (!s.early_warning_triggers || s.early_warning_triggers.length === 0)
94
+ problems.push(`${s.scenario_id}: early_warning_triggers required — scenario without triggers is a narrative, not a management tool`);
95
+ }
96
+
97
+ return { valid: problems.length === 0, problems, checked: data.entries.length };
98
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * variance command — Variance analysis registry
3
+ *
4
+ * Rejects non-causes (market conditions, timing, customer behaviour)
5
+ * unless decomposed into specific observed mechanisms.
6
+ *
7
+ * Usage:
8
+ * citable variance list [--period <period>]
9
+ * citable variance show <variance_id>
10
+ * citable variance validate
11
+ * citable variance material — list material/critical variances only
12
+ */
13
+ import { contextDir, loadRegistryFile, registryLoadProblems } from '../registries/index.js';
14
+ import { validateAgainst } from '../shared/schemaValidator.js';
15
+ import path from 'node:path';
16
+
17
+
18
+ // Vague causes that must be decomposed before acceptance
19
+ const REJECTED_CAUSE_PATTERNS = [
20
+ /^market conditions?$/i,
21
+ /^timing$/i,
22
+ /^customer behaviour?$/i,
23
+ /^execution issues?$/i,
24
+ /^macro(economic)?$/i,
25
+ /^seasonality$/i,
26
+ ];
27
+
28
+ export async function varianceCommand(args, root = process.cwd()) {
29
+ const [subcommand, ...rest] = args;
30
+ const file = path.join(contextDir(root), 'variances.yaml');
31
+
32
+ switch (subcommand) {
33
+ case 'show': return varianceShow(file, rest[0]);
34
+ case 'validate': return varianceValidate(file);
35
+ case 'material': return varianceList(file, { materialOnly: true });
36
+ default: {
37
+ const i = rest.indexOf('--period');
38
+ return varianceList(file, { period: i >= 0 ? rest[i + 1] : null });
39
+ }
40
+ }
41
+ }
42
+
43
+ function load(file) {
44
+ return loadRegistryFile(file, 'variances');
45
+ }
46
+
47
+ function varianceList(file, { materialOnly = false, period = null } = {}) {
48
+ const data = load(file);
49
+ let entries = data.entries;
50
+ if (materialOnly) entries = entries.filter(v => ['material','critical'].includes(v.materiality));
51
+ if (period) entries = entries.filter(v => v.period === period);
52
+ return {
53
+ variances: entries.map(v => ({
54
+ variance_id: v.variance_id,
55
+ metric_id: v.metric_id,
56
+ period: v.period,
57
+ variance_pct: v.variance_pct,
58
+ materiality: v.materiality,
59
+ primary_driver: v.primary_driver,
60
+ controllable: v.controllable,
61
+ confidence: v.confidence,
62
+ })),
63
+ total: entries.length,
64
+ };
65
+ }
66
+
67
+ function varianceShow(file, id) {
68
+ if (!id) return { error: 'variance_id required' };
69
+ const data = load(file);
70
+ const v = data.entries.find(e => e.variance_id === id);
71
+ if (!v) return { error: `Variance not found: ${id}` };
72
+ return { variance: v };
73
+ }
74
+
75
+ function varianceValidate(file) {
76
+ const data = load(file);
77
+ const problems = [...registryLoadProblems(data)];
78
+ const { valid, errors } = validateAgainst('variance.schema.json', data);
79
+ if (!valid) problems.push(...errors);
80
+
81
+ for (const v of data.entries) {
82
+ // Reject vague causes
83
+ for (const pattern of REJECTED_CAUSE_PATTERNS) {
84
+ if (pattern.test((v.primary_driver ?? '').trim())) {
85
+ problems.push(`${v.variance_id}: primary_driver "${v.primary_driver}" is a non-cause — decompose into a specific observed mechanism`);
86
+ }
87
+ for (const d of v.secondary_drivers ?? []) {
88
+ if (pattern.test(d.trim())) {
89
+ problems.push(`${v.variance_id}: secondary_driver "${d}" is a non-cause — decompose into a specific observed mechanism`);
90
+ }
91
+ }
92
+ }
93
+ // Material variances need management response
94
+ if (['material','critical'].includes(v.materiality) && !v.management_response)
95
+ problems.push(`${v.variance_id}: material variance requires management_response`);
96
+ // Evidence required
97
+ if (!v.evidence || v.evidence.length === 0)
98
+ problems.push(`${v.variance_id}: evidence array must not be empty`);
99
+ }
100
+
101
+ return { valid: problems.length === 0, problems, checked: data.entries.length };
102
+ }
@@ -100,12 +100,49 @@ export function runDetectors(detectors, ctx) {
100
100
  /** Pages whose declared or default intent is to be indexed. */
101
101
  export function indexTargets(ctx) {
102
102
  return ctx.site.pages.filter((p) => {
103
+ if (isProviderUtilityUrl(p.url)) return false;
103
104
  const reg = registryPageFor(ctx, p);
104
105
  if (reg?.indexing_intent === 'noindex') return false;
105
106
  return true;
106
107
  });
107
108
  }
108
109
 
110
+ /** Index targets whose response is an HTML document. */
111
+ export function htmlIndexTargets(ctx) {
112
+ return indexTargets(ctx).filter(isHtmlDocument);
113
+ }
114
+
115
+ export function isHtmlDocument(page) {
116
+ const type = String(page?.contentType || '').toLowerCase();
117
+ return !type || type.includes('text/html') || type.includes('application/xhtml+xml');
118
+ }
119
+
120
+ /** URLs that conventionally identify HTML documents rather than media/data resources. */
121
+ export function isHtmlDocumentUrl(url) {
122
+ try {
123
+ const pathname = new URL(url).pathname;
124
+ const name = pathname.split('/').pop() || '';
125
+ const match = name.match(/\.([a-z0-9]+)$/i);
126
+ return Boolean(match) && ['html', 'htm', 'xhtml'].includes(match[1].toLowerCase());
127
+ } catch {
128
+ return false;
129
+ }
130
+ }
131
+
132
+ export function hasHtmlDocumentMarkup(page) {
133
+ return /^\s*(?:<!doctype\s+html\b|<html\b)/i.test(String(page?.rawHtml || ''));
134
+ }
135
+
136
+ /** Provider-owned utility routes are link evidence, not default content pages. */
137
+ export function isProviderUtilityUrl(url) {
138
+ try {
139
+ const { pathname } = new URL(url);
140
+ return pathname === '/cdn-cgi' || pathname.startsWith('/cdn-cgi/');
141
+ } catch {
142
+ return false;
143
+ }
144
+ }
145
+
109
146
  /** Match a live page to its registry entry by URL path. */
110
147
  export function registryPageFor(ctx, page) {
111
148
  const entries = ctx.registries?.pages?.entries || [];
@@ -1,4 +1,4 @@
1
- import { defineDetector, indexTargets, pageSubject } from './framework.js';
1
+ import { defineDetector, htmlIndexTargets, pageSubject } from './framework.js';
2
2
 
3
3
  const D = [];
4
4
 
@@ -11,7 +11,7 @@ D.push(defineDetector({
11
11
  remediation: 'Add a concise title identifying the page subject and distinguishing it from other pages.',
12
12
  verification: 'Confirm a non-empty <title> in rendered HTML.',
13
13
  check(ctx) {
14
- return indexTargets(ctx).filter((p) => p.status === 200 && !p.title).map((p) => ({
14
+ return htmlIndexTargets(ctx).filter((p) => p.status === 200 && !p.title).map((p) => ({
15
15
  subject: pageSubject(p), summary: 'Page has no title element', evidence: ['<title> absent or empty'],
16
16
  }));
17
17
  },
@@ -27,7 +27,7 @@ D.push(defineDetector({
27
27
  verification: 'Confirm title uniqueness across index targets.',
28
28
  check(ctx) {
29
29
  const byTitle = new Map();
30
- for (const p of indexTargets(ctx)) {
30
+ for (const p of htmlIndexTargets(ctx)) {
31
31
  if (!p.title || p.status !== 200) continue;
32
32
  if (!byTitle.has(p.title)) byTitle.set(p.title, []);
33
33
  byTitle.get(p.title).push(p);
@@ -49,7 +49,7 @@ D.push(defineDetector({
49
49
  remediation: 'Add an accurate, page-specific description stating the expected value.',
50
50
  verification: 'Confirm meta[name=description] present and non-empty.',
51
51
  check(ctx) {
52
- return indexTargets(ctx).filter((p) => p.status === 200 && !p.metaDescription).map((p) => ({
52
+ return htmlIndexTargets(ctx).filter((p) => p.status === 200 && !p.metaDescription).map((p) => ({
53
53
  subject: pageSubject(p), summary: 'Page has no meta description', evidence: ['meta[name=description] absent'],
54
54
  }));
55
55
  },
@@ -65,7 +65,7 @@ D.push(defineDetector({
65
65
  verification: 'Confirm description uniqueness.',
66
66
  check(ctx) {
67
67
  const byDesc = new Map();
68
- for (const p of indexTargets(ctx)) {
68
+ for (const p of htmlIndexTargets(ctx)) {
69
69
  if (!p.metaDescription || p.status !== 200) continue;
70
70
  if (!byDesc.has(p.metaDescription)) byDesc.set(p.metaDescription, []);
71
71
  byDesc.get(p.metaDescription).push(p);
@@ -87,7 +87,7 @@ D.push(defineDetector({
87
87
  remediation: 'Use exactly one H1 that identifies the page purpose.',
88
88
  verification: 'Count H1 elements.',
89
89
  check(ctx) {
90
- return indexTargets(ctx).filter((p) => p.status === 200 && p.h1s.length !== 1).map((p) => ({
90
+ return htmlIndexTargets(ctx).filter((p) => p.status === 200 && p.h1s.length !== 1).map((p) => ({
91
91
  subject: pageSubject(p),
92
92
  summary: p.h1s.length === 0 ? 'Page has no H1' : `Page has ${p.h1s.length} H1 elements`,
93
93
  evidence: p.h1s.length ? p.h1s.map((h) => `H1: ${h.text}`) : ['no <h1> found'],
@@ -106,7 +106,7 @@ D.push(defineDetector({
106
106
  verification: 'Walk heading sequence and confirm no level is skipped.',
107
107
  check(ctx) {
108
108
  const hits = [];
109
- for (const p of indexTargets(ctx)) {
109
+ for (const p of htmlIndexTargets(ctx)) {
110
110
  if (p.status !== 200) continue;
111
111
  let prev = 0;
112
112
  for (const h of p.headings) {
@@ -134,7 +134,7 @@ D.push(defineDetector({
134
134
  remediation: 'Add descriptive alt text (or empty alt for purely decorative images, reviewed case by case).',
135
135
  verification: 'Confirm every <img> has an alt attribute.',
136
136
  check(ctx) {
137
- return indexTargets(ctx)
137
+ return htmlIndexTargets(ctx)
138
138
  .map((p) => ({ p, missing: p.images.filter((i) => i.alt === undefined || i.alt === null) }))
139
139
  .filter(({ p, missing }) => p.status === 200 && missing.length > 0)
140
140
  .map(({ p, missing }) => ({
@@ -156,7 +156,7 @@ D.push(defineDetector({
156
156
  verification: 'Re-measure extracted word count after revision.',
157
157
  check(ctx) {
158
158
  const min = ctx.config?.audit?.thin_content_words ?? 120;
159
- return indexTargets(ctx)
159
+ return htmlIndexTargets(ctx)
160
160
  .filter((p) => p.status === 200 && p.wordCount > 0 && p.wordCount < min)
161
161
  .map((p) => ({
162
162
  subject: pageSubject(p),
@@ -178,7 +178,7 @@ D.push(defineDetector({
178
178
  verification: 'Re-measure dominant-term density.',
179
179
  check(ctx) {
180
180
  const hits = [];
181
- for (const p of indexTargets(ctx)) {
181
+ for (const p of htmlIndexTargets(ctx)) {
182
182
  if (p.status !== 200 || p.wordCount < 80) continue;
183
183
  const words = p.text.toLowerCase().match(/[a-z][a-z-]{3,}/g) || [];
184
184
  const freq = new Map();
@@ -1,4 +1,4 @@
1
- import { defineDetector, indexTargets, registryPageFor, pageSubject, safePath } from './framework.js';
1
+ import { defineDetector, hasHtmlDocumentMarkup, indexTargets, isHtmlDocument, isHtmlDocumentUrl, registryPageFor, pageSubject, safePath } from './framework.js';
2
2
  import { isAllowed } from '../crawler/robots.js';
3
3
 
4
4
  const D = [];
@@ -177,7 +177,9 @@ D.push(defineDetector({
177
177
  for (const sm of ctx.site.sitemaps) {
178
178
  for (const u of sm.parsed.urls) {
179
179
  const page = ctx.site.byUrl.get(ctx.site.normalize(u.loc));
180
- if (!page) {
180
+ if (!page && ctx.site.mode === 'url' && ctx.site.crawl?.truncated) {
181
+ continue;
182
+ } else if (!page) {
181
183
  hits.push({
182
184
  subject: { type: 'url', identifier: u.loc, url: u.loc, source_location: sm.source },
183
185
  summary: 'Sitemap URL not present in audited output',
@@ -227,7 +229,7 @@ D.push(defineDetector({
227
229
  verification: 'Inspect the Content-Type response header.',
228
230
  check(ctx) {
229
231
  return indexTargets(ctx)
230
- .filter((p) => p.status === 200 && p.contentType && !p.contentType.includes('text/html'))
232
+ .filter((p) => p.status === 200 && p.contentType && (isHtmlDocumentUrl(p.url) || hasHtmlDocumentMarkup(p)) && !isHtmlDocument(p))
231
233
  .map((p) => ({
232
234
  subject: pageSubject(p),
233
235
  summary: `HTML page served with Content-Type "${p.contentType}"`,
@@ -59,6 +59,7 @@ export function buildSiteFromDir(dir, { baseUrl = 'https://example.test' } = {})
59
59
  export async function buildSiteFromUrl(startUrl, {
60
60
  maxPages = 50, userAgent, pageMaxBytes = 5 * 1024 * 1024,
61
61
  robotsMaxBytes = 512 * 1024, sitemapMaxBytes = 5 * 1024 * 1024,
62
+ fetcher = fetchUrl,
62
63
  } = {}) {
63
64
  const origin = new URL(startUrl).origin;
64
65
  const seen = new Set();
@@ -71,7 +72,7 @@ export async function buildSiteFromUrl(startUrl, {
71
72
  if (seen.has(key)) continue;
72
73
  seen.add(key);
73
74
  try {
74
- const res = await fetchUrl(url, { userAgent, maxBodyBytes: pageMaxBytes });
75
+ const res = await fetcher(url, { userAgent, maxBodyBytes: pageMaxBytes });
75
76
  const page = extractPage({
76
77
  url: res.url, html: res.body, status: res.status, headers: res.headers, redirectChain: res.redirectChain,
77
78
  });
@@ -81,7 +82,8 @@ export async function buildSiteFromUrl(startUrl, {
81
82
  for (const l of page.links) {
82
83
  try {
83
84
  const u = new URL(l.href, res.url);
84
- if (u.origin === origin && !seen.has(u.href.replace(/#.*$/, ''))) queue.push(u.href);
85
+ u.hash = '';
86
+ if (u.origin === origin && !isProviderUtilityPath(u.pathname) && !seen.has(u.href)) queue.push(u.href);
85
87
  } catch { /* unresolvable href — surfaced by LINK detectors */ }
86
88
  }
87
89
  }
@@ -92,7 +94,7 @@ export async function buildSiteFromUrl(startUrl, {
92
94
  let robotsText = null;
93
95
  const sitemaps = [];
94
96
  try {
95
- const r = await fetchUrl(new URL('/robots.txt', origin).href, { userAgent, maxBodyBytes: robotsMaxBytes });
97
+ const r = await fetcher(new URL('/robots.txt', origin).href, { userAgent, maxBodyBytes: robotsMaxBytes });
96
98
  if (r.status === 200) robotsText = r.body;
97
99
  } catch { /* recorded as missing robots */ }
98
100
  const smUrls = robotsText ? parseRobots(robotsText).sitemaps : [new URL('/sitemap.xml', origin).href];
@@ -103,16 +105,24 @@ export async function buildSiteFromUrl(startUrl, {
103
105
  errors.push(`${sitemapUrl.href}: sitemap URL leaves audited origin`);
104
106
  continue;
105
107
  }
106
- const r = await fetchUrl(sitemapUrl.href, { userAgent, maxBodyBytes: sitemapMaxBytes });
108
+ const r = await fetcher(sitemapUrl.href, { userAgent, maxBodyBytes: sitemapMaxBytes });
107
109
  if (r.status === 200) sitemaps.push({ source: sm, parsed: parseSitemap(r.body) });
108
110
  } catch { /* absence handled by TECH detectors */ }
109
111
  }
110
- const site = assembleSite({ baseUrl: origin, pages, robotsText, sitemaps, transport: {}, mode: 'url', location: startUrl });
112
+ const pendingUrls = [...new Set(queue.map((url) => url.replace(/#.*$/, '')).filter((url) => !seen.has(url)))];
113
+ const crawl = {
114
+ maxPages,
115
+ pagesFetched: pages.length,
116
+ truncated: pages.length >= maxPages && pendingUrls.length > 0,
117
+ pendingUrlCount: pendingUrls.length,
118
+ pendingUrls,
119
+ };
120
+ const site = assembleSite({ baseUrl: origin, pages, robotsText, sitemaps, transport: {}, mode: 'url', location: startUrl, crawl });
111
121
  site.fetchErrors = errors;
112
122
  return site;
113
123
  }
114
124
 
115
- function assembleSite({ baseUrl, pages, robotsText, sitemaps, transport, mode, location }) {
125
+ function assembleSite({ baseUrl, pages, robotsText, sitemaps, transport, mode, location, crawl = null }) {
116
126
  const byUrl = new Map();
117
127
  for (const p of pages) byUrl.set(normalize(p.url), p);
118
128
 
@@ -168,9 +178,14 @@ function assembleSite({ baseUrl, pages, robotsText, sitemaps, transport, mode, l
168
178
  outbound,
169
179
  depth,
170
180
  normalize,
181
+ crawl,
171
182
  };
172
183
  }
173
184
 
185
+ function isProviderUtilityPath(pathname) {
186
+ return pathname === '/cdn-cgi' || pathname.startsWith('/cdn-cgi/');
187
+ }
188
+
174
189
  export function normalize(url) {
175
190
  try {
176
191
  const u = new URL(url);
@@ -0,0 +1,167 @@
1
+ import { envelope, observationRun, readInput } from './common.js';
2
+ import { fetchUrl } from '../crawler/fetch.js';
3
+ import { sha256 } from '../shared/io.js';
4
+ import { validateAgainst } from '../shared/schemaValidator.js';
5
+
6
+ async function executeStep(page, step) {
7
+ const locator = step.locator ? page.locator(step.locator).first() : null;
8
+ if (step.action === 'navigate') await page.goto(step.url, { waitUntil: 'networkidle' });
9
+ else if (step.action === 'click') await locator.click();
10
+ else if (step.action === 'fill') {
11
+ const value = process.env[step.value_env];
12
+ if (value == null) throw new Error(`environment input ${step.value_env} is unavailable`);
13
+ await locator.fill(value);
14
+ } else if (step.action === 'select_option') {
15
+ const value = process.env[step.value_env];
16
+ if (value == null) throw new Error(`environment input ${step.value_env} is unavailable`);
17
+ await locator.selectOption(value);
18
+ } else if (step.action === 'check') await locator.check();
19
+ else if (step.action === 'press') await locator.press(step.key);
20
+ else if (step.action === 'wait_for') await locator.waitFor({ state: 'visible' });
21
+ else if (step.action === 'assert_visible' && !(await locator.isVisible())) throw new Error(`locator is not visible: ${step.locator}`);
22
+ else if (step.action === 'scroll') await locator.scrollIntoViewIfNeeded();
23
+ }
24
+
25
+ async function playwrightCapture(profile, plan, playwright) {
26
+ if (profile.authentication_state !== 'anonymous') throw new Error(`authentication state ${profile.authentication_state} requires a disclosed custom adapter`);
27
+ const browserType = playwright[profile.browser.engine];
28
+ if (!browserType) throw new Error(`Playwright engine ${profile.browser.engine} is unavailable`);
29
+ const browser = await browserType.launch({ headless: true });
30
+ try {
31
+ const context = await browser.newContext({
32
+ viewport: profile.device.viewport,
33
+ isMobile: profile.device.is_mobile,
34
+ javaScriptEnabled: profile.javascript_enabled,
35
+ locale: profile.locale,
36
+ });
37
+ try {
38
+ const page = await context.newPage();
39
+ const consoleErrors = [], networkFailures = [], steps = [], stepScreenshots = {};
40
+ page.on('console', (message) => { if (message.type() === 'error') consoleErrors.push(message.text()); });
41
+ page.on('requestfailed', (request) => networkFailures.push({ url: request.url(), error: request.failure()?.errorText || 'unknown' }));
42
+ const response = await page.goto(plan.target, { waitUntil: 'networkidle' });
43
+ for (const step of profile.steps) {
44
+ const record = { step_id: step.step_id, action: step.action, status: 'completed', failure: null, screenshot_ref: null };
45
+ try {
46
+ await executeStep(page, step);
47
+ if (step.capture_screenshot) {
48
+ record.screenshot_ref = `journeys/${profile.profile_id}/steps/${step.step_id}.png`;
49
+ stepScreenshots[record.screenshot_ref] = await page.screenshot({ fullPage: true });
50
+ }
51
+ } catch (error) {
52
+ record.status = 'failed';
53
+ record.failure = error.message;
54
+ steps.push(record);
55
+ if (step.required) throw Object.assign(new Error(`required step ${step.step_id} failed: ${error.message}`), { steps, stepScreenshots });
56
+ continue;
57
+ }
58
+ steps.push(record);
59
+ }
60
+ const dom = await page.content();
61
+ const text = await page.locator('body').innerText();
62
+ const accessibilityTree = typeof page.locator('body').ariaSnapshot === 'function' ? await page.locator('body').ariaSnapshot() : null;
63
+ return {
64
+ final_url: page.url(), status: response?.status() ?? null, browser_version: browser.version(),
65
+ dom, text, accessibility_tree: accessibilityTree, screenshot: await page.screenshot({ fullPage: true }),
66
+ console_errors: consoleErrors, network_failures: networkFailures, steps, step_screenshots: stepScreenshots,
67
+ };
68
+ } finally {
69
+ await context.close();
70
+ }
71
+ } finally {
72
+ await browser.close();
73
+ }
74
+ }
75
+
76
+ export async function observeBrowserPlan(root, options) {
77
+ const input = readInput(options.input);
78
+ const plan = input.value;
79
+ const check = validateAgainst('browser-evidence-plan.schema.json', plan);
80
+ if (!check.valid) throw new Error(`browser evidence plan violates contract: ${check.errors.join('; ')}`);
81
+ if (options.target && options.target !== plan.target) throw new Error('browser evidence target differs from the plan target');
82
+ const profileIds = plan.profiles.map((item) => item.profile_id);
83
+ if (new Set(profileIds).size !== profileIds.length) throw new Error('browser evidence plan contains duplicate profile ids');
84
+ const targetOrigin = new URL(plan.target).origin;
85
+ for (const profile of plan.profiles) {
86
+ const stepIds = profile.steps.map((item) => item.step_id);
87
+ if (new Set(stepIds).size !== stepIds.length) throw new Error(`${profile.profile_id}: duplicate journey step ids`);
88
+ for (const step of profile.steps) {
89
+ if (step.action === 'navigate') {
90
+ if (!step.url) throw new Error(`${profile.profile_id}/${step.step_id}: navigate requires url`);
91
+ if (new URL(step.url).origin !== targetOrigin) throw new Error(`${profile.profile_id}/${step.step_id}: cross-origin navigation is not allowed`);
92
+ } else if (!step.locator) throw new Error(`${profile.profile_id}/${step.step_id}: ${step.action} requires locator`);
93
+ if (['fill', 'select_option'].includes(step.action) && !step.value_env) throw new Error(`${profile.profile_id}/${step.step_id}: ${step.action} requires value_env`);
94
+ if (step.action === 'press' && !step.key) throw new Error(`${profile.profile_id}/${step.step_id}: press requires key`);
95
+ }
96
+ }
97
+
98
+ let playwright = options.playwright;
99
+ if (!options.captureJourney && !playwright) {
100
+ try { playwright = await import('playwright'); } catch {
101
+ const item = envelope('browser_journey', { plan_id: plan.plan_id, target: plan.target }, { method: 'browser', source: 'playwright', state: 'not_evidenced', confidence: 'unknown', limitations: ['Optional Playwright dependency is not installed.'] });
102
+ return observationRun(root, 'observe render', plan.target, [item], { rawInputs: { browser_evidence_plan: input.raw }, incomplete: ['Cross-browser journey collection unavailable: install Playwright and browser engines.'] });
103
+ }
104
+ }
105
+
106
+ const initial = await (options.fetchUrl || fetchUrl)(plan.target, { maxRetries: 1 });
107
+ const observations = [], incomplete = [], artifacts = {
108
+ 'initial/response.html': initial.body,
109
+ 'initial/headers.json': initial.headers || {},
110
+ };
111
+ for (const profile of plan.profiles) {
112
+ const prefix = `journeys/${profile.profile_id}`;
113
+ try {
114
+ const capture = options.captureJourney
115
+ ? await options.captureJourney(profile, plan)
116
+ : await playwrightCapture(profile, plan, playwright);
117
+ if (!capture || typeof capture.dom !== 'string' || typeof capture.text !== 'string' || typeof capture.browser_version !== 'string' || capture.screenshot == null) {
118
+ throw new Error('browser adapter returned an incomplete capture contract');
119
+ }
120
+ const refs = {
121
+ raw_response: 'initial/response.html',
122
+ rendered_dom: `${prefix}/dom.html`,
123
+ rendered_text: `${prefix}/text.txt`,
124
+ accessibility_tree: capture.accessibility_tree == null ? null : `${prefix}/accessibility-tree.txt`,
125
+ screenshot: `${prefix}/final.png`,
126
+ failures: `${prefix}/failures.json`,
127
+ interactions: `${prefix}/steps.json`,
128
+ };
129
+ artifacts[refs.rendered_dom] = capture.dom;
130
+ artifacts[refs.rendered_text] = capture.text;
131
+ if (refs.accessibility_tree) artifacts[refs.accessibility_tree] = capture.accessibility_tree;
132
+ artifacts[refs.screenshot] = capture.screenshot;
133
+ artifacts[refs.failures] = { console_errors: capture.console_errors || [], network_failures: capture.network_failures || [] };
134
+ artifacts[refs.interactions] = capture.steps || [];
135
+ for (const [name, value] of Object.entries(capture.step_screenshots || {})) {
136
+ if (!name.startsWith(`${prefix}/steps/`) || name.includes('..')) throw new Error(`browser adapter returned unsafe artifact path: ${name}`);
137
+ artifacts[name] = value;
138
+ }
139
+ const versionMatches = profile.browser.expected_version == null || profile.browser.expected_version === capture.browser_version;
140
+ const data = {
141
+ plan_id: plan.plan_id, target: plan.target, profile_id: profile.profile_id,
142
+ browser: { ...profile.browser, observed_version: capture.browser_version, version_matches_expectation: versionMatches },
143
+ device: profile.device, javascript_enabled: profile.javascript_enabled, locale: profile.locale,
144
+ consent_state: profile.consent_state, authentication_state: profile.authentication_state,
145
+ final_url: capture.final_url, status: capture.status, dom_hash: sha256(capture.dom), text_hash: sha256(capture.text),
146
+ steps: capture.steps || [], artifact_refs: refs,
147
+ interpretation_boundary: 'Observed differences do not establish semantic, retrieval, citation, ranking, or business impact.',
148
+ };
149
+ const limitations = [...plan.limitations, ...profile.limitations];
150
+ if (!versionMatches) limitations.push('Observed browser version differs from the planned version.');
151
+ observations.push(envelope('browser_journey', data, { method: 'browser', source: `playwright/${profile.browser.engine}`, raw: capture.dom, limitations }));
152
+ } catch (error) {
153
+ incomplete.push(`${profile.profile_id}: ${error.message}`);
154
+ const failureRef = `${prefix}/failure.json`;
155
+ artifacts[failureRef] = { profile_id: profile.profile_id, error: error.message, completed_steps: error.steps || [] };
156
+ for (const [name, value] of Object.entries(error.stepScreenshots || {})) artifacts[name] = value;
157
+ observations.push(envelope('browser_journey', {
158
+ plan_id: plan.plan_id, target: plan.target, profile_id: profile.profile_id, browser: profile.browser,
159
+ device: profile.device, javascript_enabled: profile.javascript_enabled, locale: profile.locale,
160
+ consent_state: profile.consent_state, authentication_state: profile.authentication_state,
161
+ steps: error.steps || [], artifact_refs: { failure: failureRef },
162
+ interpretation_boundary: 'Profile failure does not invalidate successful profiles or establish semantic impact.',
163
+ }, { method: 'browser', source: `playwright/${profile.browser.engine}`, state: 'failed', confidence: 'confirmed', raw: error.message, limitations: [...plan.limitations, ...profile.limitations, error.message] }));
164
+ }
165
+ }
166
+ return observationRun(root, 'observe render', plan.target, observations, { rawInputs: { browser_evidence_plan: input.raw }, incomplete, artifacts });
167
+ }
@@ -29,7 +29,14 @@ async function pdfEvidence(item, file, artifacts) {
29
29
 
30
30
  function transcriptEvidence(item, file, artifacts) {
31
31
  const raw = fs.readFileSync(file, 'utf8');
32
- const cues = raw.split(/\r?\n\r?\n/).map((block) => { const lines = block.split(/\r?\n/).filter(Boolean); const timing = lines.find((line) => line.includes('-->')) || null; const text = lines.filter((line) => line !== 'WEBVTT' && line !== timing && !/^\d+$/.test(line)).join(' ').replace(/<[^>]+>/g, '').trim(); return text ? { timing, text } : null; }).filter(Boolean);
32
+ const cues = raw.split(/\r?\n\r?\n/).map((block) => {
33
+ const lines = block.split(/\r?\n/).filter(Boolean);
34
+ const timing = lines.find((line) => line.includes('-->')) || null;
35
+ const fragment = parse(lines.filter((line) => line !== 'WEBVTT' && line !== timing && !/^\d+$/.test(line)).join(' '));
36
+ for (const node of fragment.querySelectorAll('script,style')) node.remove();
37
+ const text = fragment.textContent.replace(/\s+/g, ' ').trim();
38
+ return text ? { timing, text } : null;
39
+ }).filter(Boolean);
33
40
  const text = cues.map((cue) => cue.text).join(' ');
34
41
  artifacts[`media/${item.media_id}/transcript.txt`] = text;
35
42
  return envelope('media_transcript', { media_id: item.media_id, source_url: item.source_url, page_url: item.page_url, claim_ids: item.claim_ids, permission_status: item.permission_status, language: item.language || null, published_at: item.published_at || null, cues, word_count: text ? text.split(/\s+/).length : 0 }, { method: 'owner_import', source: file, raw, limitations: ['Speaker identity, transcription accuracy, timing accuracy, and media parity require human verification.', 'Transcript ingestion does not establish that linked claims are supported.'] });