lazycodex-ai 5.1.48 → 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 (437) hide show
  1. package/dist/cli/index.js +1194 -752
  2. package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
  3. package/dist/cli/service-auth/commands.d.ts +2 -4
  4. package/dist/cli/service-auth/index.d.ts +1 -1
  5. package/dist/cli/service-auth/keystore.d.ts +26 -2
  6. package/dist/cli/service-auth/protocol.d.ts +7 -1
  7. package/dist/cli/service-auth/session.d.ts +6 -0
  8. package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
  9. package/dist/cli-node/index.js +1194 -752
  10. package/package.json +3 -1
  11. package/packages/lsp-core/package.json +45 -0
  12. package/packages/lsp-core/src/index.ts +30 -0
  13. package/packages/lsp-core/src/lsp/bun-command-output.ts +82 -0
  14. package/packages/lsp-core/src/lsp/bun-project-checks.test.ts +170 -0
  15. package/packages/lsp-core/src/lsp/bun-project-checks.ts +223 -0
  16. package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
  17. package/packages/lsp-core/src/lsp/cleanup-errors.ts +14 -0
  18. package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +52 -0
  19. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +471 -0
  20. package/packages/lsp-core/src/lsp/client-diagnostics-pull-timeout.test.ts +64 -0
  21. package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
  22. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +213 -0
  23. package/packages/lsp-core/src/lsp/client-wrapper.ts +290 -0
  24. package/packages/lsp-core/src/lsp/client.ts +398 -0
  25. package/packages/lsp-core/src/lsp/config-loader.ts +254 -0
  26. package/packages/lsp-core/src/lsp/connection.ts +95 -0
  27. package/packages/lsp-core/src/lsp/constants.ts +17 -0
  28. package/packages/lsp-core/src/lsp/controlled-clock-test-support.ts +90 -0
  29. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +221 -0
  30. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +187 -0
  31. package/packages/lsp-core/src/lsp/effective-extension.ts +10 -0
  32. package/packages/lsp-core/src/lsp/errors.ts +89 -0
  33. package/packages/lsp-core/src/lsp/fake-bun-test-support.ts +102 -0
  34. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
  35. package/packages/lsp-core/src/lsp/fixtures/disposed-stdin-epipe-probe.ts +28 -0
  36. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
  37. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +234 -0
  38. package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
  39. package/packages/lsp-core/src/lsp/format-document.ts +90 -0
  40. package/packages/lsp-core/src/lsp/formatters.ts +144 -0
  41. package/packages/lsp-core/src/lsp/infer-extension.ts +66 -0
  42. package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
  43. package/packages/lsp-core/src/lsp/json-rpc-connection.ts +369 -0
  44. package/packages/lsp-core/src/lsp/language-mappings.ts +173 -0
  45. package/packages/lsp-core/src/lsp/manager-lifecycle.test.ts +262 -0
  46. package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
  47. package/packages/lsp-core/src/lsp/manager.ts +495 -0
  48. package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
  49. package/packages/lsp-core/src/lsp/process-pipe-errors.test.ts +21 -0
  50. package/packages/lsp-core/src/lsp/process-signal-cleanup.ts +21 -0
  51. package/packages/lsp-core/src/lsp/process.ts +221 -0
  52. package/packages/lsp-core/src/lsp/server-definitions.ts +205 -0
  53. package/packages/lsp-core/src/lsp/server-install-state.ts +67 -0
  54. package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
  55. package/packages/lsp-core/src/lsp/server-installation.ts +218 -0
  56. package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
  57. package/packages/lsp-core/src/lsp/server-resolution.ts +117 -0
  58. package/packages/lsp-core/src/lsp/startup-failure.ts +1 -0
  59. package/packages/lsp-core/src/lsp/timer-provider.ts +13 -0
  60. package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
  61. package/packages/lsp-core/src/lsp/transport-request-timeout.test.ts +73 -0
  62. package/packages/lsp-core/src/lsp/transport.ts +339 -0
  63. package/packages/lsp-core/src/lsp/types.ts +134 -0
  64. package/packages/lsp-core/src/lsp/utils.test.ts +72 -0
  65. package/packages/lsp-core/src/lsp/utils.ts +40 -0
  66. package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
  67. package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +218 -0
  68. package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
  69. package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +194 -0
  70. package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
  71. package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +150 -0
  72. package/packages/lsp-core/src/lsp/workspace-document-state.ts +392 -0
  73. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +132 -0
  74. package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
  75. package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
  76. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
  77. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
  78. package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
  79. package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
  80. package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
  81. package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
  82. package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
  83. package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
  84. package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
  85. package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
  86. package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
  87. package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
  88. package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
  89. package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
  90. package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
  91. package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
  92. package/packages/lsp-core/src/lsp/workspace-edit.ts +55 -0
  93. package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
  94. package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
  95. package/packages/lsp-core/src/mcp-protocol-pin.test.ts +97 -0
  96. package/packages/lsp-core/src/mcp.ts +122 -0
  97. package/packages/lsp-core/src/missing-dependency-result.test.ts +135 -0
  98. package/packages/lsp-core/src/missing-dependency-result.ts +79 -0
  99. package/packages/lsp-core/src/post-edit/file-location.ts +55 -0
  100. package/packages/lsp-core/src/post-edit/index.ts +3 -0
  101. package/packages/lsp-core/src/post-edit/not-installed-guidance.ts +36 -0
  102. package/packages/lsp-core/src/post-edit/not-installed.test.ts +224 -0
  103. package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
  104. package/packages/lsp-core/src/post-edit/orchestration.ts +205 -0
  105. package/packages/lsp-core/src/request-context.test.ts +200 -0
  106. package/packages/lsp-core/src/request-context.ts +235 -0
  107. package/packages/lsp-core/src/tool-surface.test.ts +173 -0
  108. package/packages/lsp-core/src/tools/bun-directory-diagnostics.test.ts +113 -0
  109. package/packages/lsp-core/src/tools/bun-directory-diagnostics.ts +75 -0
  110. package/packages/lsp-core/src/tools/definitions.ts +156 -0
  111. package/packages/lsp-core/src/tools/diagnostics.ts +133 -0
  112. package/packages/lsp-core/src/tools/format.test.ts +56 -0
  113. package/packages/lsp-core/src/tools/format.ts +56 -0
  114. package/packages/lsp-core/src/tools/index.ts +11 -0
  115. package/packages/lsp-core/src/tools/install-decision.ts +39 -0
  116. package/packages/lsp-core/src/tools/navigation.ts +88 -0
  117. package/packages/lsp-core/src/tools/parameters.test.ts +51 -0
  118. package/packages/lsp-core/src/tools/parameters.ts +49 -0
  119. package/packages/lsp-core/src/tools/rename.ts +69 -0
  120. package/packages/lsp-core/src/tools/result.ts +5 -0
  121. package/packages/lsp-core/src/tools/runtime.ts +21 -0
  122. package/packages/lsp-core/src/tools/schema.ts +9 -0
  123. package/packages/lsp-core/src/tools/status.ts +28 -0
  124. package/packages/lsp-core/src/tools/symbols.ts +99 -0
  125. package/packages/lsp-core/src/tools/types.ts +116 -0
  126. package/packages/lsp-core/src/tools.ts +1 -0
  127. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  128. package/packages/omo-codex/plugin/README.md +1 -1
  129. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  130. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  131. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  132. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  133. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  134. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  135. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  136. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  137. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  138. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  139. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
  140. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
  141. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  142. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  143. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  145. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  146. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  147. package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
  148. package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
  149. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
  150. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
  151. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  152. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  153. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
  154. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
  155. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
  156. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
  157. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
  158. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
  159. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  160. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  161. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  162. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  163. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  164. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
  165. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  166. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  184. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  185. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  186. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  187. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  188. package/packages/omo-codex/plugin/package-lock.json +16 -16
  189. package/packages/omo-codex/plugin/package.json +1 -1
  190. package/packages/omo-codex/plugin/shared/package.json +1 -1
  191. package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
  192. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
  193. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
  194. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  195. package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  196. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  197. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
  198. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
  199. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  200. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
  201. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  202. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  203. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
  204. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
  205. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  206. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
  207. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
  208. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
  209. package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
  210. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  211. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  212. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  213. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  214. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
  215. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  216. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
  217. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  218. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
  219. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
  220. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  221. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  222. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
  223. package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
  224. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
  225. package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
  226. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  227. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
  228. package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  229. package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
  230. package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
  231. package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
  232. package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
  233. package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  234. package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
  235. package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  236. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  237. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
  238. package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
  239. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  240. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  241. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  242. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  243. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  244. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  245. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  246. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  247. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  248. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  249. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  250. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  251. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  252. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  253. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  254. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  255. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  256. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  257. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  258. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  259. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  260. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
  261. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
  262. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
  263. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  264. package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  265. package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
  266. package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  267. package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
  268. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  269. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
  270. package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
  271. package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  272. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  273. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  274. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  275. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
  276. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
  277. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  278. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  279. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
  280. package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  281. package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
  282. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
  283. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
  284. package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
  285. package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
  286. package/packages/shared-skills/skill-source-filter.mjs +6 -2
  287. package/packages/shared-skills/skills/ast-grep/README.md +1 -1
  288. package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
  289. package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
  290. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  291. package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  292. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  293. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
  294. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
  295. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  296. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
  297. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  298. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  299. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
  300. package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
  301. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  302. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
  303. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
  304. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
  305. package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
  306. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  307. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  308. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
  309. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  310. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
  311. package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
  312. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  313. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  314. package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
  315. package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
  316. package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
  317. package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  318. package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
  319. package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  320. package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
  321. package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
  322. package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
  323. package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
  324. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  325. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  326. package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  327. package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  328. package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
  329. package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
  330. package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  331. package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  332. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  333. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  334. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  335. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
  336. package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  337. package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
  338. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  339. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  340. package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
  341. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  342. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  343. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  344. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  345. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  346. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  347. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  348. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  349. package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  350. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  351. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  352. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  353. package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  354. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  355. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  356. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  357. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  358. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  359. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  360. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  361. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  362. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  363. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  364. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  365. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  366. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  367. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  368. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  369. package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  370. package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  371. package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
  372. package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
  373. package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
  374. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  375. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  376. package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  377. package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  378. package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
  379. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  380. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  381. package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
  382. package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
  383. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  384. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  385. package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
  386. package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  387. package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
  388. package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  389. package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  390. package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  391. package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  392. package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  393. package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  394. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  395. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  396. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  397. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  398. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  399. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
  400. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
  401. package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  402. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
  403. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  404. package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  405. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  406. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  407. package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
  408. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  409. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  410. package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  411. package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  412. package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  413. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  414. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  415. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  416. package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  417. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  418. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  419. package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  420. package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  421. package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  422. package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
  423. package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
  424. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  425. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  426. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  427. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  428. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  429. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
  430. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
  431. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
  432. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
  433. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
  434. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
  435. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
  436. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
  437. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
