oh-my-opencode 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 (495) 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 -316
  64. package/dist/skills/ulw-research/references/deliverable-phase.md +23 -21
  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 +12 -5
  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 +13 -4
  77. package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -110
  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-polish.test.ts +4 -3
  84. package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  85. package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
  86. package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  87. package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  88. package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
  89. package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  90. package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  91. package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  92. package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  93. package/dist/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  94. package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  95. package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  96. package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  97. package/dist/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  98. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  99. package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  100. package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  101. package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  102. package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  103. package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  104. package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  105. package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  106. package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  107. package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  108. package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  109. package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  110. package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  111. package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  112. package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  113. package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  114. package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  115. package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  116. package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  117. package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  118. package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  119. package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
  120. package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
  121. package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
  122. package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  123. package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  124. package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  125. package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  126. package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
  127. package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  128. package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  129. package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
  130. package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
  131. package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  132. package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  133. package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
  134. package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  135. package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
  136. package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  137. package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  138. package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  139. package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  140. package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  141. package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  142. package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  143. package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  144. package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  145. package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  146. package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  147. package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
  148. package/dist/skills/ulw-research/scripts/report-tools.test.ts +5 -800
  149. package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  150. package/dist/skills/ulw-research/scripts/source-commands.mjs +79 -26
  151. package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  152. package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  153. package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  154. package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  155. package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
  156. package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  157. package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  158. package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  159. package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  160. package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  161. package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  162. package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  163. package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  164. package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  165. package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  166. package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  167. package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  168. package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  169. package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  170. package/dist/skills/ulw-research/scripts/units.mjs +14 -3
  171. package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
  172. package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  173. package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  174. package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  175. package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  176. package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  177. package/dist/tools/delegate-task/executor-types.d.ts +1 -0
  178. package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
  179. package/dist/tools/delegate-task/types.d.ts +1 -0
  180. package/dist/tools/skill/description-formatter.d.ts +2 -1
  181. package/dist/tools/skill/types.d.ts +6 -0
  182. package/dist/tui.js +131 -33
  183. package/package.json +18 -15
  184. package/packages/git-bash-mcp/package.json +1 -1
  185. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  186. package/packages/omo-codex/plugin/README.md +1 -1
  187. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  188. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  189. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  190. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  191. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  192. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  193. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  194. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  195. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  196. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  197. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
  198. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
  199. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  200. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  201. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  202. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  203. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  204. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  205. package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
  206. package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
  207. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
  208. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
  209. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  210. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  211. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
  212. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
  213. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
  214. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
  215. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
  216. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
  217. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  218. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  219. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  220. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  221. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  222. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
  223. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  224. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  225. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  226. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  227. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  228. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  229. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  230. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  231. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  232. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  233. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  234. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  235. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  236. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  237. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  238. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  239. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  240. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  241. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  242. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  243. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  244. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  245. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  246. package/packages/omo-codex/plugin/package-lock.json +16 -16
  247. package/packages/omo-codex/plugin/package.json +1 -1
  248. package/packages/omo-codex/plugin/shared/package.json +1 -1
  249. package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
  250. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
  251. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
  252. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  253. package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  254. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  255. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
  256. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
  257. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  258. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
  259. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  260. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  261. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
  262. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
  263. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  264. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
  265. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
  266. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
  267. package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
  268. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  269. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  270. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  271. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  272. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
  273. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  274. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
  275. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  276. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
  277. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
  278. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  279. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  280. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
  281. package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
  282. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
  283. package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
  284. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  285. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
  286. package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  287. package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
  288. package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
  289. package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
  290. package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
  291. package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  292. package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
  293. package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  294. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  295. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
  296. package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
  297. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  298. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  299. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  300. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  301. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  302. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  303. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  304. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  305. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  306. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  307. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  308. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  309. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  310. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  311. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  312. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  313. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  314. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  315. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  316. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  317. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  318. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
  319. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
  320. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
  321. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  322. package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  323. package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
  324. package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  325. package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
  326. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  327. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
  328. package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
  329. package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  330. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  331. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  332. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  333. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
  334. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
  335. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  336. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  337. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
  338. package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  339. package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
  340. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
  341. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
  342. package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
  343. package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
  344. package/packages/shared-skills/skill-source-filter.mjs +6 -2
  345. package/packages/shared-skills/skills/ast-grep/README.md +1 -1
  346. package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
  347. package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
  348. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  349. package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  350. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  351. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
  352. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
  353. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  354. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
  355. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  356. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  357. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
  358. package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
  359. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  360. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
  361. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
  362. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
  363. package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
  364. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  365. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  366. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
  367. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  368. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
  369. package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
  370. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  371. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  372. package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
  373. package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
  374. package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
  375. package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  376. package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
  377. package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  378. package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
  379. package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
  380. package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
  381. package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
  382. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  383. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  384. package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  385. package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  386. package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
  387. package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
  388. package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  389. package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  390. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  391. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  392. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  393. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
  394. package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  395. package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
  396. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  397. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  398. package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
  399. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
  400. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
  401. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
  402. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
  403. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
  404. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  405. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  406. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  407. package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
  408. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  409. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  410. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  411. package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  412. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  413. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  414. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  415. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  416. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  417. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  418. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  419. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
  420. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  421. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  422. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  423. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  424. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  425. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  426. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  427. package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  428. package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  429. package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
  430. package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
  431. package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
  432. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  433. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  434. package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  435. package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  436. package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
  437. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  438. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  439. package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
  440. package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
  441. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  442. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  443. package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
  444. package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  445. package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
  446. package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  447. package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  448. package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  449. package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  450. package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  451. package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  452. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  453. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  454. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  455. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  456. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  457. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
  458. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
  459. package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  460. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
  461. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  462. package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  463. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  464. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  465. package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
  466. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  467. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  468. package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  469. package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  470. package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  471. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  472. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  473. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  474. package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  475. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  476. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  477. package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  478. package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  479. package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  480. package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
  481. package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
  482. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  483. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  484. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  485. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  486. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  487. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
  488. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
  489. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
  490. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
  491. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
  492. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
  493. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
  494. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
  495. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
