oh-my-opencode 5.1.47 → 5.1.51

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 (497) hide show
  1. package/dist/agents/refusal-rule.d.ts +7 -0
  2. package/dist/cli/index.js +1194 -752
  3. package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
  4. package/dist/cli/service-auth/commands.d.ts +2 -4
  5. package/dist/cli/service-auth/index.d.ts +1 -1
  6. package/dist/cli/service-auth/keystore.d.ts +26 -2
  7. package/dist/cli/service-auth/protocol.d.ts +7 -1
  8. package/dist/cli/service-auth/session.d.ts +6 -0
  9. package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
  10. package/dist/cli-node/index.js +1194 -752
  11. package/dist/config/schema/hooks.d.ts +1 -0
  12. package/dist/create-hooks.d.ts +1 -0
  13. package/dist/features/boulder-state/storage.d.ts +1 -1
  14. package/dist/features/boulder-state/types.d.ts +1 -1
  15. package/dist/hooks/atlas/idle-continuation.d.ts +2 -1
  16. package/dist/hooks/atlas/types.d.ts +9 -1
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/momus-review-persistence/hook.d.ts +19 -0
  19. package/dist/hooks/momus-review-persistence/index.d.ts +1 -0
  20. package/dist/hooks/momus-review-persistence/review-resolution.d.ts +20 -0
  21. package/dist/hooks/prometheus-md-only/constants.d.ts +2 -0
  22. package/dist/hooks/prometheus-md-only/fixtures/denial-log.d.ts +1 -0
  23. package/dist/hooks/prometheus-md-only/fixtures/guarded-hashline.d.ts +1 -0
  24. package/dist/hooks/prometheus-md-only/fixtures/invoke-before.d.ts +7 -0
  25. package/dist/hooks/prometheus-md-only/fixtures/opencode-patch-parser.d.ts +2 -0
  26. package/dist/hooks/prometheus-md-only/hook.d.ts +5 -1
  27. package/dist/hooks/prometheus-md-only/path-policy.d.ts +2 -9
  28. package/dist/hooks/prometheus-md-only/vendor/opencode-patch-parser.d.ts +22 -0
  29. package/dist/index.js +2322 -1045
  30. package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
  31. package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
  32. package/dist/shared/posthog-activity-state.d.ts +1 -0
  33. package/dist/shared/posthog.d.ts +1 -2
  34. package/dist/shared/resolve-file-write-path.d.ts +6 -0
  35. package/dist/skills/ast-grep/README.md +1 -1
  36. package/dist/skills/ast-grep/install.ps1 +5 -3
  37. package/dist/skills/ast-grep/install.sh +4 -5
  38. package/dist/skills/ast-grep/references/install.md +2 -2
  39. package/dist/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  40. package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
  41. package/dist/skills/coding-agent-sessions/AGENTS.md +5 -4
  42. package/dist/skills/coding-agent-sessions/SKILL.md +11 -11
  43. package/dist/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  44. package/dist/skills/coding-agent-sessions/references/codex.md +4 -4
  45. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  46. package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  47. package/dist/skills/frontend/ATTRIBUTION.md +1 -1
  48. package/dist/skills/frontend/SKILL.md +34 -12
  49. package/dist/skills/frontend/references/design/README.md +2 -2
  50. package/dist/skills/frontend/references/design/_INDEX.md +2 -1
  51. package/dist/skills/frontend/references/design/component-catalogs.md +14 -10
  52. package/dist/skills/frontend/references/design/design-system-architecture.md +19 -6
  53. package/dist/skills/frontend/references/design/grounding.md +29 -0
  54. package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  55. package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  56. package/dist/skills/ultimate-browsing/SKILL.md +5 -4
  57. package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  58. package/dist/skills/ultimate-browsing/engine/__main__.py +9 -6
  59. package/dist/skills/ultimate-browsing/engine/summary.py +1 -1
  60. package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  61. package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  62. package/dist/skills/ulw-research/AGENTS.md +8 -4
  63. package/dist/skills/ulw-research/SKILL.md +7 -259
  64. package/dist/skills/ulw-research/references/deliverable-phase.md +68 -24
  65. package/dist/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  66. package/dist/skills/ulw-research/references/fact-ledger.md +42 -8
  67. package/dist/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  68. package/dist/skills/ulw-research/references/markdown-blocks.md +12 -0
  69. package/dist/skills/ulw-research/references/report-gates.md +14 -6
  70. package/dist/skills/ulw-research/references/research-collection.md +195 -0
  71. package/dist/skills/ulw-research/references/research-delivery.md +123 -0
  72. package/dist/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  73. package/dist/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  74. package/dist/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  75. package/dist/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  76. package/dist/skills/ulw-research/scripts/contracts.mjs +16 -15
  77. package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -109
  78. package/dist/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  79. package/dist/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  80. package/dist/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  81. package/dist/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  82. package/dist/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  83. package/dist/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
  84. package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
  85. package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  86. package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
  87. package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  88. package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  89. package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
  90. package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
  91. package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
  92. package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
  93. package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
  94. package/dist/skills/ulw-research/scripts/fact-commands.mjs +40 -62
  95. package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  96. package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  97. package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  98. package/dist/skills/ulw-research/scripts/fact-fill.mjs +9 -6
  99. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  100. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  101. package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  102. package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  103. package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  104. package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  105. package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  106. package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  107. package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  108. package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  109. package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  110. package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
  111. package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  112. package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  113. package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  114. package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  115. package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  116. package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  117. package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  118. package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  119. package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  120. package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
  121. package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
  122. package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
  123. package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  124. package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  125. package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  126. package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  127. package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
  128. package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  129. package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  130. package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
  131. package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
  132. package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  133. package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  134. package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
  135. package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  136. package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
  137. package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  138. package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  139. package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  140. package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  141. package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  142. package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  143. package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  144. package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  145. package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  146. package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  147. package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  148. package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
  149. package/dist/skills/ulw-research/scripts/report-tools.test.ts +6 -560
  150. package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  151. package/dist/skills/ulw-research/scripts/source-commands.mjs +87 -29
  152. package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  153. package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  154. package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  155. package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  156. package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
  157. package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  158. package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  159. package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  160. package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  161. package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  162. package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  163. package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  164. package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  165. package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  166. package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  167. package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  168. package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  169. package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  170. package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  171. package/dist/skills/ulw-research/scripts/units.mjs +14 -3
  172. package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
  173. package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  174. package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  175. package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  176. package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  177. package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  178. package/dist/tools/delegate-task/executor-types.d.ts +1 -0
  179. package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
  180. package/dist/tools/delegate-task/types.d.ts +1 -0
  181. package/dist/tools/skill/description-formatter.d.ts +2 -1
  182. package/dist/tools/skill/types.d.ts +6 -0
  183. package/dist/tui.js +131 -33
  184. package/package.json +18 -15
  185. package/packages/git-bash-mcp/package.json +1 -1
  186. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  187. package/packages/omo-codex/plugin/README.md +1 -1
  188. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  189. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  190. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  191. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  192. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  193. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  194. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  195. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  196. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  197. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  198. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
  199. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
  200. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  201. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  202. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  203. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  204. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  205. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  206. package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
  207. package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
  208. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
  209. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
  210. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  211. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  212. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
  213. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
  214. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
  215. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
  216. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
  217. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
  218. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  219. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  220. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  221. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  222. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  223. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
  224. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  225. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  226. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  227. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  228. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  229. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  230. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  231. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  232. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  233. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  234. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  235. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  236. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  237. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  238. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  239. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  240. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  241. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  242. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  243. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  244. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  245. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  246. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  247. package/packages/omo-codex/plugin/package-lock.json +16 -16
  248. package/packages/omo-codex/plugin/package.json +1 -1
  249. package/packages/omo-codex/plugin/shared/package.json +1 -1
  250. package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
  251. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
  252. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
  253. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  254. package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  255. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  256. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
  257. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
  258. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  259. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
  260. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  261. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  262. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
  263. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
  264. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  265. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
  266. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
  267. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
  268. package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
  269. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  270. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  271. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  272. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  273. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
  274. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  275. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
  276. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  277. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
  278. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
  279. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  280. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  281. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
  282. package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
  283. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -259
  284. package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +68 -24
  285. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  286. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
  287. package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  288. package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
  289. package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +14 -6
  290. package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
  291. package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
  292. package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  293. package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +16 -15
  294. package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  295. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  296. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
  297. package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
  298. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
  299. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
  300. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
  301. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
  302. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +40 -62
  303. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  304. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +9 -6
  305. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  306. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  307. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  308. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  309. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  310. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  311. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
  312. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  313. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  314. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  315. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  316. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  317. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  318. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  319. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
  320. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
  321. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
  322. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  323. package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  324. package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
  325. package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  326. package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
  327. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  328. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
  329. package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
  330. package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  331. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  332. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  333. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  334. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
  335. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +87 -29
  336. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  337. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  338. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
  339. package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  340. package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
  341. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
  342. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
  343. package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
  344. package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
  345. package/packages/shared-skills/skill-source-filter.mjs +6 -2
  346. package/packages/shared-skills/skills/ast-grep/README.md +1 -1
  347. package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
  348. package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
  349. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  350. package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  351. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  352. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
  353. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
  354. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  355. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
  356. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  357. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  358. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
  359. package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
  360. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  361. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
  362. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
  363. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
  364. package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
  365. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  366. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  367. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
  368. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  369. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
  370. package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
  371. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  372. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  373. package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
  374. package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -259
  375. package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +68 -24
  376. package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  377. package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
  378. package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  379. package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
  380. package/packages/shared-skills/skills/ulw-research/references/report-gates.md +14 -6
  381. package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
  382. package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
  383. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  384. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  385. package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  386. package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  387. package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +16 -15
  388. package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -109
  389. package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  390. package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  391. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  392. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  393. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  394. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
  395. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
  396. package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  397. package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
  398. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  399. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  400. package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
  401. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
  402. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
  403. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
  404. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
  405. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +40 -62
  406. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  407. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  408. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  409. package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +9 -6
  410. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  411. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  412. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  413. package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  414. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  415. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  416. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  417. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  418. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  419. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  420. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  421. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
  422. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  423. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  424. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  425. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  426. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  427. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  428. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  429. package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  430. package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  431. package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
  432. package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
  433. package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
  434. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  435. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  436. package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  437. package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  438. package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
  439. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  440. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  441. package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
  442. package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
  443. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  444. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  445. package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
  446. package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  447. package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
  448. package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  449. package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  450. package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  451. package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  452. package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  453. package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  454. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  455. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  456. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  457. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  458. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  459. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
  460. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +6 -560
  461. package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  462. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +87 -29
  463. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  464. package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  465. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  466. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  467. package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
  468. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  469. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  470. package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  471. package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  472. package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  473. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  474. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  475. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  476. package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  477. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  478. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  479. package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  480. package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  481. package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  482. package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
  483. package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
  484. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  485. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  486. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  487. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  488. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  489. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
  490. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
  491. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
  492. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
  493. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
  494. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
  495. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
  496. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
  497. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