@@ -0,0 +1,236 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { readFileSync } from "node:fs"
3
+ import { join } from "node:path"
4
+
5
+ import { valueChecks } from "./fidelity-values.mjs"
6
+ import { buildContext, checkStatic } from "./gates-static.mjs"
7
+ import { parseHtml } from "./html-lite.mjs"
8
+ import { isClaimSegment, numeralKinds, sourcesClaims } from "./sources-citation.mjs"
9
+ import { type ClassRow, GLUED_LETTER_ROWS, SHAPE_ROWS } from "./tests/numeral-classes"
10
+
11
+ const FIX = join(import.meta.dir, "tests", "fixtures")
12
+ const EMPTY = { schemaVersion: 1, rows: [], events: [] }
13
+ const GATED = new Set(["unsourced_number", "untraceable_number", "verification_claim_unmarked"])
14
+
15
+ /** The codes the static gate, the number trace, and the claim check raise over one document. */
16
+ function gated(html: string) {
17
+ const doc = parseHtml(html)
18
+ const fidelity = valueChecks(buildContext(doc, {}), EMPTY, null, null) as { code: string }[]
19
+ return [...(checkStatic(doc).defects as { code: string }[]), ...fidelity].map((d) => d.code).filter((code) => GATED.has(code))
20
+ }
21
+ const underSources = (body: string) => gated(`<h2>Official sources</h2>${body}`)
22
+
23
+ // Round-4 ruling, guard: a digit run glued to a unit, multiplier, or currency stays a numeral, in a
24
+ // reference-shaped line (EN, KO) and in a Korean sentence where a particle follows the unit.
25
+ const QUANTITIES = ["50M", "10k", "3x", "5.4T", "12%", "2.5GB", "10ms", "320m", "40percent"]
26
+ const GUARD = [
27
+ ...QUANTITIES.flatMap((q) => [
28
+ `<li>Annual filing ${q}, https://example.com/filing</li>`,
29
+ `<li>\uC5F0\uAC04 \uACF5\uC2DC ${q}, https://example.com/filing</li>`,
30
+ `<p>\uADDC\uBAA8\uB294 ${q}\uB85C \uC9D1\uACC4\uB410\uB2E4.</p>`,
31
+ ]),
32
+ "<li>Q3 revenue 12%, https://example.com/q3</li>",
33
+ "<li>Q3 \uB9E4\uCD9C 12%, https://example.com/q3</li>",
34
+ "<li>3\uBD84\uAE30 \uB9E4\uCD9C 12%, https://example.com/q3</li>",
35
+ "<li>Market data, USD5bn in 2025, https://example.com/fx</li>",
36
+ ]
37
+
38
+ // Round-4 date ruling: a month/day is a date (a citation field), a day count is not.
39
+ const DATES = [
40
+ "<li>Fed minutes 2026-09-16 (released 10/26), https://example.com/minutes</li>",
41
+ "<li>Press release, Oct 26, https://example.com/press</li>",
42
+ "<li>Press release, October 26, 2026, https://example.com/press</li>",
43
+ "<li>\uC5F0\uC900 \uC758\uC0AC\uB85D (10/26 \uACF5\uAC1C), https://example.com/minutes</li>",
44
+ "<li>\uBCF4\uB3C4\uC790\uB8CC 10\uC6D4 26\uC77C, https://example.com/press</li>",
45
+ "<li>\uBCF4\uB3C4\uC790\uB8CC 2026. 10. 26., https://example.com/press</li>",
46
+ ]
47
+ const DAY_COUNTS = [
48
+ "<li>Trial period 30 days, https://example.com/trial</li>",
49
+ "<p>The pilot ran for 30 days.</p>",
50
+ "<li>\uC2DC\uBC94 \uC6B4\uC601 30\uC77C\uAC04, https://example.com/trial</li>",
51
+ "<p>\uC2DC\uBC94 \uC6B4\uC601\uC740 30\uC77C \uB3D9\uC548 \uC9C4\uD589\uB410\uB2E4.</p>",
52
+ ]
53
+
54
+ // Round 5: a unit, multiplier, or percent on the right keeps a digit run a numeral even with letters
55
+ // glued on its left (a Korean particle after the unit allowed), a multiplier glued on the left (x3) is a
56
+ // numeral, mn / pct / yr(s) / mo are units, and a European digit grouping is a numeral (EN and KO).
57
+ const GLUED_MEASURES = [
58
+ "<p>\uB9E4\uCD9C40% \uC99D\uAC00.</p>",
59
+ "<li>\uC804\uB144\uB300\uBE4430%, https://example.com/yoy</li>",
60
+ "<p>\uC57D300\uBA85\uC774 \uCC38\uC5EC\uD588\uB2E4.</p>",
61
+ "<p>Model B is x3 faster.</p>",
62
+ "<p>\uC18D\uB3C4\uB294 x3 \uBE68\uB790\uB2E4.</p>",
63
+ "<li>Churn rate40%, https://example.com/churn</li>",
64
+ "<p>Grew 5mn users.</p>",
65
+ "<p>Up 40pct.</p>",
66
+ "<p>5yrs of data.</p>",
67
+ "<li>Retention 18mo, https://example.com/retention</li>",
68
+ "<li>\uC5F0\uAC04 \uC131\uC7A5 40pct, https://example.com/growth</li>",
69
+ "<p>1.234.567 users signed up.</p>",
70
+ "<p>\uAC00\uC785\uC790\uB294 1.234.567\uBA85\uC774\uB2E4.</p>",
71
+ "<li>Annual report (10-K), https://example.com/filing</li>",
72
+ ]
73
+
74
+ // Decision 25: under Sources a sentence is checked unless every numeral in it is a citation-field number.
75
+ // Receipt cases from review rounds 1-3, EN and KO (Korean as \u escapes).
76
+ const MUST_FLAG = [
77
+ "<p>[S4] says revenue rose 40% in 2025.</p>",
78
+ "<p>[S4] Revenue rose 40% in 2025, the highest on record.</p>",
79
+ "<li>Revenue rose 40% in 2025 according to https://example.com/report</li>",
80
+ "<p>[S4] Annual report 2024, https://example.com/report<br>The check found 42% of spans out of tolerance.</p>",
81
+ "<p>Revenue was 40% higher in 2025.</p>",
82
+ "<p>Revenue totaled 5 billion dollars in 2025.</p>",
83
+ "<p>Note: the market share is 42% as of 2025.</p>",
84
+ "<p>Exports surged 31% to 12 billion in 2025.</p>",
85
+ "<p>[S4] Revenue hit $5 billion in 2025.</p>",
86
+ "<p>[S4] The agency estimates 3.2 million users.</p>",
87
+ "<p>Revenue was 40 percent higher in 2025.</p>",
88
+ "<p>Market share is 42 percent.</p>",
89
+ "<p>Model B is 3x faster than model A.</p>",
90
+ "<p>The survey covered 1,200 firms in 2025.</p>",
91
+ "<p>The dataset includes 3412 reports.</p>",
92
+ "<p>We reviewed the filings. Market share reached 42% in 2025. Source: https://example.com/a</p>",
93
+ "<p>Note. Revenue grew 40% in 2025. Accessed 2025-10-01.</p>",
94
+ "<p>See the notes below. Unemployment was 4.1% in September. 2025.</p>",
95
+ "<li>[S5] Bloomberg (2025). Revenue grew 40% as AI demand reached record. https://example.com/bloomberg</li>",
96
+ "<p>[S19] Treasury buyback $94B 2026-10-08: https://example.com/2026/10/08/buybacks</p>",
97
+ "<li>Llama 3.1 model card, Meta, https://example.com/llama</li>",
98
+ "<li>Survey 2025, wave 2, https://example.com/survey</li>",
99
+ "<p>\uC810\uC720\uC728\uC740 42%\uC774\uB2E4.</p>",
100
+ "<p>\uB9E4\uCD9C\uC740 2025\uB144 40% \uB298\uC5B4 5\uC870\uC6D0\uC744 \uAE30\uB85D\uD588\uB2E4.</p>",
101
+ "<p>\uC9C1\uC6D0 \uC218\uB294 1,250\uBA85\uC774\uB2E4.</p>",
102
+ "<p>We ran the check and it reported 42%.</p>",
103
+ ...GUARD,
104
+ ...DAY_COUNTS,
105
+ ...GLUED_MEASURES,
106
+ ]
107
+
108
+ // Round-4 ruling, must-pass: a digit run glued to letters that are not a unit is a name (commit hashes,
109
+ // #issue numbers, identifiers, quarter and filing codes); link text is a citation field; a year range is a date.
110
+ const NAMES = [
111
+ "<li>letta-code @ a75f4d93ef / @ 701f2a53678, https://example.com/letta</li>",
112
+ "<li>\uACE0\uC815 \uCEE4\uBC0B 22c5684b983e, 424B4, https://example.com/repo</li>",
113
+ "<li>oh-my-openagent PR #6674\u2013#7906, https://example.com/prs</li>",
114
+ "<li>\uC774\uC288 #11302 \uB17C\uC758, https://example.com/issue</li>",
115
+ "<li>GPT-4 system card v2.3.1 (abc123), https://example.com/gpt</li>",
116
+ "<li>GPT-4 \uC2DC\uC2A4\uD15C \uCE74\uB4DC v2.3.1 (abc123), https://example.com/gpt</li>",
117
+ "<li>Cohort table Q3-2024, filing 2024-Q3-F1, Oracle Q1 FY27 (10-Q), S-1, https://example.com/cohort</li>",
118
+ "<li>\uCF54\uD638\uD2B8 Q3-2024 \uACF5\uC2DC 2024-Q3-F1, YC W26, H1 2026, https://example.com/cohort</li>",
119
+ "<li>FRED DGS10/DGS30, KOSPI200, Base44, CC0, 3D icons, https://example.com/data</li>",
120
+ "<li>github.com/letta-ai/letta-code @ a75f4d93ef(0.30.14); W3C PROV-DM; https://example.com/letta</li>",
121
+ "<li>\uC778\uC6A9 \uADDC\uC57D: \uACBD\uB85C:\uD589@b2105213234ab0c9762c7871611bf336dfb0eb2b (3.1.1), https://example.com/sha</li>",
122
+ "<li>\uC5F0\uC900 \uC790\uB8CC (2\uCC28 \uBCF4\uB3C4), https://example.com/fed</li>",
123
+ '<li><a href="https://example.com/hn">HN thread (90 points, 37 comments)</a></li>',
124
+ '<li><a href="https://example.com/notice">Spin-off notice (2025-12-02, \uACF5\uB3D9\uCC3D\uC5C5\uC790 20\uBA85 \uC11C\uBA85)</a></li>',
125
+ "<li>Survey archive 2019-2023, 2019~2023, 2019\u20132023, https://example.com/archive</li>",
126
+ "<li>2025\u20132026\uB144 \uADFC\uC6D4\uBB3C \uC790\uB8CC, 2019~2023\uB144, https://example.com/basis</li>",
127
+ "<p>2019\u20132023\uB144 \uD1B5\uACC4\uB97C 1\uCC28 \uC790\uB8CC\uB85C \uD655\uBCF4\uD558\uC9C0 \uBABB\uD588\uB2E4.</p>",
128
+ "<li>Build abc123, GPT-4, v2.3.1, #1234, Q3-2024 cohort, 0.30.14, https://example.com/build</li>",
129
+ "<li>\uBE4C\uB4DC abc123, GPT-4, v2.3.1, #1234, Q3-2024 \uCF54\uD638\uD2B8, 0.30.14, https://example.com/build</li>",
130
+ "<li>\uC81C3\uC790 \uC81C\uACF5 \uC790\uB8CC, https://example.com/third</li>",
131
+ "<li>Survey notes [w1:x02], https://example.com/survey</li>",
132
+ ]
133
+
134
+ const MUST_PASS = [
135
+ '<li>[S3] Reuters, "China\'s exports rose 7% in September", 2025-10-13, https://example.com/reuters</li>',
136
+ '<li>[S6] \uC5F0\uD569\uB274\uC2A4, "\uC218\uCD9C 12% \uC99D\uAC00\uD588\uB2E4", 2025-10-01, https://example.com/yna</li>',
137
+ "<li>[S7] Nikkei, \u201CSales fell 3.5% in Q2\u201D, https://example.com/nikkei</li>",
138
+ "<li>[S9] \uC5F0\uD569\uB274\uC2A4, \u300C\uC218\uCD9C 12% \uC99D\uAC00\u300D, 2025\uB144 10\uC6D4 1\uC77C</li>",
139
+ "<li>[S8] LoCoMo arXiv 2402.17753; DOI 10.1145/1571941.1572114</li>",
140
+ "<li>Field guide, ISBN 978-0-306-40615-7, 3rd edition, pp. 12-15.</li>",
141
+ "<li><cite>Llama 3.1 model card</cite>, Meta, https://example.com/llama</li>",
142
+ '<li>"Python 3.12 release notes", 2024-10-07, https://example.com/python</li>',
143
+ "<li><em>WCAG 2.2</em>, 2023-10-05, https://example.com/wcag</li>",
144
+ "<li>Smith, J. (2024a). Annual report. https://example.com/annual-2024</li>",
145
+ "<li>Bridge Review, Vol. 2024/1, No. 3, https://example.com/review. Accessed 25 October 2026.</li>",
146
+ "<li>\uAD50\uB7C9 \uC5F0\uAC10 3\uAD8C 2\uD638, 45-52\uCABD, 2024\uB144</li>",
147
+ "<p>[S4] Annual report, 2024. https://example.com/report</p>",
148
+ '<p><a href="https://example.com/2024">Annual report 2024</a></p>',
149
+ "<li>Annual report 2024, https://example.com/report</li>",
150
+ '<li>Annual report 2024, <a href="https://example.com/report">source</a></li>',
151
+ "<h3>2024</h3>",
152
+ "<p>Publication cutoff and access date: October 25, 2026. Every linked source was read directly.</p>",
153
+ ...NAMES,
154
+ ...DATES,
155
+ ]
156
+
157
+ describe("under Sources, a sentence with a numeral that is not a citation field is checked", () => {
158
+ for (const body of MUST_FLAG) test(`#given ${JSON.stringify(body)} #when checked #then untraceable_number`, () => expect(underSources(body)).toContain("untraceable_number"))
159
+
160
+ test("#given a citation, then a claim after <br> #when traced #then only the claim sentence's numbers are flagged", () => {
161
+ expect(underSources("<p>[S4] Annual report 2024, https://example.com/report<br>Revenue rose 42% in 2025.</p>").filter((code) => code === "untraceable_number")).toHaveLength(2)
162
+ })
163
+
164
+ test("#given a first-person cue with a claim number under Sources #when checked #then the claim check warns too", () => {
165
+ expect(underSources("<p>We confirmed that the rate is 42%.</p>")).toEqual(expect.arrayContaining(["unsourced_number", "untraceable_number", "verification_claim_unmarked"]))
166
+ })
167
+ })
168
+
169
+ describe("an element whose every numeral is a citation field is exempt", () => {
170
+ for (const body of MUST_PASS) test(`#given ${JSON.stringify(body)} #when checked #then nothing`, () => expect(underSources(body)).toEqual([]))
171
+
172
+ test("#given a report with every reference shape (APA, pages, volume, access dates, year subheading, dl, Sources table) #when checked #then no gated code", () => {
173
+ expect(gated(readFileSync(join(FIX, "sources-shapes.html"), "utf8"))).toEqual([])
174
+ })
175
+ })
176
+
177
+ // Mutation test: each heuristic the literal rule replaced, re-introduced as a gate on the predicate,
178
+ // must miss at least one must-flag case, so restoring any of them in sources-citation.mjs fails above.
179
+ const OLD_MEASURE = [/\d\s?(?:%|\u2030|\uD37C\uC13C\uD2B8)/, /[$\u20AC\u00A3\u00A5\u20A9]\s?\d/, /\d\s?(?:thousand|million|billion|trillion|bn)\b|\d(?:k|K|M|B)\b/, /\d\s?(?:\uC6D0|\uB2EC\uB7EC|\uBA85|\uAC74|\uAC1C|\uBC30|[\uCC9C\uB9CC\uC5B5\uC870])/, /\d\s?(?:km|kg|mm|ms|hours?|days?|users?|people|employees|customers?)\b/, /(?<![\d.,])(?!(?:19|20)\d{2}\.)\d+\.\d+(?![\d.])/]
180
+ const OLD_VERBS = /\b(?:rose|rises|grew|increased|decreased|declined|dropped|reached|says|said|stated|reported|showed|found|estimated|according\s+to)\b|\uC99D\uAC00\uD588|\uAC10\uC18C\uD588|\uB298\uC5C8|\uC904\uC5C8|\uAE30\uB85D\uD588/
181
+ const citationOnly = (text: string) => /https?:\/\/|\b(?:accessed|retrieved)\b/i.test(text)
182
+ const root = (body: string) => parseHtml(`<div>${body}</div>`)
183
+ /** The mutants' own sentence split of a case (line breaks, then sentence ends); the real predicate decides each piece. */
184
+ const pieces = (body: string) =>
185
+ body
186
+ .replace(/<br>/g, "\n")
187
+ .replace(/<[^>]+>/g, " ")
188
+ .split("\n")
189
+ .flatMap((line) => line.split(/(?<=[.!?])\s+(?=[A-Z\uAC00-\uD7A3])/))
190
+ .map((piece) => piece.trim())
191
+ .filter(Boolean)
192
+ const MUTANTS: Record<string, (body: string) => boolean> = {
193
+ "a measure-word allow-list": (body) => pieces(body).some((s) => isClaimSegment(s) && OLD_MEASURE.some((re) => re.test(s))),
194
+ "a claim-verb trigger": (body) => pieces(body).some((s) => isClaimSegment(s) && OLD_VERBS.test(s)),
195
+ "a name rule that ignores units": (body) => pieces(body).some((s) => isClaimSegment(s.replace(/\p{L}+\d[\d.,]*|\d[\d.,]*\p{L}+/gu, " "))),
196
+ "the middle-segment title heuristic": (body) => {
197
+ const all = pieces(body)
198
+ return all.some((s, at) => !(at > 0 && at + 1 < all.length && citationOnly(all[at + 1])) && isClaimSegment(s))
199
+ },
200
+ }
201
+
202
+ describe("mutation: no word list, verb list, or title heuristic decides a Sources sentence", () => {
203
+ test("#given the literal rule #when every must-flag case is read #then each yields a checked sentence and no must-pass case does", () => {
204
+ expect(MUST_FLAG.filter((body) => sourcesClaims(root(body)).length === 0)).toEqual([])
205
+ expect(MUST_PASS.filter((body) => sourcesClaims(root(body)).length > 0)).toEqual([])
206
+ })
207
+
208
+ for (const [name, mutant] of Object.entries(MUTANTS)) {
209
+ test(`#given ${name} re-introduced #when the must-flag cases run #then at least one is missed`, () => {
210
+ expect(MUST_FLAG.filter((body) => !mutant(body)).length).toBeGreaterThan(0)
211
+ })
212
+ }
213
+ })
214
+
215
+ // Lead order (round 5): one table-driven test per class. Each row names the class of every digit run,
216
+ // and the gates must agree at the real boundary: an element under Sources is checked exactly when a
217
+ // run is a numeral.
218
+ function misread(rows: ClassRow[]) {
219
+ return rows.flatMap(({ input, expected }) => {
220
+ const kinds = numeralKinds(input).map(({ kind }: { kind: string }) => kind)
221
+ const want = Array.isArray(expected) ? expected : kinds.map(() => expected)
222
+ const flagged = underSources(`<p>${input}</p>`).includes("untraceable_number")
223
+ const ok = kinds.length === want.length && kinds.every((kind: string, at: number) => kind === want[at]) && flagged === want.includes("numeral")
224
+ return ok ? [] : [{ input, expected, kinds, flagged }]
225
+ })
226
+ }
227
+
228
+ describe("numeral classes under Sources, one row per form (EN + KO)", () => {
229
+ test(`#given ${GLUED_LETTER_ROWS.length} glued-letter forms (every unit, multiplier, percent, and currency token on the right and left, Hangul and Latin words, Korean particles) #when classified #then each reads as its row says`, () => {
230
+ expect(misread(GLUED_LETTER_ROWS)).toEqual([])
231
+ })
232
+
233
+ test(`#given ${SHAPE_ROWS.length} date, version, and code shapes (slashed, dotted, dashed, ranges, groupings, filing codes, citation markers) #when classified #then each reads as its row says`, () => {
234
+ expect(misread(SHAPE_ROWS)).toEqual([])
235
+ })
236
+ })
@@ -0,0 +1,147 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import {
3
+ ANSWERED_BY,
4
+ DEFECT_CODES,
5
+ DELIVERABLE_FORMATS,
6
+ DELIVERABLE_STATUSES,
7
+ DESIGN_SPEC_SECTIONS,
8
+ FIDELITY_CODES,
9
+ GATE_NAMES,
10
+ GATE_STATUSES,
11
+ INTEGRITY_CODES,
12
+ LANES,
13
+ LAYOUT_CODES,
14
+ LINEAGE_MODES,
15
+ MANIFEST_CODES,
16
+ REPAIR_DEFAULTS,
17
+ SCHEMA_VERSION,
18
+ STATES,
19
+ STATIC_CODES,
20
+ normalizeManifest,
21
+ validateOutcomeManifest,
22
+ validateRepairState,
23
+ } from "../contracts.mjs"
24
+
25
+
26
+ const SEVERITIES = new Set(["blocker", "major", "minor"])
27
+
28
+ const STATIC_CODES_EXPECTED = [
29
+ "korean_no_keep_all",
30
+ "palette_off_token",
31
+ "emoji_in_prose",
32
+ "em_dash_in_prose",
33
+ "en_dash_in_prose",
34
+ "heading_too_long",
35
+ "heading_generic",
36
+ "unsourced_number",
37
+ "chart_without_figure",
38
+ "chart_svg_no_text",
39
+ "chart_svg_missing_labels",
40
+ "report_without_visual",
41
+ "image_missing_alt",
42
+ "korean_serif_font",
43
+ "section_without_citation",
44
+ "missing_closing_section",
45
+ "missing_citation_section",
46
+ "broken_asset_reference",
47
+ "missing_required_section",
48
+ ]
49
+
50
+ const LAYOUT_CODES_EXPECTED = [
51
+ "layout_overflow",
52
+ "layout_text_clipped",
53
+ "layout_scroll_container",
54
+ "layout_image_distorted",
55
+ "layout_sibling_overlap",
56
+ ]
57
+
58
+ // Fidelity vocabulary contract (#11009): severity and integrity per code are fixed here.
59
+ const FIDELITY_BLOCKERS = [
60
+ "unresolved_placeholder",
61
+ "value_mismatch",
62
+ "unit_mismatch",
63
+ "quote_not_verbatim",
64
+ "claim_status_invalid",
65
+ "incompatible_operands",
66
+ "pointer_label_mismatch",
67
+ "quote_anchor_unresolved",
68
+ "unit_duplicated",
69
+ "polish_diff_fail",
70
+ "fidelity_interview_incomplete",
71
+ "derived_not_allowed",
72
+ "source_outside_floor",
73
+ "brief_changed",
74
+ "snapshot_hash_mismatch",
75
+ "chart_value_untraceable",
76
+ "quote_unbound",
77
+ "edition_unverified",
78
+ "snapshot_not_raw",
79
+ ]
80
+
81
+ const FIDELITY_MAJORS = [
82
+ "untraceable_number",
83
+ "unsupported_verification",
84
+ "claim_kind_mismatch",
85
+ "conflicting_readings",
86
+ "hedge_dropped",
87
+ "direction_flipped",
88
+ "causality_added",
89
+ "qualifier_dropped",
90
+ "unbound_sentence",
91
+ "meaning_drift_confirmed",
92
+ "meaning_unverified",
93
+ "polish_edit_rejected",
94
+ "polish_hedging_decreased",
95
+ "polish_text_churn",
96
+ "snapshot_mismatch",
97
+ "join_integrity_fail",
98
+ "quote_stale_version",
99
+ "operand_timestamp_missing",
100
+ "operand_missing",
101
+ ]
102
+
103
+ const FIDELITY_MINORS = [
104
+ "quote_fuzzy_match",
105
+ "name_outside_quote",
106
+ "verification_claim_unmarked",
107
+ "scope_widened_warn",
108
+ "particle_unverified",
109
+ "fallback_without_entity",
110
+ "meaning_drift_warn",
111
+ "polish_edit_unlocated",
112
+ "polish_link_changed",
113
+ "polish_name_changed",
114
+ "relocated",
115
+ "quote_converted_only",
116
+ ]
117
+
118
+ const FIDELITY_CODES_EXPECTED = [...FIDELITY_BLOCKERS, ...FIDELITY_MAJORS, ...FIDELITY_MINORS]
119
+
120
+
121
+ function fourGateManifest() {
122
+ const manifest = sampleManifest()
123
+ const { fidelity: _dropped, ...gates } = manifest.gates
124
+ return { ...manifest, gates }
125
+ }
126
+
127
+
128
+ function sampleManifest() {
129
+ return {
130
+ schemaVersion: SCHEMA_VERSION,
131
+ sessionDir: "/tmp/session/20260101-120000",
132
+ startedAt: "2026-01-01T12:00:00.000Z",
133
+ finishedAt: null,
134
+ elapsedMinutes: null,
135
+ lane: "no-format",
136
+ interview: null,
137
+ deliverables: [
138
+ { format: "pdf", status: "pending", promised: true, updatedAt: "2026-01-01T12:00:00.000Z" },
139
+ ],
140
+ renders: [],
141
+ gates: { static: "not_run", fidelity: "not_run", layout: "not_run", visual: "not_run", proofread: "not_run" },
142
+ residualDefects: [],
143
+ repair: null,
144
+ sources: null,
145
+ }
146
+ }
147
+ export { SEVERITIES, STATIC_CODES_EXPECTED, LAYOUT_CODES_EXPECTED, FIDELITY_BLOCKERS, FIDELITY_MAJORS, FIDELITY_MINORS, FIDELITY_CODES_EXPECTED, fourGateManifest, sampleManifest }
@@ -0,0 +1,59 @@
1
+ // Shared sessions for the delivery barrier tests (../delivery-barrier.test.ts and
2
+ // ../delivery-barrier-meaning.test.ts): a delivered edition, a fully recorded session, and the refusal
3
+ // assertion both files use.
4
+ import { expect, onTestFinished } from "bun:test"
5
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
6
+ import { tmpdir } from "node:os"
7
+ import { join } from "node:path"
8
+
9
+ import { sha256Of } from "../cli-support.mjs"
10
+ import { DEFECT_CODES } from "../contracts.mjs"
11
+ import { writeFidelityRecord } from "../fidelity-records.mjs"
12
+ import { blocksDelivery } from "../gates-fidelity.mjs"
13
+ import { run } from "../report-tools.mjs"
14
+
15
+ export async function delivered(format = "html", codes: string[] | null = null) {
16
+ const root = mkdtempSync(join(tmpdir(), "delivery-barrier-"))
17
+ onTestFinished(() => rmSync(root, { recursive: true, force: true }))
18
+ const dir = join(root, "20260101-120000")
19
+ mkdirSync(dir)
20
+ const path = join(dir, `report.${format}`)
21
+ const record = join(dir, "fidelity-defects.json")
22
+ writeFileSync(path, "<p>Report</p>")
23
+ if (codes !== null) writeFidelityRecord(record, "fidelity", { artifact_sha256: sha256Of(readFileSync(path)), report: path, defects: codes.map((code) => ({ code, severity: "minor", message: code })) })
24
+ const invoke = (args: string[]) => run(["outcome", ...args, "--session-dir", dir])
25
+ await invoke(["init", "--promised", format])
26
+ expect((await invoke(["set", format, "delivered", "--path", path, ...(codes === null ? [] : ["--verified-by", record])])).exitCode).toBe(0)
27
+ return { dir, path, record, invoke }
28
+ }
29
+
30
+ export const LOCKED_BRIEF = readFileSync(join(import.meta.dir, "fixtures", "fidelity-brief-locked.md"), "utf8")
31
+ export const BLOCKER = Object.keys(DEFECT_CODES).find((code) => blocksDelivery({ code })) as string
32
+
33
+ /** The meaning record of one delivered edition, by its outcome format. */
34
+ export const meaningFile = (dir: string, format: string) => join(dir, `fidelity-meaning-defects.${format}.json`)
35
+
36
+ /**
37
+ * A delivered html edition whose locked brief requires every table record, each present, fresh for
38
+ * the delivered bytes, and clean. recordPath is where the session keeps each row's record; a table
39
+ * row with no entry here fails the coverage test, so a new row brings its own cases.
40
+ */
41
+ export async function fullyRecorded(brief = LOCKED_BRIEF) {
42
+ const session = await delivered("html", [])
43
+ writeFileSync(join(session.dir, "brief.md"), brief)
44
+ const recordPath: Record<string, string> = { fidelity: session.record, meaning: meaningFile(session.dir, "html") }
45
+ const write = (kind: string, fields: Record<string, unknown> = {}) =>
46
+ writeFidelityRecord(recordPath[kind], kind, { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects: [], ...fields })
47
+ write("meaning")
48
+ const outcomes = async () => Promise.all(["verify", "finish"].map((command) => session.invoke([command])))
49
+ return { ...session, recordPath, write, outcomes }
50
+ }
51
+
52
+ export type Recorded = Awaited<ReturnType<typeof fullyRecorded>>
53
+
54
+ export async function expectRefused(session: Recorded, problem: Record<string, unknown>) {
55
+ for (const result of await session.outcomes()) {
56
+ expect(result.exitCode).toBe(1)
57
+ expect(result.json.problems).toContainEqual(expect.objectContaining(problem))
58
+ }
59
+ }
@@ -0,0 +1,4 @@
1
+ import { derive as deriveAt } from "../fact-derive.mjs"
2
+
3
+ // All successful test derivations use caller-owned, fixed observation time.
4
+ export const derive = (ledger: unknown, spec: unknown) => deriveAt(ledger, spec !== null && typeof spec === "object" && !Array.isArray(spec) ? { now: "2026-10-23T08:00:00Z", ...spec } : spec)
@@ -0,0 +1,65 @@
1
+ import { describe, expect, onTestFinished, test } from "bun:test"
2
+ import { mkdtempSync, rmSync } from "node:fs"
3
+ import { tmpdir } from "node:os"
4
+ import { join } from "node:path"
5
+ import { recompute } from "../fact-derive.mjs"
6
+ import { derive } from "./derive-clock"
7
+ import { addRow, emptyLedger, readLedger, writeLedger } from "../fact-ledger.mjs"
8
+
9
+
10
+ const HASH = "a".repeat(64)
11
+
12
+ const EOK_WON = "\uC5B5\uC6D0"
13
+
14
+
15
+ type Row = Record<string, unknown>
16
+
17
+ type Ledger = { schemaVersion: number; rows: Row[]; events: unknown[] }
18
+
19
+
20
+ function measured(factId: string, value: string, unit: string, extra: Row = {}): Row {
21
+ return {
22
+ fact_id: factId,
23
+ kind: "measured",
24
+ value,
25
+ unit,
26
+ raw: `${value} ${unit}`,
27
+ quote: `The figure is ${value} ${unit}.`,
28
+ source_id: "S1",
29
+ locator: { artifact: "sources/S1/text.txt", char_start: 0, char_end: 20 },
30
+ snapshot_sha256: HASH,
31
+ extracted_by: "fact add --find",
32
+ observed_at: "2026-10-23T08:00:00Z",
33
+ label: factId.toLowerCase(),
34
+ ...extra,
35
+ }
36
+ }
37
+
38
+
39
+ function ledgerOf(rows: Row[]): Ledger {
40
+ const ledger = emptyLedger() as Ledger
41
+ for (const row of rows) addRow(ledger, row)
42
+ return ledger
43
+ }
44
+
45
+
46
+ function fixture(): Ledger {
47
+ return ledgerOf([
48
+ measured("F5", "100", EOK_WON, { population: "all" }),
49
+ measured("F6", "200", EOK_WON, { population: "all" }),
50
+ measured("F7", "200", EOK_WON, { population: "subset" }),
51
+ measured("F8", "15", "%"),
52
+ measured("F9", "20", "%"),
53
+ measured("F12", "320", "m"),
54
+ measured("F19", "100", "case", { valid_at: "2025-Q3", entity: "acme" }),
55
+ measured("F20", "112", "case", { valid_at: "2026-Q3", entity: "acme" }),
56
+ measured("F30", "3.2", "m"),
57
+ ])
58
+ }
59
+
60
+
61
+ function rowOf(result: { row?: Row; error?: string; detail?: string }): Row {
62
+ if (!result.row) throw new Error(`expected a row, got ${result.error}: ${result.detail}`)
63
+ return result.row
64
+ }
65
+ export { HASH, EOK_WON, Row, Ledger, measured, ledgerOf, fixture, rowOf }
@@ -0,0 +1,41 @@
1
+ import { expect, test } from "bun:test"
2
+ import { recompute } from "../fact-derive.mjs"
3
+ import { derive } from "./derive-clock"
4
+ import { addRow, emptyLedger, retractRow, validateLedger } from "../fact-ledger.mjs"
5
+ import { canonicalUnit } from "../unit-rules.mjs"
6
+ import { convertFactor } from "../units.mjs"
7
+
8
+
9
+ type Row = Record<string, unknown>
10
+
11
+ type Book = { schemaVersion: number; rows: Row[]; events: unknown[] }
12
+
13
+ const now = "2026-10-23T08:00:00Z"
14
+
15
+ function book(values: string[] = ["1", "3"], units: Array<string | null> = ["m", "m"], extras: Row[] = []): Book {
16
+ const ledger = emptyLedger() as Book
17
+ values.forEach((value, i) => addRow(ledger, {
18
+ kind: "measured", value, unit: units[i], raw: value, quote: value, source_id: "S1",
19
+ locator: { artifact: "sources/S1/text.txt", char_start: 0, char_end: 1 },
20
+ snapshot_sha256: "a".repeat(64), extracted_by: "test", observed_at: now, label: `f${i + 1}`,
21
+ ...extras[i],
22
+ }))
23
+ return ledger
24
+ }
25
+
26
+ function row(ledger: Book, spec: Row): Row {
27
+ const result = derive(ledger, { ...spec, now })
28
+ if (!("row" in result)) throw Error(JSON.stringify(result))
29
+ return result.row as Row
30
+ }
31
+
32
+ const sum = { op: "sum", operands: ["F1", "F2"], unit: "m" }
33
+
34
+ function refused(ledger: Book, spec: unknown) {
35
+ const before = structuredClone(ledger)
36
+ const result = derive(ledger, spec)
37
+ expect(result).toMatchObject({ error: "incompatible_operands" })
38
+ expect(ledger).toEqual(before)
39
+ return result
40
+ }
41
+ export { Row, Book, now, book, row, sum, refused }