@@ -0,0 +1,241 @@
1
+ import { describe, expect, test } from "bun:test"
2
+ import { display, recompute } from "../fact-derive.mjs"
3
+ import { derive } from "./derive-clock"
4
+ import { parseExpr } from "../fact-expr.mjs"
5
+ import { addRow, emptyLedger, OPERATIONS } from "../fact-ledger.mjs"
6
+ import { canonicalUnit, expectedUnit, isAffine, OPERATION_RULES, renderPrecision } from "../unit-rules.mjs"
7
+
8
+ // Property checks of references/unit-rules.md: every case table below is keyed by the registry's own operation list,
9
+ // so a new operation without valid, relabel, and malformed cases fails here.
10
+
11
+ type Row = Record<string, unknown>
12
+
13
+ type Ledger = { schemaVersion: number; rows: Row[]; events: unknown[] }
14
+
15
+ type Spec = Record<string, unknown>
16
+
17
+ const HASH = "a".repeat(64)
18
+
19
+ function measured(factId: string, value: string, unit: string | null, extra: Row = {}): Row {
20
+ return {
21
+ fact_id: factId,
22
+ kind: "measured",
23
+ value,
24
+ unit,
25
+ raw: `${value} ${unit ?? ""}`.trim(),
26
+ quote: `The figure is ${value}.`,
27
+ source_id: "S1",
28
+ locator: { artifact: "sources/S1/text.txt", char_start: 0, char_end: 20 },
29
+ snapshot_sha256: HASH,
30
+ extracted_by: "fact add --find",
31
+ observed_at: "2026-10-23T08:00:00Z",
32
+ label: factId.toLowerCase(),
33
+ ...extra,
34
+ }
35
+ }
36
+
37
+ function ledger(): Ledger {
38
+ const built = emptyLedger() as Ledger
39
+ const rows = [
40
+ measured("F1", "1", "m"),
41
+ measured("F2", "3", "m"),
42
+ measured("F3", "20", "%"),
43
+ measured("F4", "15", "%"),
44
+ measured("F5", "5", "%p"),
45
+ measured("F6", "100", "case", { valid_at: "2025", entity: "acme" }),
46
+ measured("F7", "112", "case", { valid_at: "2026", entity: "acme" }),
47
+ measured("F8", "40", "person"),
48
+ measured("F9", "200", "person"),
49
+ measured("F10", "100", "USD"),
50
+ measured("F11", "20", "USD/person"),
51
+ measured("F12", "0", "m"),
52
+ measured("F13", "25", "C", { valid_at: "2025", entity: "x" }),
53
+ measured("F14", "30", "C", { valid_at: "2026", entity: "x" }),
54
+ measured("F15", "0", "person"),
55
+ measured("F16", "2.5", "kilometre"),
56
+ measured("F17", "120", "case", { valid_at: "2026", entity: "other" }),
57
+ measured("F18", "0", "case", { valid_at: "2025", entity: "acme" }),
58
+ measured("F19", "-5", "person"),
59
+ measured("F20", "2", "%p"),
60
+ measured("F21", "105", "case", { valid_at: "2025", entity: "acme" }),
61
+ measured("F22", "200", "person"),
62
+ ]
63
+ for (const row of rows) addRow(built, row)
64
+ return built
65
+ }
66
+
67
+ const PCT_SUM = { op: "sum", operands: ["F3", "F4"], unit: "%", disjoint: true, reference: "all respondents", rationale: "disjoint answer shares" }
68
+
69
+ const VALID: Record<string, Array<{ spec: Spec; unit: string | null; precision?: "places" | "sigfigs" }>> = {
70
+ sum: [
71
+ { spec: { op: "sum", operands: ["F1", "F2"], unit: "m" }, unit: "m" },
72
+ { spec: { op: "sum", operands: ["F1", "F2"], unit: "metre" }, unit: "m" },
73
+ { spec: PCT_SUM, unit: "%" },
74
+ ],
75
+ diff: [
76
+ { spec: { op: "diff", operands: ["F2", "F1"], unit: "m" }, unit: "m" },
77
+ { spec: { op: "diff", operands: ["F3", "F4"], unit: "pp" }, unit: "%p" },
78
+ { spec: { op: "diff", operands: ["F3", "F5"], unit: "%" }, unit: "%" },
79
+ { spec: { op: "diff", operands: ["F5", "F20"], unit: "%p" }, unit: "%p" },
80
+ ],
81
+ growth: [{ spec: { op: "growth", from: "F6", to: "F7", unit: "%" }, unit: "%" }],
82
+ share: [
83
+ { spec: { op: "share", part: "F8", whole: "F9", unit: "%" }, unit: "%" },
84
+ { spec: { op: "share", part: "F22", whole: "F9", unit: "%" }, unit: "%" },
85
+ ],
86
+ ratio: [
87
+ { spec: { op: "ratio", num: "F10", den: "F11", unit: "person" }, unit: "person" },
88
+ { spec: { op: "ratio", num: "F1", den: "F2", unit: null }, unit: null },
89
+ { spec: { op: "ratio", num: "F10", den: "F9", unit: "USD/person" }, unit: "USD/person" },
90
+ ],
91
+ convert: [
92
+ { spec: { op: "convert", operands: ["F12"], to: "km" }, unit: "km" },
93
+ { spec: { op: "convert", operands: ["F16"], to: "m" }, unit: "m" },
94
+ { spec: { op: "convert", operands: ["F2"], to: "kilometre" }, unit: "km" },
95
+ ],
96
+ expr: [
97
+ { spec: { op: "expr", formula: "F3 - F4", unit: "%p" }, unit: "%p", precision: "places" },
98
+ { spec: { op: "expr", formula: "F2 - F1", unit: "m" }, unit: "m", precision: "places" },
99
+ { spec: { op: "expr", formula: "F5", unit: "%p" }, unit: "%p", precision: "places" },
100
+ { spec: { op: "expr", formula: "F1 * F1 / F2", unit: "m" }, unit: "m" },
101
+ { spec: { op: "expr", formula: "F10 / F11", unit: "person" }, unit: "person" },
102
+ { spec: { op: "expr", formula: "pct(F8 / F9)", unit: "%" }, unit: "%" },
103
+ { spec: { op: "expr", formula: "F3 * F9", unit: "person" }, unit: "person" },
104
+ ],
105
+ }
106
+
107
+ /** Invariant 5 per operation: sum and diff render by decimal places, the rest by significant figures (expr cases override). */
108
+ const PRECISION: Record<string, "places" | "sigfigs"> = { sum: "places", diff: "places", growth: "sigfigs", share: "sigfigs", ratio: "sigfigs", convert: "sigfigs", expr: "sigfigs" }
109
+
110
+ const RELABELS = [null, "%", "%p", "pp", "bp", "m", "metre", "km", "kilometre", "cm", "C", "case", "person", "USD", "USD/person", "person/USD", "KRW-e8"]
111
+
112
+ type Mutation = { name: string; base: Spec; mutate: (row: Row, book: Ledger) => Row; reason: string }
113
+
114
+ const generic = (base: Spec, arity: string[], arityReason = "takes ", missingReason = "no ledger row F999"): Mutation[] => [
115
+ { name: "operands null", base, mutate: (row) => ({ ...row, operands: null }), reason: "operands must be a non-empty array" },
116
+ { name: "operands empty", base, mutate: (row) => ({ ...row, operands: [] }), reason: "operands must be a non-empty array" },
117
+ { name: "wrong arity", base, mutate: (row) => ({ ...row, operands: arity }), reason: arityReason },
118
+ { name: "missing operand id", base, mutate: (row) => ({ ...row, operands: (row.operands as string[]).map((id, index) => (index === 0 ? "F999" : id)) }), reason: missingReason },
119
+ { name: "invalid rational", base, mutate: (row) => ({ ...row, exact: { num: "x", den: "1" } }), reason: "exact must be { num, den }" },
120
+ { name: "no operation", base, mutate: (row) => ({ ...row, operation: "mean" }), reason: 'operation "mean" is not one of' },
121
+ { name: "repeated operand", base, mutate: (row) => ({ ...row, operands: repeatFirst(row.operands as string[]) }), reason: "is repeated" },
122
+ { name: "self reference", base, mutate: (row) => ({ ...row, operands: (row.operands as string[]).map((id, index) => (index === 0 ? row.fact_id : id)) }), reason: "cites itself" },
123
+ { name: "kind operation", base, mutate: (row) => ({ ...row, kind: "assumed" }), reason: "kind assumed" },
124
+ { name: "audit fields", base, mutate: (row) => ({ ...row, factor: "999" }), reason: "factor" },
125
+ { name: "precision field", base, mutate: (row) => ({ ...row, precision: { places: -1, sigfigs: 0 } }), reason: "precision" },
126
+ { name: "compatibility field", base, mutate: (row) => ({ ...row, compatibility: "invalid" }), reason: "compatibility" },
127
+ { name: "metadata fields", base, mutate: (row) => ({ ...row, population: { tampered: true } }), reason: "population" },
128
+ { name: "noncanonical operand", base, mutate: (row, book) => {
129
+ const operand = book.rows.find((r) => r.fact_id === (row.operands as string[])[0])
130
+ if (!operand) throw Error("fixture operand missing")
131
+ operand.unit = `${operand.unit}*bp/%p`
132
+ return row
133
+ }, reason: "canonical" },
134
+ ]
135
+
136
+ /** The first operand id in a second slot: [F1, F2] -> [F1, F1]; a one-operand row gets [F1, F1]. */
137
+ const repeatFirst = (ids: string[]) => (ids.length === 1 ? [ids[0], ids[0]] : [...ids.slice(0, -1), ids[0]])
138
+
139
+ const operands = (ids: string[]) => (row: Row) => ({ ...row, operands: ids })
140
+
141
+ const MALFORMED: Record<string, Mutation[]> = {
142
+ sum: [
143
+ ...generic(VALID.sum[0].spec, ["F1"]),
144
+ { name: "no context", base: VALID.sum[0].spec, mutate: (row) => ({ ...row, context: null }), reason: "sum rows carry a context object" },
145
+ { name: "% without disjoint", base: PCT_SUM, mutate: (row) => ({ ...row, context: { disjoint: false, reference: "all respondents" } }), reason: "needs disjoint shares" },
146
+ { name: "% without reference", base: PCT_SUM, mutate: (row) => ({ ...row, context: { disjoint: true, reference: null } }), reason: "one shared reference" },
147
+ { name: "% without rationale", base: PCT_SUM, mutate: (row) => ({ ...row, rationale: null }), reason: "needs a rationale" },
148
+ { name: "unequal units", base: VALID.sum[0].spec, mutate: operands(["F1", "F8"]), reason: "unit differs" },
149
+ { name: "affine units", base: VALID.sum[0].spec, mutate: operands(["F13", "F14"]), reason: "sum refuses affine" },
150
+ { name: "closed context", base: VALID.sum[0].spec, mutate: (row) => ({ ...row, context: { disjoint: "true", reference: 7, extra: true } }), reason: "sum context" },
151
+ { name: "share total", base: PCT_SUM, mutate: (row, book) => {
152
+ for (const operand of book.rows.filter((r) => ["F3", "F4"].includes(String(r.fact_id)))) Object.assign(operand, { value: "60", exact: { num: "60", den: "1" } })
153
+ return row
154
+ }, reason: "total <= 100" },
155
+ ],
156
+ diff: [
157
+ ...generic(VALID.diff[0].spec, ["F2", "F1", "F8"]),
158
+ { name: "%p - % pair", base: VALID.diff[2].spec, mutate: operands(["F5", "F3"]), reason: '"%p" - "%" is not a typed pair' },
159
+ { name: "unit - other unit pair", base: VALID.diff[0].spec, mutate: operands(["F1", "F8"]), reason: '"m" - "person" is not a typed pair' },
160
+ { name: "affine units", base: VALID.diff[0].spec, mutate: operands(["F14", "F13"]), reason: "affine (temperature)" },
161
+ { name: "stray context", base: VALID.diff[0].spec, mutate: (row) => ({ ...row, context: "x" }), reason: "diff rows carry no context" },
162
+ ],
163
+ growth: [
164
+ ...generic(VALID.growth[0].spec, ["F6"]),
165
+ { name: "affine units", base: VALID.growth[0].spec, mutate: operands(["F13", "F14"]), reason: "growth refuses affine" },
166
+ { name: "unequal units", base: VALID.growth[0].spec, mutate: operands(["F6", "F8"]), reason: "unit differs" },
167
+ { name: "entity mismatch", base: VALID.growth[0].spec, mutate: operands(["F6", "F17"]), reason: "growth needs one declared entity" },
168
+ { name: "one period", base: VALID.growth[0].spec, mutate: operands(["F6", "F21"]), reason: "two different valid_at periods" },
169
+ { name: "from <= 0", base: VALID.growth[0].spec, mutate: operands(["F18", "F7"]), reason: "positive starting value in F18" },
170
+ { name: "stray context", base: VALID.growth[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "growth rows carry no context" },
171
+ ],
172
+ share: [
173
+ ...generic(VALID.share[0].spec, ["F8"]),
174
+ { name: "affine units", base: VALID.share[0].spec, mutate: operands(["F13", "F14"]), reason: "share refuses affine" },
175
+ { name: "unequal units", base: VALID.share[0].spec, mutate: operands(["F8", "F1"]), reason: "unit differs" },
176
+ { name: "whole <= 0", base: VALID.share[0].spec, mutate: operands(["F8", "F15"]), reason: "positive whole in F15" },
177
+ { name: "part < 0", base: VALID.share[0].spec, mutate: operands(["F19", "F9"]), reason: "F19 is outside [0, F9]" },
178
+ { name: "part above whole", base: VALID.share[0].spec, mutate: operands(["F9", "F8"]), reason: "F9 is outside [0, F8]" },
179
+ { name: "stray context", base: VALID.share[0].spec, mutate: (row) => ({ ...row, context: "x" }), reason: "share rows carry no context" },
180
+ ],
181
+ ratio: [
182
+ ...generic(VALID.ratio[0].spec, ["F10"]),
183
+ { name: "affine units", base: VALID.ratio[0].spec, mutate: operands(["F13", "F14"]), reason: "ratio refuses affine" },
184
+ { name: "divides by zero", base: VALID.ratio[0].spec, mutate: operands(["F10", "F15"]), reason: "denominator F15 is zero" },
185
+ { name: "stray context", base: VALID.ratio[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "ratio rows carry no context" },
186
+ ],
187
+ convert: [
188
+ ...generic(VALID.convert[0].spec, ["F12", "F1"]),
189
+ { name: "no context", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: null }), reason: "convert rows carry a context object" },
190
+ { name: "empty target", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "" } }), reason: "carries its target in context.target" },
191
+ { name: "alias target", base: VALID.convert[0].spec, mutate: (row) => ({ ...relabel(row, "kilometre")[0], context: { target: "kilometre" } }), reason: 'context.target "kilometre" is not canonical' },
192
+ { name: "currency target", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "USD" } }), reason: "no table conversion to USD (a currency)" },
193
+ { name: "no factor to target", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "person" } }), reason: 'F12 in "m" has no table conversion to person' },
194
+ { name: "closed context", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "km", extra: true } }), reason: "exactly target" },
195
+ ],
196
+ expr: [
197
+ ...generic(VALID.expr[0].spec, ["F3", "F4", "F5"], "do not match operands", "do not match operands F999, F4"),
198
+ { name: "formula id mismatch", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 - F99" }), reason: "do not match operands" },
199
+ { name: "parse error", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 -" }), reason: "the expression ends early" },
200
+ { name: "divides by zero", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 / (F4 - F4)" }), reason: "the expression divides by zero" },
201
+ { name: "uninferable unit", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 + F4" }), reason: "adding % values" },
202
+ { name: "affine sum", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F13 + F14", operands: ["F13", "F14"] }), reason: "adding affine (temperature)" },
203
+ { name: "stray context", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "expr rows carry no context" },
204
+ { name: "undated rate", base: VALID.expr[0].spec, mutate: (row, book) => {
205
+ const rate = book.rows.find((r) => r.fact_id === "F3")
206
+ if (!rate) throw Error("fixture rate missing")
207
+ rate.unit = "USD/EUR"
208
+ return { ...row, formula: "F3 * F4" }
209
+ }, reason: "dated valid_at" },
210
+ ],
211
+ }
212
+
213
+ /** Review r6 HIGH: one id twice is never disjoint shares; expr repeats F1 inside its formula and stores the id set. */
214
+ const REPEATED: Record<string, Spec> = {
215
+ sum: { ...PCT_SUM, operands: ["F3", "F3"] },
216
+ diff: { op: "diff", operands: ["F3", "F3"], unit: "%p" },
217
+ growth: { op: "growth", from: "F6", to: "F6", unit: "%" },
218
+ share: { op: "share", part: "F9", whole: "F9", unit: "%" },
219
+ ratio: { op: "ratio", num: "F10", den: "F10", unit: null },
220
+ convert: { op: "convert", operands: ["F12", "F12"], to: "km" },
221
+ expr: { op: "expr", formula: "F1 * F1 / F2", unit: "m" },
222
+ }
223
+
224
+ function rowOf(result: { row?: Row; error?: string; detail?: string }): Row {
225
+ if (!result.row) throw new Error(`expected a row, got ${result.error}: ${result.detail}`)
226
+ return result.row
227
+ }
228
+
229
+ /** The row relabeled to `unit`; when the operation persists a context, a second variant rewrites that context too. */
230
+ function relabel(row: Row, unit: string | null): Row[] {
231
+ const shown = display(row.value, unit)
232
+ const render = row.operation === "convert" ? `${shown} ${String(row.render).slice(String(row.render).indexOf("("))}` : shown
233
+ const plain = { ...row, unit, raw: render, render }
234
+ const context = row.context as Row
235
+ if (row.operation === "convert") return [plain, { ...plain, context: { ...context, target: unit } }]
236
+ if (row.operation === "sum") return [plain, { ...plain, context: { ...context, reference: `relabeled ${unit}` } }]
237
+ return [plain]
238
+ }
239
+
240
+ const OPS = Object.keys(OPERATION_RULES)
241
+ export { Row, Ledger, Spec, HASH, measured, ledger, PCT_SUM, VALID, PRECISION, RELABELS, Mutation, generic, repeatFirst, operands, MALFORMED, REPEATED, rowOf, relabel, OPS }
@@ -0,0 +1,30 @@
1
+ /// <reference types="bun-types" />
2
+ import { readFileSync } from "node:fs"
3
+ import { join } from "node:path"
4
+
5
+ import { valueChecks } from "../fidelity-values.mjs"
6
+ import { buildContext } from "../gates-static.mjs"
7
+ import { parseHtml } from "../html-lite.mjs"
8
+
9
+ export type Defect = { code: string; severity: string; selector: string; line: number; message: string; hint: string }
10
+ export type Row = Record<string, unknown> & { fact_id: string }
11
+ type Ledger = { schemaVersion: number; rows: Row[]; events: unknown[] }
12
+ type FillEntry = { fact_id: string; rendered: string; selector?: string }
13
+ type Options = { ledger?: Ledger; fillMap?: FillEntry[] | null; sourcesDir?: string | null; baseDir?: string; recompute?: (ledger: object, row: object) => { ok: boolean }; asOf?: string }
14
+
15
+ const FIX = join(import.meta.dir, "fixtures", "fidelity")
16
+ export const SOURCES = join(FIX, "sources")
17
+ export const LEDGER: Ledger = JSON.parse(readFileSync(join(FIX, "ledger-verify.json"), "utf8"))
18
+
19
+ export function ledgerWith(id: string, patch: Record<string, unknown>): Ledger {
20
+ const copy = structuredClone(LEDGER)
21
+ copy.rows = copy.rows.map((row) => (row.fact_id === id ? { ...row, ...patch } : row))
22
+ return copy
23
+ }
24
+
25
+ export function run(body: string, options: Options = {}): Defect[] {
26
+ const html = /<h2/.test(body) ? body : `<h2>Findings</h2>\n${body}`
27
+ const ctx = buildContext(parseHtml(html), { baseDir: options.baseDir ?? FIX })
28
+ const sourcesDir = options.sourcesDir === undefined ? SOURCES : options.sourcesDir
29
+ return valueChecks(ctx, options.ledger ?? LEDGER, options.fillMap ?? null, sourcesDir, options) as Defect[]
30
+ }
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <body>
4
+ <p>USD 4.2<sup>2</sup> billion</p>
5
+ <p>27.3<sup><a href="#fn1">1</a></sup> percent</p>
6
+ <p>km<sup>2</sup>; 10<sup>9</sup> kWh</p>
7
+ <p><span>1</span><span>,</span><span>234.5</span></p>
8
+ <p>1 234 567</p>
9
+ <p><del>1,200</del> <ins>1,250</ins></p>
10
+ <p><time datetime="2026-10-01T09:00:00Z">1 Oct</time></p>
11
+ <p><span style="display:none">99.9</span></p>
12
+ <table><tr><th>Total<sup>2</sup></th><td>12,345</td><td>15,678</td></tr></table>
13
+ </body>
14
+ </html>
@@ -0,0 +1,20 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="utf-8"><title>Reference shapes</title></head>
3
+ <body>
4
+ <h2>Findings</h2>
5
+ <p>The bridge span is reported in the cited annual report [S1].</p>
6
+ <h2>Sources</h2>
7
+ <p class="note">Publication cutoff and access date: October 25, 2026. Every linked source was read directly.</p>
8
+ <h3>2024</h3>
9
+ <ol>
10
+ <li>Smith, J. (2024). Annual report. https://example.com/annual-2024</li>
11
+ <li>Harbor Authority, Yearbook 2024, pp. 12-15, https://example.com/yearbook</li>
12
+ <li>Bridge Review, Vol. 2024/1, No. 3, https://example.com/review. Accessed 25 October 2026.</li>
13
+ <li>[S1] Annual report 2024, <a href="https://example.com/report">example.com/report</a></li>
14
+ </ol>
15
+ <p>Annual report 2024, https://example.com/report</p>
16
+ <p>[S2] City statistics office, 2025 release, https://example.com/stats<br>Last updated 2026-03-24.</p>
17
+ <dl><dt>[S3] Transit survey</dt><dd>Survey 2025, https://example.com/survey</dd><dd>Accessed 2026-10-25.</dd></dl>
18
+ <table><thead><tr><th>Source</th><th>What it contains</th><th>Reliability</th><th>Access date</th></tr></thead>
19
+ <tbody><tr><td><a href="https://example.com/a">Agency report 2024</a></td><td>Span tables, 2019-2024</td><td>Primary</td><td>2026-10-25</td></tr></tbody></table>
20
+ </body></html>
@@ -0,0 +1,196 @@
1
+ // Row tables for the Sources numeral classes (lead order, review round 5 #11302): every form of a
2
+ // class with the class the Sources predicate must give each digit run in it. A string expectation
3
+ // applies to every digit run of the input; an array lists them in order. Consumed by
4
+ // sources-citation.test.ts. Korean text is \u escaped.
5
+
6
+ export type NumeralKind = "numeral" | "name" | "date" | "citation-field"
7
+ export type ClassRow = { input: string; expected: NumeralKind | NumeralKind[] }
8
+
9
+ // Class 1: numeral tokenization vs glued letters. Every unit, multiplier, percent, and currency
10
+ // token of units.mjs (tokens and aliases) and of the numerals.mjs UNIT pattern, written after the
11
+ // number: glued, spaced, glued behind a Hangul word, glued behind a Latin word, with a Korean
12
+ // particle, and behind a Hangul word with a particle.
13
+ const LATIN_UNITS = [
14
+ "mm", "millimeter", "millimeters", "millimetre", "cm", "centimeter", "m", "meter", "meters", "metre", "km", "kilometer", "kilometers",
15
+ "g", "gram", "grams", "kg", "kilogram", "kilograms", "t", "ton", "tons", "tonne", "tonnes",
16
+ "ms", "millisecond", "milliseconds", "s", "sec", "secs", "second", "seconds", "min", "mins", "minute", "minutes", "h", "hr", "hrs", "hour", "hours",
17
+ "day", "days", "week", "weeks", "month", "months", "mo", "year", "years", "yr", "yrs",
18
+ "B", "byte", "bytes", "KB", "MB", "GB", "TB", "kb", "mb", "gb", "tb", "C", "F", "celsius", "fahrenheit",
19
+ "percent", "pct", "permille", "pp", "bp", "bps",
20
+ "x", "times", "k", "K", "thousand", "M", "mn", "million", "b", "bn", "billion", "T", "trillion",
21
+ "person", "persons", "people", "users", "employees", "engineers", "tokens", "requests", "stars", "downloads", "customers", "case", "cases",
22
+ "KRW", "won", "USD", "usd", "dollar", "dollars", "EUR", "eur", "euro", "euros", "JPY", "yen", "GBP", "pound", "pounds",
23
+ ]
24
+ const SYMBOL_UNITS = ["%", "%p", "%pt", "\u2030", "\u00D7", "\u00B0C", "\u00B0F", "\u2103", "\u2109", "$", "\u20AC", "\u00A3", "\u00A5", "\u20A9"]
25
+ const HANGUL_UNITS = [
26
+ "\uBC00\uB9AC\uBBF8\uD130", "\uC13C\uD2F0\uBBF8\uD130", "\uBBF8\uD130", "\uD0AC\uB85C\uBBF8\uD130", "\uADF8\uB7A8", "\uD0AC\uB85C\uADF8\uB7A8", "\uD1A4", "\uBC00\uB9AC\uCD08", "\uCD08", "\uBD84", "\uC2DC\uAC04", "\uC77C", "\uC8FC", "\uAC1C\uC6D4", "\uB144",
27
+ "\uBC14\uC774\uD2B8", "\uD0AC\uB85C\uBC14\uC774\uD2B8", "\uBA54\uAC00\uBC14\uC774\uD2B8", "\uAE30\uAC00\uBC14\uC774\uD2B8", "\uD14C\uB77C\uBC14\uC774\uD2B8",
28
+ "\uD37C\uC13C\uD2B8", "\uD504\uB85C", "\uD37C\uBC00", "\uD37C\uC13C\uD2B8\uD3EC\uC778\uD2B8", "\uBC30", "\uCC9C", "\uB9CC", "\uBC31\uB9CC", "\uC5B5", "\uC2ED\uC5B5", "\uC870",
29
+ "\uBA85", "\uAC74", "\uAC1C", "\uD68C", "\uBC88", "\uC6D0", "\uCC9C\uC6D0", "\uB9CC\uC6D0", "\uC5B5\uC6D0", "\uC870\uC6D0", "\uB2EC\uB7EC", "\uC720\uB85C", "\uC5D4", "\uD30C\uC6B4\uB4DC",
30
+ ]
31
+ const KO_WORD = "\uB9E4\uCD9C"
32
+ const LATIN_WORD = "rate"
33
+
34
+ const unitRows = (unit: string, kind: "latin" | "symbol" | "hangul"): ClassRow[] => {
35
+ const particle = kind === "hangul" ? "\uC774" : "\uB85C"
36
+ return [
37
+ { input: `5${unit}`, expected: "numeral" },
38
+ { input: `5 ${unit}`, expected: "numeral" },
39
+ { input: `${KO_WORD}5${unit}`, expected: "numeral" },
40
+ // Latin letters on both sides of a digit run make an identifier ("W3C"); a symbol or Hangul unit keeps it a measure.
41
+ { input: `${LATIN_WORD}5${unit}`, expected: kind === "latin" ? "name" : "numeral" },
42
+ { input: `5${unit}${particle}`, expected: "numeral" },
43
+ { input: `${KO_WORD}5${unit}${particle}`, expected: "numeral" },
44
+ ]
45
+ }
46
+
47
+ // Written before the number: currency symbols and codes, and a standalone multiplier x.
48
+ const PREFIXES = ["$", "US$", "\u20AC", "\u00A3", "\u00A5", "\u20A9", "USD", "KRW", "EUR", "JPY", "GBP"]
49
+ const prefixRows = (prefix: string): ClassRow[] => [
50
+ { input: `${prefix}5`, expected: "numeral" },
51
+ { input: `${prefix}5.5`, expected: "numeral" },
52
+ { input: `${KO_WORD}${prefix}5`, expected: "numeral" },
53
+ { input: `${prefix}5bn`, expected: "numeral" },
54
+ ]
55
+
56
+ export const GLUED_LETTER_ROWS: ClassRow[] = [
57
+ ...LATIN_UNITS.flatMap((unit) => unitRows(unit, "latin")),
58
+ ...SYMBOL_UNITS.flatMap((unit) => unitRows(unit, "symbol")),
59
+ ...HANGUL_UNITS.flatMap((unit) => unitRows(unit, "hangul")),
60
+ ...PREFIXES.flatMap(prefixRows),
61
+ // Multipliers on the left and on the right, with decimals.
62
+ { input: "x3", expected: "numeral" },
63
+ { input: "x1.5 faster", expected: "numeral" },
64
+ { input: "(x3)", expected: "numeral" },
65
+ { input: "\uC18D\uB3C4x3", expected: "numeral" },
66
+ { input: "\u00D73", expected: "numeral" },
67
+ { input: "3.5x", expected: "numeral" },
68
+ { input: "1.2bn", expected: "numeral" },
69
+ { input: "5.4T", expected: "numeral" },
70
+ { input: "3.5k", expected: "numeral" },
71
+ { input: "1M+", expected: "numeral" },
72
+ { input: "2.5\uBC30", expected: "numeral" },
73
+ { input: "1,200\uBA85", expected: "numeral" },
74
+ { input: "3\uC5B5 2,000\uB9CC\uC6D0", expected: "numeral" },
75
+ // Glued letters that are not a unit, multiplier, percent, or currency: a name.
76
+ { input: "abc123", expected: "name" },
77
+ { input: "W3C", expected: "name" },
78
+ { input: "eb2b", expected: "name" },
79
+ { input: "a75f4d93ef", expected: "name" },
80
+ { input: "424B4", expected: "name" },
81
+ { input: "1H25", expected: "name" },
82
+ { input: "3D", expected: "name" },
83
+ { input: "21st", expected: "name" },
84
+ { input: "KOSPI200", expected: "name" },
85
+ { input: "Base44", expected: "name" },
86
+ { input: "H100", expected: "name" },
87
+ { input: "mp3", expected: "name" },
88
+ { input: "[w1:x02]", expected: ["name", "name"] },
89
+ { input: "x02", expected: "name" },
90
+ { input: "rate5M", expected: "name" },
91
+ { input: "\uCF54\uB4DCabc123", expected: "name" },
92
+ // Korean ordinals are names: the prefix je, the suffix jjae, and the counter cha.
93
+ { input: "\uC81C3\uD68C", expected: "name" },
94
+ { input: "\uC81C3\uC790", expected: "name" },
95
+ { input: "\uC81C2\uCC28", expected: "name" },
96
+ { input: "3\uBC88\uC9F8", expected: "name" },
97
+ { input: "2\uCC28 \uBCF4\uB3C4", expected: "name" },
98
+ // A word glued in front of a measure keeps it a numeral (the round-4 receipt rows).
99
+ { input: "\uB9E4\uCD9C40% \uC99D\uAC00.", expected: "numeral" },
100
+ { input: "\uC804\uB144\uB300\uBE4430%", expected: "numeral" },
101
+ { input: "\uC57D300\uBA85", expected: "numeral" },
102
+ { input: "Churn rate40%", expected: "numeral" },
103
+ { input: "x3 faster.", expected: "numeral" },
104
+ { input: "Grew 5mn users.", expected: "numeral" },
105
+ { input: "Up 40pct.", expected: "numeral" },
106
+ { input: "5yrs of data.", expected: "numeral" },
107
+ ]
108
+
109
+ // Class 2: date, version, and name shapes: every slashed, dotted, and dashed form.
110
+ export const SHAPE_ROWS: ClassRow[] = [
111
+ // Month/day, day/month/year, and full dates.
112
+ { input: "10/26", expected: "date" },
113
+ { input: "1/31", expected: "date" },
114
+ { input: "12/1", expected: "date" },
115
+ { input: "(released 10/26)", expected: "date" },
116
+ { input: "10/26 \uACF5\uAC1C", expected: "date" },
117
+ { input: "26/10/2026", expected: "date" },
118
+ { input: "10/26/2026", expected: "date" },
119
+ { input: "26.10.2026", expected: "date" },
120
+ { input: "26-10-2026", expected: "date" },
121
+ { input: "2026-10-26", expected: "date" },
122
+ { input: "2026/10/26", expected: "date" },
123
+ { input: "2026.10.26", expected: "date" },
124
+ { input: "2026.10.26.", expected: "date" },
125
+ { input: "2026. 10. 26.", expected: "date" },
126
+ { input: "2026-10", expected: "date" },
127
+ { input: "2026.10", expected: "date" },
128
+ { input: "26.10.26", expected: "date" },
129
+ { input: "Oct 26", expected: "date" },
130
+ { input: "26 Oct", expected: "date" },
131
+ { input: "October 26, 2026", expected: "date" },
132
+ { input: "26 October 2026", expected: "date" },
133
+ { input: "2026\uB144 10\uC6D4 26\uC77C", expected: "date" },
134
+ { input: "10\uC6D4 26\uC77C", expected: "date" },
135
+ { input: "2026", expected: "date" },
136
+ { input: "2026\uB144", expected: "date" },
137
+ { input: "2025\uB144 3\uBD84\uAE30", expected: "date" },
138
+ { input: "3\uBD84\uAE30", expected: "date" },
139
+ { input: "2026\uB144 1\uBD84\uAE30", expected: "date" },
140
+ // Year ranges.
141
+ { input: "2019-2023", expected: "date" },
142
+ { input: "2019~2023", expected: "date" },
143
+ { input: "2019\u20132023", expected: "date" },
144
+ { input: "2019 \u2013 2023", expected: "date" },
145
+ { input: "2025\u20132026\uB144", expected: "date" },
146
+ { input: "2019~2023\uB144", expected: "date" },
147
+ // Not a date: a slashed pair outside month/day, and a day count.
148
+ { input: "13/45", expected: ["numeral", "numeral"] },
149
+ { input: "30 days", expected: "numeral" },
150
+ { input: "30\uC77C\uAC04", expected: "numeral" },
151
+ // Versions and decimals: a dotted run with a segment that is not three digits is a version name;
152
+ // one dot is a decimal; three-digit period groups are a European grouping.
153
+ { input: "1.2", expected: "numeral" },
154
+ { input: "Llama 3.1", expected: "numeral" },
155
+ { input: "v1.2", expected: "name" },
156
+ { input: "1.2.3", expected: "name" },
157
+ { input: "0.30.14", expected: "name" },
158
+ { input: "v2.3.1", expected: "name" },
159
+ { input: "(3.1.1)", expected: "name" },
160
+ { input: "1.234.567", expected: "numeral" },
161
+ { input: "1.234.567\uBA85", expected: "numeral" },
162
+ { input: "1.234,5", expected: "numeral" },
163
+ { input: "1,234.5", expected: "numeral" },
164
+ { input: "1,234,567", expected: "numeral" },
165
+ { input: "1.234", expected: "numeral" },
166
+ // Codes: a filing code whose letter is a multiplier stays a numeral; other codes are names.
167
+ { input: "10-K", expected: "numeral" },
168
+ { input: "8-K", expected: "numeral" },
169
+ { input: "10-Q", expected: "name" },
170
+ { input: "S-1", expected: "name" },
171
+ { input: "#123", expected: "name" },
172
+ { input: "#6674\u2013#7906", expected: ["name", "name"] },
173
+ { input: "GPT-4", expected: "name" },
174
+ { input: "H.15", expected: "name" },
175
+ { input: "Q3", expected: "name" },
176
+ { input: "FY27", expected: "name" },
177
+ { input: "Q3-2024", expected: ["name", "date"] },
178
+ { input: "H1 2026", expected: ["name", "date"] },
179
+ { input: "2024-Q3-F1", expected: ["date", "name", "name"] },
180
+ { input: "DGS10/DGS30", expected: ["name", "name"] },
181
+ // Citation fields: markers, identifiers, and containers.
182
+ { input: "pp. 12-15", expected: "citation-field" },
183
+ { input: "p. 7", expected: "citation-field" },
184
+ { input: "Vol. 2024/1", expected: "citation-field" },
185
+ { input: "No. 3", expected: "citation-field" },
186
+ { input: "3rd edition", expected: "citation-field" },
187
+ { input: "45-52\uCABD", expected: "citation-field" },
188
+ { input: "3\uAD8C 2\uD638", expected: "citation-field" },
189
+ { input: "[S4]", expected: "citation-field" },
190
+ { input: "DOI 10.1145/1571941.1572114", expected: "citation-field" },
191
+ { input: "arXiv 2402.17753", expected: "citation-field" },
192
+ { input: "ISBN 978-0-306-40615-7", expected: "citation-field" },
193
+ { input: "https://example.com/2024/10/report-42", expected: "citation-field" },
194
+ { input: "\"Sales fell 3.5% in Q2\"", expected: "citation-field" },
195
+ { input: "\u300C\uC218\uCD9C 12% \uC99D\uAC00\u300D", expected: "citation-field" },
196
+ ]