@@ -0,0 +1,141 @@
1
+ import { describe, expect, onTestFinished, test } from "bun:test"
2
+ import { createHash } from "node:crypto"
3
+ import { copyFileSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
4
+ import { tmpdir } from "node:os"
5
+ import { delimiter, join } from "node:path"
6
+ import { PROMOTION } from "./fact-commands-meaning.mjs"
7
+ import { writeFidelityRecord } from "./fidelity-records.mjs"
8
+ import { PAIR_KINDS } from "./fact-pairs.mjs"
9
+ import { VERDICT_SCHEMA } from "./meaning-check.mjs"
10
+ import { POLISH_MARKUP_REASON } from "./polish-apply.mjs"
11
+ import { COMMANDS, run } from "./report-tools.mjs"
12
+ import { SCRIPT, FIXTURES, sessionDir, nodeWithoutBun, defectsFile, FIDELITY, sha256, CliRow, CliJson, nodeJson, fidelitySession, verify, codesOf, Pair, pairedSession, verdicts, calibrationRows, runLines, PolishJson, polishSession, polishApply, setField, fillTemplate, textSource, ledgerRow } from "./tests/report-tools-support"
13
+
14
+
15
+
16
+ describe("polish wiring under node", () => {
17
+ test("#given the fixture edits #when fact polish-apply runs #then it exits 0, applies the wording edit, and rejects the numeral edit", () => {
18
+ const { dir } = polishSession()
19
+ const applied = polishApply(dir, join(FIDELITY, "polish-edits.json"))
20
+ const polished = readFileSync(join(dir, "report.polished.html"), "utf8")
21
+ expect(applied.code).toBe(0)
22
+ expect(applied.json.data).toMatchObject({ applied: 1, rejected: 1, unlocated: 0 })
23
+ expect(applied.json.defects.map((d) => [d.code, d.index])).toEqual([["polish_edit_rejected", 1]])
24
+ expect(polished).toContain("Collected from a single cited public page")
25
+ expect(polished).toContain("retrieved 2026-10-01")
26
+ expect(polished).not.toContain("2026-10-02")
27
+ })
28
+
29
+ test("#given an edit that adds an attribute #when polish-apply and polish-diff run #then apply refuses it as markup changed and diff exits 1", () => {
30
+ const { dir } = polishSession()
31
+ const html = readFileSync(join(dir, "report.html"), "utf8")
32
+ const edits = join(dir, "attribute.json")
33
+ writeFileSync(edits, JSON.stringify([{ before: "<h2>Findings</h2>", after: '<h2 id="findings">Findings</h2>', reason: "anchor" }]))
34
+ const applied = polishApply(dir, edits)
35
+ expect(applied.code).toBe(0)
36
+ expect(applied.json.data).toMatchObject({ applied: 0, rejected: 1, unlocated: 0 })
37
+ expect(applied.json.defects.map((d) => [d.code, d.index])).toEqual([["polish_edit_rejected", 0]])
38
+ expect(applied.json.defects[0]?.reason).toContain("markup changed")
39
+ expect(readFileSync(join(dir, "report.polished.html"), "utf8")).toBe(html)
40
+ writeFileSync(join(dir, "attribute.html"), html.replace("<h2>Findings</h2>", '<h2 id="findings">Findings</h2>'))
41
+ const diffed = nodeJson(["fact", "polish-diff", "--before", join(dir, "report.html"), "--after", join(dir, "attribute.html"), "--ledger", join(dir, "fact-ledger.json"), "--session-dir", dir])
42
+ expect(diffed.code).toBe(1)
43
+ expect(codesOf(diffed.json)).toContain("polish_diff_fail")
44
+ expect(JSON.stringify(diffed.json)).toContain("markup changed")
45
+ })
46
+
47
+ test("#given an edit whose before holds & #when fact polish-apply runs #then it prints polish-apply's own markup reason verbatim for that edit", () => {
48
+ const { dir } = polishSession()
49
+ const before = "Acme & Bolt"
50
+ const edits = join(dir, "ampersand.json")
51
+ writeFileSync(edits, JSON.stringify([{ before, after: "Acme and Bolt", reason: "ampersand" }]))
52
+ const applied = polishApply(dir, edits)
53
+ const line = ` rejected edit 0 ("${before}"): ${POLISH_MARKUP_REASON}`
54
+ expect(applied.code).toBe(0)
55
+ expect(applied.json.data).toMatchObject({ applied: 0, rejected: 1, unlocated: 0 })
56
+ expect(applied.json.defects.map((d) => [d.code, d.index, d.reason])).toEqual([["polish_edit_rejected", 0, POLISH_MARKUP_REASON]])
57
+ expect(applied.stderr.split("\n")).toContain(line)
58
+ })
59
+
60
+ test("#given a polished copy edited by hand #when fact polish-diff runs #then it exits 1 with polish_diff_fail", () => {
61
+ const { dir } = polishSession()
62
+ const html = readFileSync(join(dir, "report.html"), "utf8")
63
+ writeFileSync(join(dir, "hand.html"), html.replace("320 m", "321 m"))
64
+ const diffed = nodeJson(["fact", "polish-diff", "--before", join(dir, "report.html"), "--after", join(dir, "hand.html"), "--ledger", join(dir, "fact-ledger.json"), "--session-dir", dir])
65
+ expect(diffed.code).toBe(1)
66
+ expect(codesOf(diffed.json)).toContain("polish_diff_fail")
67
+ })
68
+
69
+ test("#given an accepted subject and object swap #when fact pairs runs with --changed-since #then only that sentence's pair is emitted, with the new text", () => {
70
+ const { dir, s } = polishSession()
71
+ const edits = join(dir, "swap.json")
72
+ writeFileSync(edits, JSON.stringify([{ before: "Acme acquired Bolt", after: "Bolt acquired Acme", reason: "word order" }]))
73
+ const applied = polishApply(dir, edits)
74
+ const map = join(dir, "report.html.fill-map.json")
75
+ const changed = nodeJson(["fact", "pairs", join(dir, "report.polished.html"), "--changed-since", map, "--out", join(dir, "pairs-changed.json"), ...s])
76
+ const written = JSON.parse(readFileSync(join(dir, "pairs-changed.json"), "utf8"))
77
+ expect(applied.json.data).toMatchObject({ applied: 1, rejected: 0 })
78
+ expect(changed.code).toBe(0)
79
+ expect(written.pairs.map((p: Pair) => [p.kind, p.fact_ids])).toEqual([["quote", ["F1"]]])
80
+ expect(written.pairs[0].sentence).toContain("Bolt acquired Acme")
81
+ })
82
+ })
83
+
84
+ describe("markdown editions under node", () => {
85
+ const MD = ["# Bridge", "", "## Findings", "", "The span length is {{F1:span_len}} [S4].", "", "The operator wrote {{Q1:completion}} [S4].", "", "## How this report was made", "", "Collected from one cited public page [S4].", "", "## Sources", "", "1. [S4] Bridge page, retrieved 2026-10-01.", ""].join("\n")
86
+
87
+ function mdSession() {
88
+ const session = fidelitySession()
89
+ writeFileSync(join(session.dir, "report.src.md"), MD)
90
+ const filled = nodeJson(["fact", "fill", join(session.dir, "report.src.md"), "--format", "md", "--out", join(session.dir, "report.md"), ...session.s])
91
+ return { ...session, filled }
92
+ }
93
+
94
+ test("#given a markdown source #when filled and verified as md #then verify passes and records the md bytes", () => {
95
+ const { dir, filled } = mdSession()
96
+ const checked = verify(dir, "report.md", ["--format", "md"])
97
+ expect(filled.code).toBe(0)
98
+ expect(readFileSync(join(dir, "report.md"), "utf8")).toContain("The span length is 320 m [S4].")
99
+ expect(checked.code).toBe(0)
100
+ expect(checked.json.defects).toEqual([])
101
+ expect(JSON.parse(readFileSync(join(dir, "fidelity-defects.json"), "utf8")).artifact_sha256).toBe(sha256(join(dir, "report.md")))
102
+ })
103
+
104
+ test("#given a filled markdown edition #when a value is hand-edited or a number typed #then md verify exits 1 with the code", () => {
105
+ const { dir } = mdSession()
106
+ const md = readFileSync(join(dir, "report.md"), "utf8")
107
+ writeFileSync(join(dir, "typed.md"), md.replace("## How", "Revenue grew 12% [S4].\n\n## How"))
108
+ copyFileSync(join(dir, "report.md.fill-map.json"), join(dir, "typed.md.fill-map.json"))
109
+ const typed = verify(dir, "typed.md", ["--format", "md"])
110
+ expect(typed.code).toBe(1)
111
+ expect(codesOf(typed.json)).toContain("untraceable_number")
112
+ })
113
+
114
+ test("#given a filled markdown edition with an unterminated fence #when verified or paired #then both refuse with exit 2", () => {
115
+ const { dir, s } = mdSession()
116
+ writeFileSync(join(dir, "fence.md"), `${readFileSync(join(dir, "report.md"), "utf8")}\n\`\`\`\nunclosed code\n`)
117
+ copyFileSync(join(dir, "report.md.fill-map.json"), join(dir, "fence.md.fill-map.json"))
118
+ const checked = verify(dir, "fence.md", ["--format", "md"])
119
+ expect(checked.code).toBe(2)
120
+ expect(checked.stderr).toContain("unterminated_fence")
121
+ expect(nodeJson(["fact", "pairs", join(dir, "fence.md"), "--out", join(dir, "pairs.json"), ...s]).code).toBe(2)
122
+ })
123
+
124
+ test("#given a filled markdown edition #when fact pairs runs on it #then it pairs the same quotes as the html edition", () => {
125
+ const { dir, s } = mdSession()
126
+ const pairs = nodeJson(["fact", "pairs", join(dir, "report.md"), "--out", join(dir, "pairs.json"), ...s])
127
+ expect(pairs.code).toBe(0)
128
+ expect(JSON.parse(readFileSync(join(dir, "pairs.json"), "utf8")).pairs.map((p: Pair) => p.fact_ids)).toEqual([["F1"], ["Q1"]])
129
+ })
130
+ })
131
+
132
+ describe("repair decide with several defect files", () => {
133
+ test("#given two --defects files #when decided #then the attempt signature carries both codes", async () => {
134
+ const dir = sessionDir()
135
+ const state = join(dir, "repair-state.json")
136
+ await run(["repair", "decide", "--state", state, "--defects", defectsFile(dir, "a.json", ["heading_generic"]), "--defects", defectsFile(dir, "b.json", ["untraceable_number"])])
137
+ const signature = JSON.parse(readFileSync(state, "utf8")).attempts[0].signature
138
+ expect(signature).toContain("heading_generic")
139
+ expect(signature).toContain("untraceable_number")
140
+ })
141
+ })
@@ -0,0 +1,135 @@
1
+ import { describe, expect, onTestFinished, test } from "bun:test"
2
+ import { createHash } from "node:crypto"
3
+ import { copyFileSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
4
+ import { tmpdir } from "node:os"
5
+ import { delimiter, join } from "node:path"
6
+ import { PROMOTION } from "./fact-commands-meaning.mjs"
7
+ import { writeFidelityRecord } from "./fidelity-records.mjs"
8
+ import { PAIR_KINDS } from "./fact-pairs.mjs"
9
+ import { VERDICT_SCHEMA } from "./meaning-check.mjs"
10
+ import { POLISH_MARKUP_REASON } from "./polish-apply.mjs"
11
+ import { COMMANDS, run } from "./report-tools.mjs"
12
+ import { SCRIPT, FIXTURES, sessionDir, nodeWithoutBun, defectsFile, FIDELITY, sha256, CliRow, CliJson, nodeJson, fidelitySession, verify, codesOf, Pair, pairedSession, verdicts, calibrationRows, runLines, PolishJson, polishSession, polishApply, setField, fillTemplate, textSource, ledgerRow } from "./tests/report-tools-support"
13
+
14
+
15
+
16
+ describe("fidelity delivery barrier", () => {
17
+ /**
18
+ * The locked brief has meaning check on, so a deliverable session also carries a clean meaning record:
19
+ * one edition's (fidelity-meaning-defects.<format>.json), or without a format the legacy session record.
20
+ */
21
+ const meaningRan = (dir: string, report = "report.html", format?: string) =>
22
+ writeFidelityRecord(join(dir, format === undefined ? "fidelity-meaning-defects.json" : `fidelity-meaning-defects.${format}.json`), "meaning", { artifact_sha256: sha256(join(dir, report)), report: join(dir, report), defects: [] })
23
+
24
+ async function deliveredSession(codes: string[]) {
25
+ const { dir, s } = fidelitySession()
26
+ nodeJson(["fact", "fill", join(dir, "report.src.html"), "--out", join(dir, "report.html"), ...s])
27
+ meaningRan(dir)
28
+ const record = (list: string[]) => writeFidelityRecord(join(dir, "fidelity-defects.json"), "fidelity", { artifact_sha256: sha256(join(dir, "report.html")), report: join(dir, "report.html"), defects: list.map((code) => ({ code, message: code })) })
29
+ record(codes)
30
+ await run(["outcome", "init", "--session-dir", dir, "--promised", "html"])
31
+ await run(["outcome", "set", "html", "delivered", "--path", join(dir, "report.html"), "--verified-by", join(dir, "fidelity-defects.json"), "--session-dir", dir])
32
+ const decide = ["repair", "decide", "--state", join(dir, "repair-state.json"), "--defects", join(dir, "fidelity-defects.json"), "--artifact-bytes", "4096", "--renders", "1", "--session-dir", dir]
33
+ await run(decide)
34
+ const decision = await run(decide)
35
+ return { dir, record, decision }
36
+ }
37
+
38
+ test("#given a clean meaning record #when the report is edited and fact verify re-run #then the stale meaning record refuses, and a fresh one passes", async () => {
39
+ // given: meaning check on, readers clean, the edition verified and delivered
40
+ const { dir, s } = pairedSession()
41
+ const report = join(dir, "report.html")
42
+ const clean = [{ pair_id: "P1", verdict: "ok" }, { pair_id: "P2", verdict: "ok" }]
43
+ const readers = () => nodeJson(["fact", "meaning-check", "--pairs", join(dir, "pairs.json"), "--verdicts", verdicts(dir, "cheap.json", "cheap", clean), "--verdicts", verdicts(dir, "strong.json", "strong", clean), ...s])
44
+ expect(readers().code).toBe(0)
45
+ expect(verify(dir, "report.html").code).toBe(0)
46
+ await run(["outcome", "init", "--session-dir", dir, "--promised", "html"])
47
+ await run(["outcome", "set", "html", "delivered", "--path", report, "--verified-by", join(dir, "fidelity-defects.json"), "--session-dir", dir])
48
+ const first = await run(["outcome", "verify", "--session-dir", dir])
49
+ // when: draft 2 (a repair rewrite) is re-verified by fact verify only
50
+ writeFileSync(report, `${readFileSync(report, "utf8")}\n<!-- draft 2 -->\n`)
51
+ expect(verify(dir, "report.html").code).toBe(0)
52
+ const stale = await run(["outcome", "verify", "--session-dir", dir])
53
+ // when: the meaning readers run again on draft 2
54
+ expect(nodeJson(["fact", "pairs", report, "--out", join(dir, "pairs.json"), ...s]).code).toBe(0)
55
+ expect(readers().code).toBe(0)
56
+ const fresh = await run(["outcome", "verify", "--session-dir", dir])
57
+ // then
58
+ expect(first.exitCode).toBe(0)
59
+ expect(stale.exitCode).toBe(1)
60
+ expect(stale.json.problems).toContainEqual(expect.objectContaining({ code: "edition_unverified", path: join(dir, "fidelity-meaning-defects.json"), message: expect.stringContaining("meaning record") }))
61
+ expect(fresh.exitCode).toBe(0)
62
+ })
63
+
64
+ test("#given an unregistered appendix value #when verified #then untraceable_number and outcome verify refuses", async () => {
65
+ const { dir, s } = fidelitySession()
66
+ nodeJson(["fact", "fill", join(dir, "report.src.html"), "--out", join(dir, "report.html"), ...s])
67
+ const html = readFileSync(join(dir, "report.html"), "utf8").replace("<h2>How", "<h2>Appendix</h2>\n<p>Revenue grew 12% [S4].</p>\n<h2>How")
68
+ writeFileSync(join(dir, "report.html"), html)
69
+ const checked = verify(dir, "report.html")
70
+ await run(["outcome", "init", "--session-dir", dir, "--promised", "html"])
71
+ await run(["outcome", "set", "html", "delivered", "--path", join(dir, "report.html"), "--verified-by", join(dir, "fidelity-defects.json"), "--session-dir", dir])
72
+ const outcome = await run(["outcome", "verify", "--session-dir", dir])
73
+ expect(codesOf(checked.json)).toContain("untraceable_number")
74
+ expect(outcome.exitCode).toBe(1)
75
+ expect(outcome.json.problems.map((p: { code: string }) => p.code)).toContain("fidelity_unresolved")
76
+ })
77
+
78
+ for (const code of ["untraceable_number", "unbound_sentence"]) {
79
+ test(`#given ${code} left after repair delivers on exhaustion #when verified and finished #then both refuse, and an empty record passes`, async () => {
80
+ const { dir, record, decision } = await deliveredSession([code])
81
+ const refused = await run(["outcome", "verify", "--session-dir", dir])
82
+ const finish = await run(["outcome", "finish", "--session-dir", dir])
83
+ record([])
84
+ const passed = await run(["outcome", "verify", "--session-dir", dir])
85
+ const finished = await run(["outcome", "finish", "--session-dir", dir])
86
+ expect(decision.json.decision.action).toBe("deliver")
87
+ expect(refused.exitCode).toBe(1)
88
+ expect(JSON.stringify(refused.json.problems)).toContain(`fidelity_unresolved: ${code}`)
89
+ expect(finish.exitCode).toBe(1)
90
+ expect(passed.exitCode).toBe(0)
91
+ expect(finished.exitCode).toBe(0)
92
+ })
93
+ }
94
+
95
+ test("#given a clean main report and an inline edition #when the edition lacks or mismatches its verify record #then edition_unverified, and its own record passes", async () => {
96
+ // given
97
+ const { dir, s } = fidelitySession()
98
+ // a stylesheet and an image, so the inline edition's bytes differ from report.html
99
+ writeFileSync(join(dir, "report.css"), "body { margin: 0 auto; max-width: 42rem; }")
100
+ writeFileSync(join(dir, "report.src.html"), readFileSync(join(dir, "report.src.html"), "utf8").replace("</title>", '</title><link rel="stylesheet" href="report.css">').replace("<h2>Findings</h2>", '<h2>Findings</h2>\n<img src="assets/bridge.png" alt="The bridge from the south bank">'))
101
+ nodeJson(["fact", "fill", join(dir, "report.src.html"), "--out", join(dir, "report.html"), ...s])
102
+ expect(verify(dir, "report.html").code).toBe(0)
103
+ meaningRan(dir)
104
+ expect(nodeJson(["fact", "fill", join(dir, "report.src.html"), "--inline", "--out", join(dir, "report.inline.html"), ...s]).code).toBe(0)
105
+ const inline = readFileSync(join(dir, "report.inline.html"), "utf8")
106
+ expect(inline).toContain("<style>body { margin: 0 auto; max-width: 42rem; }</style>")
107
+ expect(inline).toContain(`src="${join(dir, "assets", "bridge.png")}"`)
108
+ expect(sha256(join(dir, "report.inline.html"))).not.toBe(sha256(join(dir, "report.html")))
109
+ // html keeps the legacy session meaning record; the byte-different inline edition needs its own
110
+ meaningRan(dir, "report.inline.html", "pdf")
111
+ await run(["outcome", "init", "--session-dir", dir, "--promised", "html,pdf"])
112
+ await run(["outcome", "set", "html", "delivered", "--path", join(dir, "report.html"), "--verified-by", join(dir, "fidelity-defects.json"), "--session-dir", dir])
113
+ const problems = async () => {
114
+ const result = await run(["outcome", "verify", "--session-dir", dir])
115
+ return { exitCode: result.exitCode, codes: result.json.problems.map((p: { code: string }) => p.code) }
116
+ }
117
+ // when: no --verified-by
118
+ await run(["outcome", "set", "pdf", "delivered", "--path", join(dir, "report.inline.html"), "--session-dir", dir])
119
+ const missing = await problems()
120
+ // when: a record for different bytes
121
+ expect(verify(dir, "report.inline.html", ["--out", join(dir, "fidelity-inline.json")]).code).toBe(0)
122
+ writeFileSync(join(dir, "report.inline.html"), inline.replace("320,000 mm", "330,000 mm"))
123
+ await run(["outcome", "set", "pdf", "delivered", "--path", join(dir, "report.inline.html"), "--verified-by", join(dir, "fidelity-inline.json"), "--session-dir", dir])
124
+ const altered = await problems()
125
+ // when: restored to the verified bytes
126
+ writeFileSync(join(dir, "report.inline.html"), inline)
127
+ const matched = await problems()
128
+ // then
129
+ expect({ missing, altered, matched }).toEqual({
130
+ missing: { exitCode: 1, codes: ["edition_unverified"] },
131
+ altered: { exitCode: 1, codes: ["edition_unverified", "edition_unverified"] },
132
+ matched: { exitCode: 0, codes: [] },
133
+ })
134
+ })
135
+ })
@@ -0,0 +1,231 @@
1
+ import { describe, expect, onTestFinished, test } from "bun:test"
2
+ import { createHash } from "node:crypto"
3
+ import { copyFileSync, existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
4
+ import { tmpdir } from "node:os"
5
+ import { delimiter, join } from "node:path"
6
+ import { PROMOTION } from "./fact-commands-meaning.mjs"
7
+ import { writeFidelityRecord } from "./fidelity-records.mjs"
8
+ import { PAIR_KINDS } from "./fact-pairs.mjs"
9
+ import { VERDICT_SCHEMA } from "./meaning-check.mjs"
10
+ import { POLISH_MARKUP_REASON } from "./polish-apply.mjs"
11
+ import { COMMANDS, run } from "./report-tools.mjs"
12
+ import { SCRIPT, FIXTURES, NOW, sessionDir, nodeWithoutBun, defectsFile, FIDELITY, sha256, CliRow, CliJson, nodeJson, fidelitySession, verify, codesOf, Pair, pairedSession, verdicts, calibrationRows, runLines, PolishJson, polishSession, polishApply, setField, fillTemplate, textSource, ledgerRow } from "./tests/report-tools-support"
13
+
14
+
15
+
16
+ describe("fidelity brief lock and policy under node", () => {
17
+ test("#given a filled session whose brief turns pending #when each reader-facing command runs #then all six exit 1 with only fidelity_interview_incomplete and write nothing", () => {
18
+ // given
19
+ const { dir, s } = pairedSession()
20
+ copyFileSync(join(FIXTURES, "fidelity-brief-pending.md"), join(dir, "brief.md"))
21
+ for (const name of ["fidelity-defects.json", "pairs.json"]) rmSync(join(dir, name), { force: true })
22
+ const drift = verdicts(dir, "cheap.json", "cheap", [])
23
+ writeFileSync(join(dir, "edits.json"), "[]")
24
+ // when
25
+ const runs = {
26
+ fill: nodeJson(["fact", "fill", join(dir, "report.src.html"), "--out", join(dir, "again.html"), ...s]),
27
+ verify: verify(dir, "report.html"),
28
+ pairs: nodeJson(["fact", "pairs", join(dir, "report.html"), "--out", join(dir, "pairs.json"), ...s]),
29
+ meaning: nodeJson(["fact", "meaning-check", "--pairs", join(dir, "absent-pairs.json"), "--verdicts", drift, ...s]),
30
+ polishApply: nodeJson(["fact", "polish-apply", join(dir, "report.html"), "--edits", join(dir, "edits.json"), "--out", join(dir, "polished.html"), ...s]),
31
+ polishDiff: nodeJson(["fact", "polish-diff", "--before", join(dir, "report.html"), "--after", join(dir, "report.html"), "--out", join(dir, "polish.json"), ...s]),
32
+ }
33
+ // then
34
+ for (const [name, result] of Object.entries(runs)) {
35
+ expect({ name, code: result.code, codes: codesOf(result.json) }).toEqual({ name, code: 1, codes: ["fidelity_interview_incomplete"] })
36
+ }
37
+ for (const name of ["again.html", "fidelity-defects.json", "pairs.json", "polished.html", "polish.json", "fidelity-meaning-defects.json"]) expect({ name, exists: existsSync(join(dir, name)) }).toEqual({ name, exists: false })
38
+ })
39
+
40
+ test("#given derived numbers none #when a derived or a converted placeholder is filled #then derived_not_allowed, and allowed renders both", () => {
41
+ // given
42
+ const { dir, s, mm } = fidelitySession()
43
+ const expr = nodeJson(["fact", "derive", "--op", "expr", "F1 * 2", "--unit", "m", "--rationale", "two spans", "--label", "two_spans", "--now", NOW, "--json", ...s])
44
+ const twice = expr.json.data.row.fact_id
45
+ setField(dir, "derived numbers", "none")
46
+ // when
47
+ const derived = fillTemplate(dir, `<p>Two spans are {{${twice}:two_spans}} [S4].</p>`)
48
+ const converted = fillTemplate(dir, `<p>The span is {{${mm}:span_mm}} [S4].</p>`)
49
+ setField(dir, "derived numbers", "allowed")
50
+ const allowed = fillTemplate(dir, `<p>Two spans are {{${twice}:two_spans}} [S4]. The span is {{${mm}:span_mm}} [S4].</p>`)
51
+ // then
52
+ expect(expr.code).toBe(0)
53
+ expect([derived.code, codesOf(derived.json)]).toEqual([1, ["derived_not_allowed"]])
54
+ expect([converted.code, codesOf(converted.json)]).toEqual([1, ["derived_not_allowed"]])
55
+ expect(allowed.code).toBe(0)
56
+ expect(readFileSync(join(dir, "t.html"), "utf8")).toContain("320,000 mm")
57
+ })
58
+
59
+ test("#given source floor primary only #when rows from secondary, unknown, and primary sources are filled #then only the primary row renders", () => {
60
+ // given
61
+ const { dir } = fidelitySession()
62
+ const secondary = textSource(dir, "S7", "secondary")
63
+ const unknown = textSource(dir, "S8")
64
+ const primary = textSource(dir, "S6", "primary")
65
+ setField(dir, "source floor", "primary only")
66
+ // when
67
+ const fills = [secondary, unknown, primary].map(({ row }) => fillTemplate(dir, `<p>The span is {{${row.fact_id}:${row.label}}} [S4].</p>`))
68
+ // then
69
+ expect([secondary.snap.json, unknown.snap.json, primary.snap.json].map((json) => (json as unknown as { data: { provenance: string } }).data.provenance)).toEqual(["secondary", "unknown", "primary"])
70
+ expect(fills.map((f) => [f.code, codesOf(f.json)])).toEqual([
71
+ [1, ["source_outside_floor"]],
72
+ [1, ["source_outside_floor"]],
73
+ [0, []],
74
+ ])
75
+ })
76
+
77
+ test("#given a row registered while source floor is pending #when the floor locks to pointed only S4, then standard #then fill refuses, then renders, and outside_floor caches each result", () => {
78
+ // given
79
+ const { dir } = fidelitySession()
80
+ setField(dir, "source floor", "pending", "pending")
81
+ const { snap, row } = textSource(dir, "S9")
82
+ const body = `<p>The span is {{${row.fact_id}:${row.label}}} [S9].</p>`
83
+ // when
84
+ setField(dir, "source floor", "pointed only: S4")
85
+ const refused = fillTemplate(dir, body)
86
+ const cachedRefused = ledgerRow(dir, row.fact_id).outside_floor
87
+ setField(dir, "source floor", "standard")
88
+ const rendered = fillTemplate(dir, body)
89
+ // then
90
+ expect(snap.code).toBe(0)
91
+ expect(row.outside_floor).toBe(false)
92
+ expect([refused.code, codesOf(refused.json)]).toEqual([1, ["source_outside_floor"]])
93
+ expect(cachedRefused).toBe(true)
94
+ expect(rendered.code).toBe(0)
95
+ expect(ledgerRow(dir, row.fact_id).outside_floor).toBe(false)
96
+ })
97
+
98
+ test("#given a markdown translation comment after a quote #when languages is translation beside, then quotes original #then fact pairs emits a translation pair only for the first", () => {
99
+ // given
100
+ const { dir, s } = fidelitySession()
101
+ const md = ["# T", "", "## Findings", "", "The operator wrote {{Q1:completion}} <!-- translates: Q1 --> completion comes in 2027 at the earliest [S4].", ""].join("\n")
102
+ writeFileSync(join(dir, "t.src.md"), md)
103
+ const kinds = () => {
104
+ const filled = nodeJson(["fact", "fill", join(dir, "t.src.md"), "--format", "md", "--out", join(dir, "t.md"), ...s])
105
+ const pairs = nodeJson(["fact", "pairs", join(dir, "t.md"), "--out", join(dir, "pairs.json"), ...s])
106
+ return { fill: filled.code, pairs: pairs.code, kinds: JSON.parse(readFileSync(join(dir, "pairs.json"), "utf8")).pairs.map((p: Pair) => p.kind) }
107
+ }
108
+ // when
109
+ const beside = kinds()
110
+ setField(dir, "languages", "report en; sources en; quotes original")
111
+ const original = kinds()
112
+ // then
113
+ expect(beside).toEqual({ fill: 0, pairs: 0, kinds: ["quote", "translation"] })
114
+ expect(original).toEqual({ fill: 0, pairs: 0, kinds: ["quote"] })
115
+ })
116
+
117
+ test("#given a sentence that failed twice #when filled with --replace-failed #then block-quote replaces it and fallback omit removes it", () => {
118
+ // given
119
+ const { dir } = fidelitySession()
120
+ const state = { schemaVersion: 1, failures: { "findings#F1": 2 }, replaced: [] }
121
+ const body = "<p>The span length is {{F1:span_len}} [S4]. The operator wrote {{Q1:completion}} [S4].</p>"
122
+ // when
123
+ writeFileSync(join(dir, "fidelity-state.json"), JSON.stringify(state))
124
+ const quoted = fillTemplate(dir, body, ["--replace-failed"])
125
+ const quotedHtml = readFileSync(join(dir, "t.html"), "utf8")
126
+ setField(dir, "fallback", "omit")
127
+ writeFileSync(join(dir, "fidelity-state.json"), JSON.stringify(state))
128
+ const omitted = fillTemplate(dir, body, ["--replace-failed"])
129
+ const omittedHtml = readFileSync(join(dir, "t.html"), "utf8")
130
+ // then
131
+ expect(quoted.code).toBe(0)
132
+ expect(quotedHtml).toContain("<blockquote")
133
+ expect(omitted.code).toBe(0)
134
+ expect(omittedHtml).not.toContain("<blockquote")
135
+ expect(omittedHtml).not.toContain("The span length is")
136
+ expect(omittedHtml).toContain("The operator wrote")
137
+ })
138
+
139
+ test("#given --calibration #when meaning-check flags a pair #then the calibration line goes to that path, not the session default", () => {
140
+ const { dir, s } = pairedSession()
141
+ const drift = { pair_id: "P2", verdict: "drift", drift_kind: "hedge_dropped", fragment: "no earlier than 2027", source_fragment: "we estimate" }
142
+ const log = join(dir, "custom-calibration.jsonl")
143
+ const checked = nodeJson(["fact", "meaning-check", "--pairs", join(dir, "pairs.json"), "--verdicts", verdicts(dir, "cheap.json", "cheap", [drift, { pair_id: "P1", verdict: "ok" }]), "--calibration", log, ...s])
144
+ const rows = readFileSync(log, "utf8").trim().split("\n").map((line) => JSON.parse(line)).filter((row) => row.header !== true && row.run !== true)
145
+ expect(checked.code).toBe(0)
146
+ expect(rows).toHaveLength(1)
147
+ expect(existsSync(join(dir, "fidelity-calibration.jsonl"))).toBe(false)
148
+ })
149
+ })
150
+
151
+ describe("fidelity brief values, sourceless rows, and the brief binding under node", () => {
152
+ test("#given derived numbers or fallback off its table #when fact fill runs #then a usage error names the field and value and nothing is written", () => {
153
+ // given
154
+ const { dir, s } = fidelitySession()
155
+ const twice = nodeJson(["fact", "derive", "--op", "expr", "F1 * 2", "--unit", "m", "--rationale", "two spans", "--label", "two_spans", "--now", NOW, "--json", ...s]).json.data.row.fact_id
156
+ // when
157
+ setField(dir, "derived numbers", "nope")
158
+ const derived = fillTemplate(dir, `<p>Two spans are {{${twice}:two_spans}} [S4].</p>`)
159
+ setField(dir, "derived numbers", "allowed")
160
+ setField(dir, "fallback", "drop")
161
+ const fallback = fillTemplate(dir, "<p>The span length is {{F1:span_len}} [S4].</p>")
162
+ // then
163
+ expect({ code: derived.code, named: derived.stderr.includes('derived numbers "nope"') }).toEqual({ code: 2, named: true })
164
+ expect({ code: fallback.code, named: fallback.stderr.includes('fallback "drop"') }).toEqual({ code: 2, named: true })
165
+ expect(existsSync(join(dir, "t.html"))).toBe(false)
166
+ })
167
+
168
+ test("#given an assumed row #when filled under primary only, then standard #then the sourceless row is source_outside_floor, then renders", () => {
169
+ // given
170
+ const { dir, s } = fidelitySession()
171
+ const assumed = nodeJson(["fact", "add", "--assumed", "12", "--unit", "%", "--rationale", "planning share chosen by the requester", "--label", "share_assumed", "--json", ...s]).json.data.row.fact_id
172
+ const body = `<p>The planning share is {{${assumed}:share_assumed}}.</p>`
173
+ // when
174
+ setField(dir, "source floor", "primary only")
175
+ const refused = fillTemplate(dir, body)
176
+ setField(dir, "source floor", "standard")
177
+ const rendered = fillTemplate(dir, body)
178
+ // then
179
+ expect([refused.code, codesOf(refused.json)]).toEqual([1, ["source_outside_floor"]])
180
+ expect(JSON.stringify(refused.json)).toContain("no source")
181
+ expect(rendered.code).toBe(0)
182
+ })
183
+
184
+ test("#given a derived row whose operand rests on a secondary source #when filled under primary only #then source_outside_floor names that source", () => {
185
+ // given
186
+ const { dir, s } = fidelitySession()
187
+ const { row } = textSource(dir, "S7", "secondary")
188
+ const twice = nodeJson(["fact", "derive", "--op", "expr", `${row.fact_id} * 2`, "--unit", "m", "--rationale", "two spans", "--label", "two_spans", "--now", NOW, "--json", ...s]).json.data.row.fact_id
189
+ setField(dir, "source floor", "primary only")
190
+ // when
191
+ const refused = fillTemplate(dir, `<p>Two spans are {{${twice}:two_spans}} [S7].</p>`)
192
+ // then
193
+ expect([refused.code, codesOf(refused.json)]).toEqual([1, ["source_outside_floor"]])
194
+ expect(JSON.stringify(refused.json)).toContain("rests on S7")
195
+ })
196
+
197
+ test("#given an edition filled under standard from a secondary source #when the brief tightens to primary only #then fact verify refuses with and without its fill map", () => {
198
+ // given
199
+ const { dir, s } = fidelitySession()
200
+ const { row } = textSource(dir, "S7", "secondary")
201
+ const src = readFileSync(join(dir, "report.src.html"), "utf8")
202
+ .replace("<h2>How", `<p>A review gives the span as {{${row.fact_id}:${row.label}}} [S7].</p>\n<h2>How`)
203
+ .replace("</ol>", '<li id="s7">[S7] Bridge review, retrieved 2026-10-01.</li></ol>')
204
+ writeFileSync(join(dir, "report.src.html"), src)
205
+ const filled = nodeJson(["fact", "fill", join(dir, "report.src.html"), "--out", join(dir, "report.html"), ...s])
206
+ const map = join(dir, "report.html.fill-map.json")
207
+ const before = verify(dir, "report.html")
208
+ // when
209
+ setField(dir, "source floor", "primary only")
210
+ const bound = verify(dir, "report.html")
211
+ const record = JSON.parse(readFileSync(join(dir, "fidelity-defects.json"), "utf8"))
212
+ const kept = readFileSync(map, "utf8")
213
+ rmSync(map)
214
+ const unbound = verify(dir, "report.html")
215
+ setField(dir, "source floor", "standard")
216
+ const { brief_sha256: _dropped, ...legacy } = JSON.parse(kept)
217
+ writeFileSync(map, JSON.stringify(legacy))
218
+ const unstamped = verify(dir, "report.html")
219
+ // then
220
+ expect([filled.code, before.code, codesOf(before.json)]).toEqual([0, 0, []])
221
+ expect(typeof JSON.parse(kept).brief_sha256).toBe("string")
222
+ expect(bound.code).toBe(1)
223
+ expect(codesOf(bound.json)).toContain("brief_changed")
224
+ expect(codesOf(bound.json)).toContain("source_outside_floor")
225
+ expect(record.status).toBe("fail")
226
+ expect(unbound.code).toBe(1)
227
+ expect(codesOf(unbound.json)).toContain("source_outside_floor")
228
+ expect(codesOf(unbound.json)).toContain("brief_changed")
229
+ expect([unstamped.code, codesOf(unstamped.json)]).toEqual([1, ["brief_changed"]])
230
+ })
231
+ })
@@ -133,7 +133,7 @@ export async function runOutcome(argv) {
133
133
  switch (sub) {
134
134
  case "init": {
135
135
  const promised = args.required("promised").split(",").map((s) => s.trim()).filter(Boolean)
136
- const manifest = outcome.initManifest({ sessionDir: sessionDirFrom(args.flags), promised, lane: args.flags.lane ?? null, now: nowFrom(args.flags) })
136
+ const manifest = outcome.initManifest({ sessionDir: sessionDirFrom(args.flags), promised, lane: args.flags.lane ?? null, now: nowFrom(args.flags), startedAt: args.flags["started-at"] })
137
137
  outcome.writeManifest(file, manifest)
138
138
  return { json: { command: "outcome init", path: file, deliverables: manifest.deliverables }, exitCode: 0 }
139
139
  }
@@ -28,6 +28,8 @@ export const COMMANDS = Object.freeze([
28
28
  "fact verify",
29
29
  "fact derive",
30
30
  "source snapshot",
31
+ "source refresh",
32
+ "source probe-conversion",
31
33
  "claims index",
32
34
  ])
33
35
 
@@ -53,7 +55,11 @@ export async function run(argv) {
53
55
  return (await import("./source-commands.mjs")).runClaims(rest)
54
56
  case "--help":
55
57
  case "help":
56
- if (rest.includes("--json")) return { json: { commands: COMMANDS }, exitCode: 0 }
58
+ if (rest.includes("--json")) {
59
+ const { SNAPSHOT_USAGE } = await import("./source-commands.mjs")
60
+ const { REFRESH_USAGE } = await import("./source-refresh.mjs")
61
+ return { json: { commands: COMMANDS, usage: { "source snapshot": SNAPSHOT_USAGE, "source refresh": REFRESH_USAGE } }, exitCode: 0 }
62
+ }
57
63
  return { text: `report-tools <command>\n${COMMANDS.map((name) => ` ${name}`).join("\n")}`, exitCode: 0 }
58
64
  default:
59
65
  throw new CliError(`usage: report-tools <${COMMANDS.join(" | ")}> (run --help)`)