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.
- package/dist/agents/refusal-rule.d.ts +7 -0
- package/dist/cli/index.js +1194 -752
- package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
- package/dist/cli/service-auth/commands.d.ts +2 -4
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli/service-auth/keystore.d.ts +26 -2
- package/dist/cli/service-auth/protocol.d.ts +7 -1
- package/dist/cli/service-auth/session.d.ts +6 -0
- package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
- package/dist/cli-node/index.js +1194 -752
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/create-hooks.d.ts +1 -0
- package/dist/features/boulder-state/storage.d.ts +1 -1
- package/dist/features/boulder-state/types.d.ts +1 -1
- package/dist/hooks/atlas/idle-continuation.d.ts +2 -1
- package/dist/hooks/atlas/types.d.ts +9 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/hook.d.ts +19 -0
- package/dist/hooks/momus-review-persistence/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/review-resolution.d.ts +20 -0
- package/dist/hooks/prometheus-md-only/constants.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/fixtures/denial-log.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/guarded-hashline.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/invoke-before.d.ts +7 -0
- package/dist/hooks/prometheus-md-only/fixtures/opencode-patch-parser.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/hook.d.ts +5 -1
- package/dist/hooks/prometheus-md-only/path-policy.d.ts +2 -9
- package/dist/hooks/prometheus-md-only/vendor/opencode-patch-parser.d.ts +22 -0
- package/dist/index.js +2322 -1045
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
- package/dist/shared/posthog-activity-state.d.ts +1 -0
- package/dist/shared/posthog.d.ts +1 -2
- package/dist/shared/resolve-file-write-path.d.ts +6 -0
- package/dist/skills/ast-grep/README.md +1 -1
- package/dist/skills/ast-grep/install.ps1 +5 -3
- package/dist/skills/ast-grep/install.sh +4 -5
- package/dist/skills/ast-grep/references/install.md +2 -2
- package/dist/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/dist/skills/coding-agent-sessions/SKILL.md +11 -11
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/dist/skills/coding-agent-sessions/references/codex.md +4 -4
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/dist/skills/frontend/ATTRIBUTION.md +1 -1
- package/dist/skills/frontend/SKILL.md +34 -12
- package/dist/skills/frontend/references/design/README.md +2 -2
- package/dist/skills/frontend/references/design/_INDEX.md +2 -1
- package/dist/skills/frontend/references/design/component-catalogs.md +14 -10
- package/dist/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/dist/skills/frontend/references/design/grounding.md +29 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/dist/skills/ultimate-browsing/SKILL.md +5 -4
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/dist/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/dist/skills/ultimate-browsing/engine/summary.py +1 -1
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/dist/skills/ulw-research/AGENTS.md +8 -4
- package/dist/skills/ulw-research/SKILL.md +7 -316
- package/dist/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/dist/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/dist/skills/ulw-research/references/fact-ledger.md +42 -8
- package/dist/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/dist/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/dist/skills/ulw-research/references/report-gates.md +12 -5
- package/dist/skills/ulw-research/references/research-collection.md +195 -0
- package/dist/skills/ulw-research/references/research-delivery.md +123 -0
- package/dist/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/dist/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/dist/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/dist/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/dist/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -110
- package/dist/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/dist/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/dist/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
- package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
- package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/dist/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/dist/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/dist/skills/ulw-research/scripts/report-tools.test.ts +5 -800
- package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/dist/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/dist/skills/ulw-research/scripts/units.mjs +14 -3
- package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/dist/tools/delegate-task/executor-types.d.ts +1 -0
- package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
- package/dist/tools/delegate-task/types.d.ts +1 -0
- package/dist/tools/skill/description-formatter.d.ts +2 -1
- package/dist/tools/skill/types.d.ts +6 -0
- package/dist/tui.js +131 -33
- package/package.json +18 -15
- package/packages/git-bash-mcp/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
- package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
- package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
- package/packages/shared-skills/skill-source-filter.mjs +6 -2
- package/packages/shared-skills/skills/ast-grep/README.md +1 -1
- package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
- package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
- package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
- package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
- package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
|
@@ -1,238 +1,12 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test"
|
|
2
|
-
|
|
3
|
-
import { derive
|
|
2
|
+
import { display, recompute } from "./fact-derive.mjs"
|
|
3
|
+
import { derive } from "./tests/derive-clock"
|
|
4
4
|
import { parseExpr } from "./fact-expr.mjs"
|
|
5
5
|
import { addRow, emptyLedger, OPERATIONS } from "./fact-ledger.mjs"
|
|
6
6
|
import { canonicalUnit, expectedUnit, isAffine, OPERATION_RULES, renderPrecision } from "./unit-rules.mjs"
|
|
7
|
+
import { Row, Ledger, Spec, HASH, measured, ledger, PCT_SUM, VALID, PRECISION, RELABELS, Mutation, generic, repeatFirst, operands, MALFORMED, REPEATED, rowOf, relabel, OPS } from "./tests/fact-unit-rules-support"
|
|
7
8
|
|
|
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
|
-
type Ledger = { schemaVersion: number; rows: Row[]; events: unknown[] }
|
|
13
|
-
type Spec = Record<string, unknown>
|
|
14
|
-
|
|
15
|
-
const HASH = "a".repeat(64)
|
|
16
|
-
|
|
17
|
-
function measured(factId: string, value: string, unit: string | null, extra: Row = {}): Row {
|
|
18
|
-
return {
|
|
19
|
-
fact_id: factId,
|
|
20
|
-
kind: "measured",
|
|
21
|
-
value,
|
|
22
|
-
unit,
|
|
23
|
-
raw: `${value} ${unit ?? ""}`.trim(),
|
|
24
|
-
quote: `The figure is ${value}.`,
|
|
25
|
-
source_id: "S1",
|
|
26
|
-
locator: { artifact: "sources/S1/text.txt", char_start: 0, char_end: 20 },
|
|
27
|
-
snapshot_sha256: HASH,
|
|
28
|
-
extracted_by: "fact add --find",
|
|
29
|
-
observed_at: "2026-10-23T08:00:00Z",
|
|
30
|
-
label: factId.toLowerCase(),
|
|
31
|
-
...extra,
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function ledger(): Ledger {
|
|
36
|
-
const built = emptyLedger() as Ledger
|
|
37
|
-
const rows = [
|
|
38
|
-
measured("F1", "1", "m"),
|
|
39
|
-
measured("F2", "3", "m"),
|
|
40
|
-
measured("F3", "20", "%"),
|
|
41
|
-
measured("F4", "15", "%"),
|
|
42
|
-
measured("F5", "5", "%p"),
|
|
43
|
-
measured("F6", "100", "case", { valid_at: "2025", entity: "acme" }),
|
|
44
|
-
measured("F7", "112", "case", { valid_at: "2026", entity: "acme" }),
|
|
45
|
-
measured("F8", "40", "person"),
|
|
46
|
-
measured("F9", "200", "person"),
|
|
47
|
-
measured("F10", "100", "USD"),
|
|
48
|
-
measured("F11", "20", "USD/person"),
|
|
49
|
-
measured("F12", "0", "m"),
|
|
50
|
-
measured("F13", "25", "C", { valid_at: "2025", entity: "x" }),
|
|
51
|
-
measured("F14", "30", "C", { valid_at: "2026", entity: "x" }),
|
|
52
|
-
measured("F15", "0", "person"),
|
|
53
|
-
measured("F16", "2.5", "kilometre"),
|
|
54
|
-
measured("F17", "120", "case", { valid_at: "2026", entity: "other" }),
|
|
55
|
-
measured("F18", "0", "case", { valid_at: "2025", entity: "acme" }),
|
|
56
|
-
measured("F19", "-5", "person"),
|
|
57
|
-
measured("F20", "2", "%p"),
|
|
58
|
-
measured("F21", "105", "case", { valid_at: "2025", entity: "acme" }),
|
|
59
|
-
measured("F22", "200", "person"),
|
|
60
|
-
]
|
|
61
|
-
for (const row of rows) addRow(built, row)
|
|
62
|
-
return built
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const PCT_SUM = { op: "sum", operands: ["F3", "F4"], unit: "%", disjoint: true, reference: "all respondents", rationale: "disjoint answer shares" }
|
|
66
|
-
|
|
67
|
-
const VALID: Record<string, Array<{ spec: Spec; unit: string | null; precision?: "places" | "sigfigs" }>> = {
|
|
68
|
-
sum: [
|
|
69
|
-
{ spec: { op: "sum", operands: ["F1", "F2"], unit: "m" }, unit: "m" },
|
|
70
|
-
{ spec: { op: "sum", operands: ["F1", "F2"], unit: "metre" }, unit: "m" },
|
|
71
|
-
{ spec: PCT_SUM, unit: "%" },
|
|
72
|
-
],
|
|
73
|
-
diff: [
|
|
74
|
-
{ spec: { op: "diff", operands: ["F2", "F1"], unit: "m" }, unit: "m" },
|
|
75
|
-
{ spec: { op: "diff", operands: ["F3", "F4"], unit: "pp" }, unit: "%p" },
|
|
76
|
-
{ spec: { op: "diff", operands: ["F3", "F5"], unit: "%" }, unit: "%" },
|
|
77
|
-
{ spec: { op: "diff", operands: ["F5", "F20"], unit: "%p" }, unit: "%p" },
|
|
78
|
-
],
|
|
79
|
-
growth: [{ spec: { op: "growth", from: "F6", to: "F7", unit: "%" }, unit: "%" }],
|
|
80
|
-
share: [
|
|
81
|
-
{ spec: { op: "share", part: "F8", whole: "F9", unit: "%" }, unit: "%" },
|
|
82
|
-
{ spec: { op: "share", part: "F22", whole: "F9", unit: "%" }, unit: "%" },
|
|
83
|
-
],
|
|
84
|
-
ratio: [
|
|
85
|
-
{ spec: { op: "ratio", num: "F10", den: "F11", unit: "person" }, unit: "person" },
|
|
86
|
-
{ spec: { op: "ratio", num: "F1", den: "F2", unit: null }, unit: null },
|
|
87
|
-
{ spec: { op: "ratio", num: "F10", den: "F9", unit: "USD/person" }, unit: "USD/person" },
|
|
88
|
-
],
|
|
89
|
-
convert: [
|
|
90
|
-
{ spec: { op: "convert", operands: ["F12"], to: "km" }, unit: "km" },
|
|
91
|
-
{ spec: { op: "convert", operands: ["F16"], to: "m" }, unit: "m" },
|
|
92
|
-
{ spec: { op: "convert", operands: ["F2"], to: "kilometre" }, unit: "km" },
|
|
93
|
-
],
|
|
94
|
-
expr: [
|
|
95
|
-
{ spec: { op: "expr", formula: "F3 - F4", unit: "%p" }, unit: "%p", precision: "places" },
|
|
96
|
-
{ spec: { op: "expr", formula: "F2 - F1", unit: "m" }, unit: "m", precision: "places" },
|
|
97
|
-
{ spec: { op: "expr", formula: "F5", unit: "%p" }, unit: "%p", precision: "places" },
|
|
98
|
-
{ spec: { op: "expr", formula: "F1 * F1 / F2", unit: "m" }, unit: "m" },
|
|
99
|
-
{ spec: { op: "expr", formula: "F10 / F11", unit: "person" }, unit: "person" },
|
|
100
|
-
{ spec: { op: "expr", formula: "pct(F8 / F9)", unit: "%" }, unit: "%" },
|
|
101
|
-
{ spec: { op: "expr", formula: "F3 * F9", unit: "person" }, unit: "person" },
|
|
102
|
-
],
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** Invariant 5 per operation: sum and diff render by decimal places, the rest by significant figures (expr cases override). */
|
|
106
|
-
const PRECISION: Record<string, "places" | "sigfigs"> = { sum: "places", diff: "places", growth: "sigfigs", share: "sigfigs", ratio: "sigfigs", convert: "sigfigs", expr: "sigfigs" }
|
|
107
|
-
|
|
108
|
-
const RELABELS = [null, "%", "%p", "pp", "bp", "m", "metre", "km", "kilometre", "cm", "C", "case", "person", "USD", "USD/person", "person/USD", "KRW-e8"]
|
|
109
|
-
|
|
110
|
-
type Mutation = { name: string; base: Spec; mutate: (row: Row, book: Ledger) => Row; reason: string }
|
|
111
|
-
const generic = (base: Spec, arity: string[], arityReason = "takes ", missingReason = "no ledger row F999"): Mutation[] => [
|
|
112
|
-
{ name: "operands null", base, mutate: (row) => ({ ...row, operands: null }), reason: "operands must be a non-empty array" },
|
|
113
|
-
{ name: "operands empty", base, mutate: (row) => ({ ...row, operands: [] }), reason: "operands must be a non-empty array" },
|
|
114
|
-
{ name: "wrong arity", base, mutate: (row) => ({ ...row, operands: arity }), reason: arityReason },
|
|
115
|
-
{ name: "missing operand id", base, mutate: (row) => ({ ...row, operands: (row.operands as string[]).map((id, index) => (index === 0 ? "F999" : id)) }), reason: missingReason },
|
|
116
|
-
{ name: "invalid rational", base, mutate: (row) => ({ ...row, exact: { num: "x", den: "1" } }), reason: "exact must be { num, den }" },
|
|
117
|
-
{ name: "no operation", base, mutate: (row) => ({ ...row, operation: "mean" }), reason: 'operation "mean" is not one of' },
|
|
118
|
-
{ name: "repeated operand", base, mutate: (row) => ({ ...row, operands: repeatFirst(row.operands as string[]) }), reason: "is repeated" },
|
|
119
|
-
{ name: "self reference", base, mutate: (row) => ({ ...row, operands: (row.operands as string[]).map((id, index) => (index === 0 ? row.fact_id : id)) }), reason: "cites itself" },
|
|
120
|
-
{ name: "kind operation", base, mutate: (row) => ({ ...row, kind: "assumed" }), reason: "kind assumed" },
|
|
121
|
-
{ name: "audit fields", base, mutate: (row) => ({ ...row, factor: "999" }), reason: "factor" },
|
|
122
|
-
{ name: "precision field", base, mutate: (row) => ({ ...row, precision: { places: -1, sigfigs: 0 } }), reason: "precision" },
|
|
123
|
-
{ name: "compatibility field", base, mutate: (row) => ({ ...row, compatibility: "invalid" }), reason: "compatibility" },
|
|
124
|
-
{ name: "metadata fields", base, mutate: (row) => ({ ...row, population: { tampered: true } }), reason: "population" },
|
|
125
|
-
{ name: "noncanonical operand", base, mutate: (row, book) => {
|
|
126
|
-
const operand = book.rows.find((r) => r.fact_id === (row.operands as string[])[0])
|
|
127
|
-
if (!operand) throw Error("fixture operand missing")
|
|
128
|
-
operand.unit = `${operand.unit}*bp/%p`
|
|
129
|
-
return row
|
|
130
|
-
}, reason: "canonical" },
|
|
131
|
-
]
|
|
132
|
-
/** The first operand id in a second slot: [F1, F2] -> [F1, F1]; a one-operand row gets [F1, F1]. */
|
|
133
|
-
const repeatFirst = (ids: string[]) => (ids.length === 1 ? [ids[0], ids[0]] : [...ids.slice(0, -1), ids[0]])
|
|
134
|
-
const operands = (ids: string[]) => (row: Row) => ({ ...row, operands: ids })
|
|
135
|
-
|
|
136
|
-
const MALFORMED: Record<string, Mutation[]> = {
|
|
137
|
-
sum: [
|
|
138
|
-
...generic(VALID.sum[0].spec, ["F1"]),
|
|
139
|
-
{ name: "no context", base: VALID.sum[0].spec, mutate: (row) => ({ ...row, context: null }), reason: "sum rows carry a context object" },
|
|
140
|
-
{ name: "% without disjoint", base: PCT_SUM, mutate: (row) => ({ ...row, context: { disjoint: false, reference: "all respondents" } }), reason: "needs disjoint shares" },
|
|
141
|
-
{ name: "% without reference", base: PCT_SUM, mutate: (row) => ({ ...row, context: { disjoint: true, reference: null } }), reason: "one shared reference" },
|
|
142
|
-
{ name: "% without rationale", base: PCT_SUM, mutate: (row) => ({ ...row, rationale: null }), reason: "needs a rationale" },
|
|
143
|
-
{ name: "unequal units", base: VALID.sum[0].spec, mutate: operands(["F1", "F8"]), reason: "unit differs" },
|
|
144
|
-
{ name: "affine units", base: VALID.sum[0].spec, mutate: operands(["F13", "F14"]), reason: "sum refuses affine" },
|
|
145
|
-
{ name: "closed context", base: VALID.sum[0].spec, mutate: (row) => ({ ...row, context: { disjoint: "true", reference: 7, extra: true } }), reason: "sum context" },
|
|
146
|
-
{ name: "share total", base: PCT_SUM, mutate: (row, book) => {
|
|
147
|
-
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" } })
|
|
148
|
-
return row
|
|
149
|
-
}, reason: "total <= 100" },
|
|
150
|
-
],
|
|
151
|
-
diff: [
|
|
152
|
-
...generic(VALID.diff[0].spec, ["F2", "F1", "F8"]),
|
|
153
|
-
{ name: "%p - % pair", base: VALID.diff[2].spec, mutate: operands(["F5", "F3"]), reason: '"%p" - "%" is not a typed pair' },
|
|
154
|
-
{ name: "unit - other unit pair", base: VALID.diff[0].spec, mutate: operands(["F1", "F8"]), reason: '"m" - "person" is not a typed pair' },
|
|
155
|
-
{ name: "affine units", base: VALID.diff[0].spec, mutate: operands(["F14", "F13"]), reason: "affine (temperature)" },
|
|
156
|
-
{ name: "stray context", base: VALID.diff[0].spec, mutate: (row) => ({ ...row, context: "x" }), reason: "diff rows carry no context" },
|
|
157
|
-
],
|
|
158
|
-
growth: [
|
|
159
|
-
...generic(VALID.growth[0].spec, ["F6"]),
|
|
160
|
-
{ name: "affine units", base: VALID.growth[0].spec, mutate: operands(["F13", "F14"]), reason: "growth refuses affine" },
|
|
161
|
-
{ name: "unequal units", base: VALID.growth[0].spec, mutate: operands(["F6", "F8"]), reason: "unit differs" },
|
|
162
|
-
{ name: "entity mismatch", base: VALID.growth[0].spec, mutate: operands(["F6", "F17"]), reason: "growth needs one declared entity" },
|
|
163
|
-
{ name: "one period", base: VALID.growth[0].spec, mutate: operands(["F6", "F21"]), reason: "two different valid_at periods" },
|
|
164
|
-
{ name: "from <= 0", base: VALID.growth[0].spec, mutate: operands(["F18", "F7"]), reason: "positive starting value in F18" },
|
|
165
|
-
{ name: "stray context", base: VALID.growth[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "growth rows carry no context" },
|
|
166
|
-
],
|
|
167
|
-
share: [
|
|
168
|
-
...generic(VALID.share[0].spec, ["F8"]),
|
|
169
|
-
{ name: "affine units", base: VALID.share[0].spec, mutate: operands(["F13", "F14"]), reason: "share refuses affine" },
|
|
170
|
-
{ name: "unequal units", base: VALID.share[0].spec, mutate: operands(["F8", "F1"]), reason: "unit differs" },
|
|
171
|
-
{ name: "whole <= 0", base: VALID.share[0].spec, mutate: operands(["F8", "F15"]), reason: "positive whole in F15" },
|
|
172
|
-
{ name: "part < 0", base: VALID.share[0].spec, mutate: operands(["F19", "F9"]), reason: "F19 is outside [0, F9]" },
|
|
173
|
-
{ name: "part above whole", base: VALID.share[0].spec, mutate: operands(["F9", "F8"]), reason: "F9 is outside [0, F8]" },
|
|
174
|
-
{ name: "stray context", base: VALID.share[0].spec, mutate: (row) => ({ ...row, context: "x" }), reason: "share rows carry no context" },
|
|
175
|
-
],
|
|
176
|
-
ratio: [
|
|
177
|
-
...generic(VALID.ratio[0].spec, ["F10"]),
|
|
178
|
-
{ name: "affine units", base: VALID.ratio[0].spec, mutate: operands(["F13", "F14"]), reason: "ratio refuses affine" },
|
|
179
|
-
{ name: "divides by zero", base: VALID.ratio[0].spec, mutate: operands(["F10", "F15"]), reason: "denominator F15 is zero" },
|
|
180
|
-
{ name: "stray context", base: VALID.ratio[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "ratio rows carry no context" },
|
|
181
|
-
],
|
|
182
|
-
convert: [
|
|
183
|
-
...generic(VALID.convert[0].spec, ["F12", "F1"]),
|
|
184
|
-
{ name: "no context", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: null }), reason: "convert rows carry a context object" },
|
|
185
|
-
{ name: "empty target", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "" } }), reason: "carries its target in context.target" },
|
|
186
|
-
{ name: "alias target", base: VALID.convert[0].spec, mutate: (row) => ({ ...relabel(row, "kilometre")[0], context: { target: "kilometre" } }), reason: 'context.target "kilometre" is not canonical' },
|
|
187
|
-
{ name: "currency target", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "USD" } }), reason: "no table conversion to USD (a currency)" },
|
|
188
|
-
{ 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' },
|
|
189
|
-
{ name: "closed context", base: VALID.convert[0].spec, mutate: (row) => ({ ...row, context: { target: "km", extra: true } }), reason: "exactly target" },
|
|
190
|
-
],
|
|
191
|
-
expr: [
|
|
192
|
-
...generic(VALID.expr[0].spec, ["F3", "F4", "F5"], "do not match operands", "do not match operands F999, F4"),
|
|
193
|
-
{ name: "formula id mismatch", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 - F99" }), reason: "do not match operands" },
|
|
194
|
-
{ name: "parse error", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 -" }), reason: "the expression ends early" },
|
|
195
|
-
{ name: "divides by zero", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 / (F4 - F4)" }), reason: "the expression divides by zero" },
|
|
196
|
-
{ name: "uninferable unit", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F3 + F4" }), reason: "adding % values" },
|
|
197
|
-
{ name: "affine sum", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, formula: "F13 + F14", operands: ["F13", "F14"] }), reason: "adding affine (temperature)" },
|
|
198
|
-
{ name: "stray context", base: VALID.expr[0].spec, mutate: (row) => ({ ...row, context: { target: "km" } }), reason: "expr rows carry no context" },
|
|
199
|
-
{ name: "undated rate", base: VALID.expr[0].spec, mutate: (row, book) => {
|
|
200
|
-
const rate = book.rows.find((r) => r.fact_id === "F3")
|
|
201
|
-
if (!rate) throw Error("fixture rate missing")
|
|
202
|
-
rate.unit = "USD/EUR"
|
|
203
|
-
return { ...row, formula: "F3 * F4" }
|
|
204
|
-
}, reason: "dated valid_at" },
|
|
205
|
-
],
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/** Review r6 HIGH: one id twice is never disjoint shares; expr repeats F1 inside its formula and stores the id set. */
|
|
209
|
-
const REPEATED: Record<string, Spec> = {
|
|
210
|
-
sum: { ...PCT_SUM, operands: ["F3", "F3"] },
|
|
211
|
-
diff: { op: "diff", operands: ["F3", "F3"], unit: "%p" },
|
|
212
|
-
growth: { op: "growth", from: "F6", to: "F6", unit: "%" },
|
|
213
|
-
share: { op: "share", part: "F9", whole: "F9", unit: "%" },
|
|
214
|
-
ratio: { op: "ratio", num: "F10", den: "F10", unit: null },
|
|
215
|
-
convert: { op: "convert", operands: ["F12", "F12"], to: "km" },
|
|
216
|
-
expr: { op: "expr", formula: "F1 * F1 / F2", unit: "m" },
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function rowOf(result: { row?: Row; error?: string; detail?: string }): Row {
|
|
220
|
-
if (!result.row) throw new Error(`expected a row, got ${result.error}: ${result.detail}`)
|
|
221
|
-
return result.row
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/** The row relabeled to `unit`; when the operation persists a context, a second variant rewrites that context too. */
|
|
225
|
-
function relabel(row: Row, unit: string | null): Row[] {
|
|
226
|
-
const shown = display(row.value, unit)
|
|
227
|
-
const render = row.operation === "convert" ? `${shown} ${String(row.render).slice(String(row.render).indexOf("("))}` : shown
|
|
228
|
-
const plain = { ...row, unit, raw: render, render }
|
|
229
|
-
const context = row.context as Row
|
|
230
|
-
if (row.operation === "convert") return [plain, { ...plain, context: { ...context, target: unit } }]
|
|
231
|
-
if (row.operation === "sum") return [plain, { ...plain, context: { ...context, reference: `relabeled ${unit}` } }]
|
|
232
|
-
return [plain]
|
|
233
|
-
}
|
|
234
9
|
|
|
235
|
-
const OPS = Object.keys(OPERATION_RULES)
|
|
236
10
|
|
|
237
11
|
test("the case tables cover exactly the registry's operations, which are the ledger schema's operations", () => {
|
|
238
12
|
expect([...OPS].sort()).toEqual([...OPERATIONS].sort())
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import { CLAIM_ATTRIBUTE, CLAIM_KINDS, claimSatisfied, unmarkedKinds, unmarkedRequires } from "./claim-kinds.mjs"
|
|
15
15
|
import { proseSentences } from "./fidelity-binding.mjs"
|
|
16
16
|
import { clip } from "./fidelity-trace.mjs"
|
|
17
|
+
import { isClaimSegment } from "./sources-citation.mjs"
|
|
17
18
|
import { proseText } from "./html-lite.mjs"
|
|
18
19
|
|
|
19
20
|
const marked = (node) => node.attrs?.[CLAIM_ATTRIBUTE] !== undefined
|
|
@@ -63,7 +64,7 @@ export function claimChecks(ctx, rows, provenanceOf, flag) {
|
|
|
63
64
|
const id = fact.attrs["data-fact"]
|
|
64
65
|
if (!nearest) {
|
|
65
66
|
const need = unmarkedRequires(rows.get(id))
|
|
66
|
-
const mark = need && `{{${CLAIM_KINDS[need].prefix}:${id}}} (${CLAIM_ATTRIBUTE}="${need}")`
|
|
67
|
+
const mark = need && `{{${CLAIM_KINDS[need].prefix}:${id}:${rows.get(id).label}}} (${CLAIM_ATTRIBUTE}="${need}")`
|
|
67
68
|
if (need) flag("claim_kind_mismatch", fact, `${id} is a ${rows.get(id).kind} row cited with no mark; an unmarked numeral reads as a fact, so mark it ${mark}`)
|
|
68
69
|
continue
|
|
69
70
|
}
|
|
@@ -77,8 +78,8 @@ export function claimChecks(ctx, rows, provenanceOf, flag) {
|
|
|
77
78
|
flag(entry.defect, fact, `${row.fact_id} is marked ${name}, but it is a ${row.kind} row${source}`)
|
|
78
79
|
}
|
|
79
80
|
for (const block of proseSentences(ctx)) {
|
|
80
|
-
if (block.kind === "
|
|
81
|
-
for (const sentence of block.sentences) {
|
|
81
|
+
if (block.kind === "toc") continue
|
|
82
|
+
for (const sentence of block.kind === "sources" ? block.sentences.filter((s) => isClaimSegment(s.text)) : block.sentences) {
|
|
82
83
|
for (const name of unmarkedKinds(sentence.text)) {
|
|
83
84
|
const covered = sentence.facts.length > 0 ? sentence.facts.every((fact) => nearestKind(fact.node) === name) : nearestKind(block.owner) === name
|
|
84
85
|
if (covered) continue
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Read fact export CSV records, including quoted commas, escaped quotes and newlines.
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
3
|
+
|
|
4
|
+
export function readCsv(path) {
|
|
5
|
+
if (!existsSync(path)) return null
|
|
6
|
+
const text = readFileSync(path, "utf8")
|
|
7
|
+
const records = []
|
|
8
|
+
let cells = []
|
|
9
|
+
let cell = ""
|
|
10
|
+
let quoted = false
|
|
11
|
+
for (let i = 0; i <= text.length; i++) {
|
|
12
|
+
const char = text[i]
|
|
13
|
+
if (char === '"') {
|
|
14
|
+
if (quoted && text[i + 1] === '"') {
|
|
15
|
+
cell += '"'
|
|
16
|
+
i++
|
|
17
|
+
} else quoted = !quoted
|
|
18
|
+
} else if (!quoted && (char === "," || char === "\n" || char === undefined)) {
|
|
19
|
+
cells.push(cell.trim())
|
|
20
|
+
cell = ""
|
|
21
|
+
if (char !== ",") {
|
|
22
|
+
if (cells.some((value) => value !== "")) records.push(cells)
|
|
23
|
+
cells = []
|
|
24
|
+
}
|
|
25
|
+
} else if (char !== undefined) cell += char
|
|
26
|
+
}
|
|
27
|
+
if (quoted) return null
|
|
28
|
+
const [head = [], ...rows] = records
|
|
29
|
+
const [id, value, unit] = ["fact_id", "plot_value", "unit"].map((name) => head.indexOf(name))
|
|
30
|
+
if (id < 0 || value < 0 || unit < 0 || rows.length === 0) return null
|
|
31
|
+
return rows.map((c) => ({ fact_id: c[id], plot_value: c[value], unit: c[unit] ?? "" }))
|
|
32
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// causality_added, qualifier_dropped (six-token window around the fact span; a :q rendering puts
|
|
5
5
|
// the qualifier inside the span), scope_widened_warn, and the acronym-aware name_outside_quote.
|
|
6
6
|
// The hedge-position heuristic never yields a code; it only sets force_strong for the meaning
|
|
7
|
-
// verifier
|
|
7
|
+
// verifier; name_outside_quote and scope_widened_warn also emit minor defects. Latin terms match whole words (terms
|
|
8
8
|
// of four or more letters also match their inflections); Korean terms match as substrings, single
|
|
9
9
|
// syllables as tokens. No model, no IO. Plain Node ESM; Korean strings are \u escapes.
|
|
10
10
|
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Check displayed conversion originals against their operands, not the mutable render field.
|
|
2
|
+
import { sameValue, unitKey } from "./fidelity-binding.mjs"
|
|
3
|
+
import { proseText } from "./html-lite.mjs"
|
|
4
|
+
import { parseNumeral } from "./numerals.mjs"
|
|
5
|
+
import { normalizeText } from "./text-normalize.mjs"
|
|
6
|
+
import { display } from "./unit-precision.mjs"
|
|
7
|
+
import { dimensionOf } from "./units.mjs"
|
|
8
|
+
|
|
9
|
+
const DERIVED = new Set(["converted", "derived"])
|
|
10
|
+
/**
|
|
11
|
+
* The one bracket grammar of the skill. After NFKC (fullwidth parentheses and square brackets fold
|
|
12
|
+
* to ASCII), an original is a () [] 【】 「」 or 〔〕 group. Inside a derived or converted element every
|
|
13
|
+
* group is an original, never prose; a dash separator is not an original.
|
|
14
|
+
*/
|
|
15
|
+
const PAIRS = [["(", ")"], ["[", "]"], ["\u3010", "\u3011"], ["\u300C", "\u300D"], ["\u3014", "\u3015"]]
|
|
16
|
+
const [OPEN, CLOSE] = [PAIRS.map((pair) => pair[0]).join(""), PAIRS.map((pair) => pair[1]).join("")]
|
|
17
|
+
const inClass = (chars) => chars.replace(/[\\\]\[^-]/g, "\\$&")
|
|
18
|
+
const literal = (chars) => chars.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
19
|
+
const ANY = inClass(OPEN + CLOSE)
|
|
20
|
+
const GROUP = new RegExp(PAIRS.map(([open, close]) => `${literal(open)}([^${ANY}]*)${literal(close)}`).join("|"), "gu")
|
|
21
|
+
const BRACKET = new RegExp(`[${ANY}]`, "u")
|
|
22
|
+
const folded = (text) => String(text).normalize("NFKC")
|
|
23
|
+
const innerOf = (match) => match.slice(1).find((part) => part !== undefined)
|
|
24
|
+
const mismatch = (message) => ["value_mismatch", message, "original"]
|
|
25
|
+
|
|
26
|
+
const halfFits = (row, half) => {
|
|
27
|
+
const expected = normalizeText(folded(display(String(row.value), row.unit ?? null)))
|
|
28
|
+
const text = normalizeText(half)
|
|
29
|
+
return text === expected || (text.endsWith(` ${expected}`) && !/\d/.test(text.slice(0, -expected.length)))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The converted half (the text outside the originals) equals display(row.value, row.unit), rebuilt from the row. */
|
|
33
|
+
export function convertedHalfFits(row, shown) {
|
|
34
|
+
if (!DERIVED.has(row.kind) || row.value === null || row.value === undefined) return false
|
|
35
|
+
return halfFits(row, folded(shown).replace(GROUP, ""))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A second number outside the value verify reads and its originals ("320,000 mm - 999 m"). */
|
|
39
|
+
function strayNumber(row, half) {
|
|
40
|
+
if (row.value === null || row.value === undefined || halfFits(row, half)) return null
|
|
41
|
+
const read = parseNumeral(half)
|
|
42
|
+
if (!read || !sameValue(read.value, row.value)) return null
|
|
43
|
+
const rest = half.slice(0, read.span[0]) + half.slice(read.span[1])
|
|
44
|
+
return /\d/.test(row.unit ? rest.split(row.unit).join("") : rest) ? mismatch(`"${half.trim()}" carries a number besides the value and its originals`) : null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `valueMode`: the element shows the bare value ({{F:x:value}}), so no original is due. */
|
|
48
|
+
export function originalProblem(row, shown, rows, valueMode = false) {
|
|
49
|
+
if (!DERIVED.has(row.kind)) return null
|
|
50
|
+
const text = folded(shown)
|
|
51
|
+
const groups = [...text.matchAll(GROUP)]
|
|
52
|
+
const half = text.replace(GROUP, "")
|
|
53
|
+
if (BRACKET.test(half)) return mismatch("original brackets are malformed or nested")
|
|
54
|
+
const operands = (row.derived_from ?? []).map((id) => rows.get(id))
|
|
55
|
+
for (const [index, match] of groups.entries()) {
|
|
56
|
+
const [inner, operand] = [innerOf(match), operands[index]]
|
|
57
|
+
const parsed = parseNumeral(inner)
|
|
58
|
+
if (!operand) return mismatch(`original "${inner}" has no operand of ${row.fact_id}`)
|
|
59
|
+
if (!parsed || !sameValue(parsed.value, operand.value)) return mismatch(`original "${inner}" differs from operand ${operand.fact_id}`)
|
|
60
|
+
if (unitKey(parsed.unitRaw ?? "") !== unitKey(operand.unit ?? "")) return ["unit_mismatch", `original "${inner}" is not in ${operand.unit}`, "original"]
|
|
61
|
+
const expected = normalizeText(folded(display(operand.value, operand.unit ?? null)))
|
|
62
|
+
if (normalizeText(inner) !== expected) return mismatch(`original "${inner}" differs from "${expected}"`)
|
|
63
|
+
}
|
|
64
|
+
if (groups.length > 0 && !/\d/.test(text.slice(0, groups[0].index))) return mismatch(`original "${innerOf(groups[0])}" precedes the value`)
|
|
65
|
+
if (row.kind === "converted" && !valueMode && /\d/.test(half) && groups.length < operands.length) return mismatch(`the original of ${row.derived_from[groups.length]} is missing after the value`)
|
|
66
|
+
return strayNumber(row, half)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Stands for a filled element or another fill-map value in the text after a fill site. */
|
|
70
|
+
const FILLED = "\uFFFC"
|
|
71
|
+
/** After a fill site the grammar also reads the brackets an element never carries as originals. */
|
|
72
|
+
const FOLLOW = [...PAIRS, ["\u300E", "\u300F"], ["\u300A", "\u300B"], ["\u3008", "\u3009"], ["\u27E8", "\u27E9"]]
|
|
73
|
+
const dimension = (unit) => dimensionOf(String(unit).replace(/-e\d+$/u, "")) ?? unitKey(unit)
|
|
74
|
+
|
|
75
|
+
/** What the text after a fill site opens: a bracket group's content, or the clause after a separator (`open`); else null. */
|
|
76
|
+
function openedGroup(text) {
|
|
77
|
+
const rest = folded(text).trimStart()
|
|
78
|
+
const pair = FOLLOW.find(([open]) => rest.startsWith(open))
|
|
79
|
+
const close = pair ? rest.indexOf(pair[1], 1) : -1
|
|
80
|
+
if (pair) return { group: rest.slice(1, close === -1 ? undefined : close).trim(), open: false }
|
|
81
|
+
return /^[-\u2013\u2014/]/u.test(rest) ? { group: rest.slice(1).split(/[,;:!?)\]]|\.(?!\d)/u)[0].trim(), open: true } : null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Whether the text right after a fill site of `row` opens another original: a bracket group or a
|
|
86
|
+
* separator clause that is exactly a numeral with a unit of the row's or an operand's dimension (a
|
|
87
|
+
* separator clause may end in a glued particle, as Korean writes "- 999 m\uC774\uB2E4").
|
|
88
|
+
* A filled element, a fill-map value (`fills`), a placeholder, a unitless number (a year, a
|
|
89
|
+
* footnote) and prose with digits are not originals; untraceable_number still reads a stray number.
|
|
90
|
+
*/
|
|
91
|
+
export const followsOriginal = (row, rows, fills = []) => (text) => {
|
|
92
|
+
if (!DERIVED.has(row?.kind)) return false
|
|
93
|
+
const after = [...fills].filter(Boolean).sort((a, b) => b.length - a.length).reduce((cur, fill) => cur.split(fill).join(FILLED), String(text))
|
|
94
|
+
const { group, open } = openedGroup(after) ?? { group: "" }
|
|
95
|
+
if (!group || group.includes(FILLED) || group.includes("{{")) return false
|
|
96
|
+
const units = [row.unit, ...(row.derived_from ?? []).map((id) => rows.get(id)?.unit)].filter(Boolean)
|
|
97
|
+
return [group, ...(open ? [group.replace(/[\uAC00-\uD7A3]+$/u, "").trim()] : [])].some((body) => {
|
|
98
|
+
const read = parseNumeral(body, 0)
|
|
99
|
+
return Boolean(read?.unitRaw) && read.span[0] === 0 && read.span[1] === body.length && units.some((unit) => dimension(unit) === dimension(read.unitRaw))
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The prose after `node` in its parent, each filled element (data-fact) read as one FILLED mark. */
|
|
104
|
+
export const textAfter = (node) => {
|
|
105
|
+
const siblings = node.parent?.children.slice(node.parent.children.indexOf(node) + 1) ?? []
|
|
106
|
+
return proseText({ children: siblings.map((child) => (child.attrs?.["data-fact"] === undefined ? child : { tag: "#text", text: FILLED })) })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const SPACE = "[\\s\\u3000]"
|
|
110
|
+
const DIGIT = "[0-9\\uFF10-\\uFF19]"
|
|
111
|
+
/** Each character with the fullwidth form NFKC folds onto it. */
|
|
112
|
+
const wide = (chars) => [...chars].map((ch) => ch + (/[!-~]/.test(ch) ? String.fromCharCode(ch.charCodeAt(0) + 0xfee0) : "")).join("")
|
|
113
|
+
const [WIDE_OPEN, WIDE_CLOSE] = [inClass(wide(OPEN)), inClass(wide(CLOSE))]
|
|
114
|
+
|
|
115
|
+
/** A pattern reading `rendered` modulo the bracket grammar: NFKC fullwidth forms, bracket style, spacing around brackets. */
|
|
116
|
+
function renderPattern(rendered) {
|
|
117
|
+
const text = folded(rendered).trim()
|
|
118
|
+
let body = ""
|
|
119
|
+
for (let at = 0; at < text.length; at += 1) {
|
|
120
|
+
const ch = text[at]
|
|
121
|
+
const beside = (OPEN + CLOSE).includes(text.slice(at).trimStart()[0]) || OPEN.includes(text[at - 1])
|
|
122
|
+
if (/\s/.test(ch)) body += beside ? "" : `${SPACE}+`
|
|
123
|
+
else if (OPEN.includes(ch)) body += `${SPACE}*([${WIDE_OPEN}])${SPACE}*`
|
|
124
|
+
else if (CLOSE.includes(ch)) body += `${SPACE}*([${WIDE_CLOSE}])`
|
|
125
|
+
else body += `[${inClass(wide(ch))}]`
|
|
126
|
+
}
|
|
127
|
+
// A digit may not run into a render's leading or trailing digit ("1,320 m" holds no "320 m"); a bracket ends the render.
|
|
128
|
+
return new RegExp(`${/^\d/.test(text) ? `(?<!${DIGIT})` : ""}${body}${/\d$/.test(text) ? `(?!${DIGIT})` : ""}`, "gu")
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const pairIndex = (ch, side) => [...side].findIndex((open) => open === folded(ch))
|
|
132
|
+
/** [start, end) of `rendered` in `text` from `from` under the bracket grammar, not followed by another original (`follows`); or null. */
|
|
133
|
+
export function findRender(text, rendered, from = 0, follows = () => false) {
|
|
134
|
+
const pattern = renderPattern(rendered)
|
|
135
|
+
pattern.lastIndex = from
|
|
136
|
+
for (let match = pattern.exec(text); match; match = pattern.exec(text)) {
|
|
137
|
+
const marks = match.slice(1)
|
|
138
|
+
const paired = marks.every((mark, i) => i % 2 === 1 || pairIndex(mark, OPEN) === pairIndex(marks[i + 1] ?? "", CLOSE))
|
|
139
|
+
const end = match.index + match[0].length
|
|
140
|
+
if (paired && !follows(text.slice(end))) return [match.index, end]
|
|
141
|
+
pattern.lastIndex = match.index + 1
|
|
142
|
+
}
|
|
143
|
+
return null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Where a stale fill-map entry's text sits: derived and converted renders are read under the bracket grammar. */
|
|
147
|
+
export const renderLocator = (rows, fillMap) => (entry, text, from) => {
|
|
148
|
+
const row = rows.get(entry.fact_id)
|
|
149
|
+
if (DERIVED.has(row?.kind)) return findRender(text, entry.rendered, from, followsOriginal(row, rows, (fillMap ?? []).map((other) => other.rendered)))
|
|
150
|
+
const hit = text.indexOf(entry.rendered, from)
|
|
151
|
+
return hit === -1 ? null : [hit, hit + entry.rendered.length]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Null when a stale derived render is still in the report; "original" when only its converted half is; "gone" otherwise. */
|
|
155
|
+
export function staleRender(row, rendered, text, follows) {
|
|
156
|
+
if (findRender(text, rendered, 0, follows) !== null) return null
|
|
157
|
+
const half = folded(rendered).replace(GROUP, "").trim()
|
|
158
|
+
return half !== "" && /\d/.test(half) && findRender(text, half) !== null ? "original" : "gone"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export const isDerivedRow = (row) => DERIVED.has(row?.kind)
|
|
@@ -137,11 +137,11 @@ function sourcesOf(row, rows, seen = new Set()) {
|
|
|
137
137
|
/** sha256 of the locked `## Fidelity` block normalized: the seven fields in FIDELITY_FIELDS order, `field: value` per line. */
|
|
138
138
|
export const briefHashOf = (parsed) => sha256Of(FIDELITY_FIELDS.map((field) => `${field}: ${parsed.fields[field]}`).join("\n"))
|
|
139
139
|
|
|
140
|
-
/** brief_changed when
|
|
140
|
+
/** brief_changed when there is no fill map (map null) or it was not written under the current brief (or predates the binding). */
|
|
141
141
|
export function briefBindingErrors(map, mapPath, parsed) {
|
|
142
|
-
if (map
|
|
143
|
-
const why = typeof map.brief_sha256 === "string" ? "was filled under a different ## Fidelity block" : "records no brief_sha256"
|
|
144
|
-
return [{ code: "brief_changed", token: null, line: null, message: `${
|
|
142
|
+
if (map?.brief_sha256 === briefHashOf(parsed)) return []
|
|
143
|
+
const why = map === null ? `no fill map at ${mapPath}` : `${mapPath} ${typeof map.brief_sha256 === "string" ? "was filled under a different ## Fidelity block" : "records no brief_sha256"}`
|
|
144
|
+
return [{ code: "brief_changed", token: null, line: null, message: `${why}; re-run fact fill under the current brief`, severity: DEFECT_CODES.brief_changed.severity, integrity: DEFECT_CODES.brief_changed.integrity, hint: DEFECT_CODES.brief_changed.hint }]
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
function metaOf(sessionDir, sourceId, cache) {
|