lazycodex-ai 5.1.44 → 5.1.46
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/README.de.md +0 -5
- package/README.es.md +0 -5
- package/README.fr.md +0 -5
- package/README.it.md +0 -5
- package/README.ja.md +0 -5
- package/README.ko.md +0 -5
- package/README.md +4 -5
- package/README.pt-br.md +0 -5
- package/README.ru.md +0 -6
- package/README.zh-cn.md +0 -5
- package/dist/cli/index.js +865 -413
- package/dist/cli/service-auth/keystore.d.ts +4 -2
- package/dist/cli-node/index.js +865 -413
- package/docs/reference/web-terminal-visual-qa.md +8 -0
- package/package.json +1 -1
- package/packages/lsp-daemon/dist/cli.js +7 -7
- package/packages/lsp-daemon/dist/client.js +7 -7
- package/packages/lsp-daemon/dist/index.js +7 -7
- package/packages/lsp-daemon/package.json +3 -3
- package/packages/lsp-tools-mcp/dist/cli.js +7 -7
- package/packages/lsp-tools-mcp/dist/mcp.js +7 -7
- package/packages/lsp-tools-mcp/dist/tools.js +4 -4
- package/packages/lsp-tools-mcp/package.json +3 -3
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +77 -26
- 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/bootstrap/src/hook.ts +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/biome.json +1 -21
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +4 -4
- 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/biome.json +1 -21
- 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 +4 -4
- package/packages/omo-codex/plugin/components/lsp/biome.json +1 -21
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +4 -4
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +4 -4
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +0 -1
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-not-installed.test.ts +1 -1
- package/packages/omo-codex/plugin/components/rules/biome.json +1 -21
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +4 -4
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/biome.json +1 -21
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +90 -1
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +91 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +4 -4
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +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 +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/biome.json +1 -21
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +7 -7
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +2 -0
- 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 +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +14 -9
- package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/browser/SKILL.md +21 -22
- package/packages/omo-codex/plugin/skills/browser/references/commands.md +2 -9
- package/packages/omo-codex/plugin/skills/browser/references/install.md +1 -2
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-doctor.mjs +2 -2
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-engine-guard.mjs +63 -487
- package/packages/omo-codex/plugin/skills/browser/scripts/browser-install.mjs +1 -1
- package/packages/omo-codex/plugin/skills/browser/scripts/omowright.mjs +1 -10
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +79 -118
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +75 -224
- package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +32 -27
- package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-accent-stripes.ts +8 -24
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/check-draft-guard.ts +40 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/collect-files.ts +53 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/findings.ts +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/lint.ts +38 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/rules.ts +69 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts +121 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/attr-lookalikes.tsx +10 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/bound-values.tsx +12 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/const-generics.tsx +3 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/generics.tsx +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/measured-stats.html +6 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/plain-copy.html +9 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/state-copy.html +11 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/attribute-edges.html +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/components.tsx +16 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/decorative-badge.vue +7 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/emoji-icons.tsx +9 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/jsx-edges.tsx +1 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.html +6 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.tsx +8 -0
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/vanity-stats.html +5 -0
- package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +10 -7
- package/packages/omo-codex/plugin/skills/programming/references/typescript/README.md +10 -7
- package/packages/omo-codex/plugin/skills/programming/references/typescript/bootstrap.md +9 -23
- package/packages/omo-codex/plugin/skills/programming/references/typescript/oxc-lint.md +130 -0
- package/packages/omo-codex/plugin/skills/programming/references/typescript/tsconfig-strict.md +6 -62
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +12 -12
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/new-project.ts +20 -81
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/.oxfmtrc.json +9 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/.oxlintrc.json +46 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/LICENSE +21 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/index.js +10 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/no-em-dash-copy.js +28 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/require-suppression-reason.js +62 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/oxc/tsconfig.json +29 -0
- package/packages/omo-codex/plugin/skills/refactor/SKILL.md +14 -14
- package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +21 -3
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +37 -12
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +77 -16
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +134 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +95 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +19 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +68 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-visualization.md +2 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/unit-rules.md +157 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +116 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claims-index.mjs +125 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/cli-support.mjs +19 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +89 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +191 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +164 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +239 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-expr.mjs +108 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +194 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +250 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-schema.mjs +221 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger.mjs +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +231 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-pairs.mjs +187 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-recompute.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-binding.mjs +130 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-brief.mjs +150 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +145 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +163 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-state.mjs +64 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +85 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +113 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +29 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-structure.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-text.mjs +1 -27
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +182 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/lexicon.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +193 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/meaning-check.mjs +196 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +226 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +8 -8
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/particles-ko.mjs +108 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +184 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +115 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-diff.mjs +31 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-project.mjs +125 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-rules.mjs +170 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/rational.mjs +139 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +21 -10
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +15 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sentence-split.mjs +77 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +176 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/text-normalize.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/text-similarity.mjs +28 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-algebra.mjs +101 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-errors.mjs +23 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-metadata.mjs +31 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-pairs.mjs +72 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-precision.mjs +44 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-rules-shapes.mjs +64 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/unit-rules.mjs +173 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +105 -0
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +71 -64
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -1
- package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +19 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +12 -8
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +169 -30
- package/packages/shared-skills/skills/ast-grep/AGENTS.md +1 -1
- package/packages/shared-skills/skills/browser/SKILL.md +21 -22
- package/packages/shared-skills/skills/browser/references/commands.md +2 -9
- package/packages/shared-skills/skills/browser/references/install.md +1 -2
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/browser/scripts/browser-doctor.mjs +2 -2
- package/packages/shared-skills/skills/browser/scripts/browser-engine-guard.mjs +63 -487
- package/packages/shared-skills/skills/browser/scripts/browser-install.mjs +1 -1
- package/packages/shared-skills/skills/browser/scripts/omowright.mjs +1 -10
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +2 -2
- package/packages/shared-skills/skills/frontend/SKILL.md +79 -118
- package/packages/shared-skills/skills/frontend/references/design/README.md +75 -224
- package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +32 -27
- package/packages/shared-skills/skills/frontend/references/perfection/README.md +2 -2
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-accent-stripes.ts +8 -24
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-draft-guard.test.ts +101 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/check-draft-guard.ts +40 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/collect-files.test.ts +50 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/collect-files.ts +53 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/findings.ts +16 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/lint.ts +38 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/rules.ts +69 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/draft-guard/text-nodes.ts +121 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/attr-lookalikes.tsx +10 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/bound-values.tsx +12 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/const-generics.tsx +3 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/generics.tsx +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/measured-stats.html +6 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/plain-copy.html +9 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/negative/state-copy.html +11 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/attribute-edges.html +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/components.tsx +16 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/decorative-badge.vue +7 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/emoji-icons.tsx +9 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/jsx-edges.tsx +1 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.html +6 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/promo-copy.tsx +8 -0
- package/packages/shared-skills/skills/frontend/scripts/perfection/fixtures/draft-guard/positive/vanity-stats.html +5 -0
- package/packages/shared-skills/skills/programming/SKILL.md +10 -7
- package/packages/shared-skills/skills/programming/references/typescript/README.md +10 -7
- package/packages/shared-skills/skills/programming/references/typescript/bootstrap.md +9 -23
- package/packages/shared-skills/skills/programming/references/typescript/oxc-lint.md +130 -0
- package/packages/shared-skills/skills/programming/references/typescript/tsconfig-strict.md +6 -62
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +12 -12
- package/packages/shared-skills/skills/programming/scripts/typescript/new-project.test.ts +162 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/new-project.ts +20 -81
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/.oxfmtrc.json +9 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/.oxlintrc.json +46 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/LICENSE +21 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/index.js +10 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/no-em-dash-copy.js +28 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/lint/oxlint-plugin/require-suppression-reason.js +62 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/oxc/tsconfig.json +29 -0
- package/packages/shared-skills/skills/refactor/SKILL.md +13 -13
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +1 -1
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +21 -3
- package/packages/shared-skills/skills/ulw-research/SKILL.md +37 -12
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +77 -16
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +134 -0
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +95 -0
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +19 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +68 -3
- package/packages/shared-skills/skills/ulw-research/references/report-visualization.md +2 -0
- package/packages/shared-skills/skills/ulw-research/references/unit-rules.md +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +193 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claims-index.mjs +125 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claims-index.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/cli-support.mjs +19 -5
- package/packages/shared-skills/skills/ulw-research/scripts/cli-support.test.ts +13 -2
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +89 -3
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +100 -12
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns.test.ts +183 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +245 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +191 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +164 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +239 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +375 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-expr.mjs +108 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +194 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.test.ts +221 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-grammar.test.ts +197 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +250 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +156 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +160 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-schema.mjs +221 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-schema.test.ts +43 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger.mjs +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger.test.ts +254 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.test.ts +118 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-pairs.mjs +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-pairs.test.ts +167 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-recompute.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +409 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +388 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-binding.mjs +130 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-binding.test.ts +81 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-brief.mjs +150 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-brief.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +145 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.test.ts +117 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +163 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-state.mjs +64 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-state.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +85 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.test.ts +58 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +270 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-context.test.ts +64 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +113 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.test.ts +73 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +29 -9
- package/packages/shared-skills/skills/ulw-research/scripts/gates-structure.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/gates-text.mjs +1 -27
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/lexicon.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/lexicon.test.ts +57 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +193 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.test.ts +271 -0
- package/packages/shared-skills/skills/ulw-research/scripts/meaning-check.mjs +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/meaning-check.test.ts +228 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +226 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +120 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +8 -8
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.test.ts +29 -0
- package/packages/shared-skills/skills/ulw-research/scripts/particles-ko.mjs +108 -0
- package/packages/shared-skills/skills/ulw-research/scripts/particles-ko.test.ts +86 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +184 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.test.ts +77 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +115 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.test.ts +363 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-diff.mjs +31 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-diff.test.ts +168 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-project.mjs +125 -0
- package/packages/shared-skills/skills/ulw-research/scripts/polish-rules.mjs +170 -0
- package/packages/shared-skills/skills/ulw-research/scripts/rational.mjs +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/rational.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +21 -10
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +15 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +458 -2
- package/packages/shared-skills/skills/ulw-research/scripts/sentence-split.mjs +77 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sentence-split.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +176 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +113 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/assets/share.csv +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/claim-graph.md +13 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/gen-legacy-dev.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/ledger-basic.json +223 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/ledger-legacy-dev.json +859 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/ledger-verify.json +420 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/report-bad.html +19 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/report-good.html +39 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S4/acronyms.json +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S4/meta.json +9 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S4/sentences.jsonl +7 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S4/text.txt +7 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S4.html +19 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S5/acronyms.json +1 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S5/meta.json +9 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S5/sentences.jsonl +1 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S5/text.txt +1 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity/sources/S9.txt +1 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-locked.md +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/fidelity-brief-pending.md +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-normalize.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-normalize.test.ts +73 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-similarity.mjs +28 -0
- package/packages/shared-skills/skills/ulw-research/scripts/text-similarity.test.ts +38 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-algebra.mjs +101 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-errors.mjs +23 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-metadata.mjs +31 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-pairs.mjs +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-precision.mjs +44 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-rules-shapes.mjs +64 -0
- package/packages/shared-skills/skills/ulw-research/scripts/unit-rules.mjs +173 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +105 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +83 -0
- package/packages/shared-skills/skills/visual-qa/SKILL.md +70 -63
- package/packages/shared-skills/skills/visual-qa/scripts/skill-doc-fields.test.ts +34 -0
- package/script/qa/web-terminal-visual-qa.mjs +6 -2
- package/script/qa/xterm-live-terminal.mjs +26 -3
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// gates-fidelity.mjs - the deterministic fidelity gate over a filled HTML report.
|
|
2
|
+
//
|
|
3
|
+
// checkFidelity refuses to judge a report whose brief has no locked `## Fidelity` block (one
|
|
4
|
+
// fidelity_interview_incomplete defect). Otherwise it builds the static-gate document context
|
|
5
|
+
// once and runs the value, binding, and lexicon checks over it, returning defects in the shape
|
|
6
|
+
// `check` emits plus integrity, sorted blocker, major, minor, then line, selector, code. It never
|
|
7
|
+
// calls a model or reads the network; the meaning verifier consumes its pairs separately.
|
|
8
|
+
// Plain Node ESM, sibling imports only.
|
|
9
|
+
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
11
|
+
import { join } from "node:path"
|
|
12
|
+
|
|
13
|
+
import { DEFECT_CODES } from "./contracts.mjs"
|
|
14
|
+
import { bindingChecks, proseSentences } from "./fidelity-binding.mjs"
|
|
15
|
+
import { isLocked, parseFidelityBlock } from "./fidelity-brief.mjs"
|
|
16
|
+
import { lexiconChecks } from "./fidelity-lexicon.mjs"
|
|
17
|
+
import { valueChecks } from "./fidelity-values.mjs"
|
|
18
|
+
import { buildContext } from "./gates-static.mjs"
|
|
19
|
+
import { parseHtml } from "./html-lite.mjs"
|
|
20
|
+
|
|
21
|
+
/** Every code this gate can raise. */
|
|
22
|
+
export const FIDELITY_GATE_CODES = Object.freeze([
|
|
23
|
+
"fidelity_interview_incomplete", "unresolved_placeholder", "value_mismatch", "unit_mismatch", "quote_not_verbatim",
|
|
24
|
+
"quote_unbound", "claim_status_invalid", "snapshot_hash_mismatch", "chart_value_untraceable", "untraceable_number",
|
|
25
|
+
"unsupported_verification", "conflicting_readings", "hedge_dropped", "direction_flipped", "causality_added",
|
|
26
|
+
"qualifier_dropped", "unbound_sentence", "snapshot_mismatch", "join_integrity_fail", "quote_stale_version",
|
|
27
|
+
"quote_fuzzy_match", "name_outside_quote", "scope_widened_warn", "claim_kind_mismatch", "verification_claim_unmarked",
|
|
28
|
+
])
|
|
29
|
+
const RANK = { blocker: 0, major: 1, minor: 2 }
|
|
30
|
+
|
|
31
|
+
/** The gate and delivery barrier share registry policy; caller severities cannot demote it. */
|
|
32
|
+
export function blocksDelivery(defect) {
|
|
33
|
+
if (!Object.hasOwn(DEFECT_CODES, defect?.code)) return true
|
|
34
|
+
const entry = DEFECT_CODES[defect.code]
|
|
35
|
+
return entry.integrity || entry.severity !== "minor"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function deliveryBlockReason(defect) {
|
|
39
|
+
return Object.hasOwn(DEFECT_CODES, defect?.code) ? `fidelity_unresolved: ${defect.code}` : `unknown defect code ${defect?.code}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function withIntegrity(defect) {
|
|
43
|
+
const { code, severity, selector, line, message, hint } = defect
|
|
44
|
+
return { code, severity, integrity: DEFECT_CODES[code].integrity, selector, line, message, hint }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function compareDefects(a, b) {
|
|
48
|
+
const text = (x, y) => (x < y ? -1 : x > y ? 1 : 0)
|
|
49
|
+
return RANK[a.severity] - RANK[b.severity] || (a.line ?? 0) - (b.line ?? 0) || text(a.selector ?? "", b.selector ?? "") || text(a.code, b.code)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readAcronyms(sourcesDir, sourceId, cache) {
|
|
53
|
+
if (!sourcesDir || !sourceId) return {}
|
|
54
|
+
if (!cache.has(sourceId)) {
|
|
55
|
+
const path = join(sourcesDir, sourceId, "acronyms.json")
|
|
56
|
+
cache.set(sourceId, existsSync(path) ? JSON.parse(readFileSync(path, "utf8")) : {})
|
|
57
|
+
}
|
|
58
|
+
return cache.get(sourceId)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** One (row quote, report sentence) pair per fact cited in a prose sentence outside sources and toc. */
|
|
62
|
+
export function fidelityPairs(ctx, ledger, sourcesDir) {
|
|
63
|
+
const rows = new Map((ledger?.rows ?? []).map((row) => [row.fact_id, row]))
|
|
64
|
+
const cache = new Map()
|
|
65
|
+
const pairs = []
|
|
66
|
+
for (const block of proseSentences(ctx)) {
|
|
67
|
+
if (block.kind === "sources" || block.kind === "toc") continue
|
|
68
|
+
block.sentences.forEach((sentence, index) => {
|
|
69
|
+
for (const fact of sentence.facts) {
|
|
70
|
+
const row = rows.get(fact.id)
|
|
71
|
+
if (!row?.quote) continue
|
|
72
|
+
pairs.push({
|
|
73
|
+
pair_id: `${fact.id}@${block.owner.line}:${index + 1}`,
|
|
74
|
+
fact_id: fact.id,
|
|
75
|
+
quote: row.quote,
|
|
76
|
+
sentence: sentence.text,
|
|
77
|
+
span: [fact.start - sentence.start, fact.end - sentence.start],
|
|
78
|
+
qualifier: row.kind === "quote" ? null : row.qualifier,
|
|
79
|
+
acronyms: readAcronyms(sourcesDir, row.source_id, cache),
|
|
80
|
+
node: block.owner,
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
return pairs
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function incomplete(parsed) {
|
|
89
|
+
const reasons = !parsed?.present ? "no ## Fidelity block" : [...(parsed.errors ?? []), ...parsed.missing.map((f) => `missing: ${f}`), ...parsed.pending.map((f) => `pending: ${f}`)].join("; ")
|
|
90
|
+
const entry = DEFECT_CODES.fidelity_interview_incomplete
|
|
91
|
+
return { code: "fidelity_interview_incomplete", severity: entry.severity, integrity: entry.integrity, selector: null, line: null, message: `fidelity interview incomplete (${reasons})`, hint: entry.hint }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} html the filled report
|
|
96
|
+
* @param {{ ledger: { rows: object[] }, sourcesDir?: string | null, claims?: object | null, fillMap?: object[] | null,
|
|
97
|
+
* brief: string | object, baseDir?: string, recompute?: (ledger: object, row: object) => { ok: boolean } }} options
|
|
98
|
+
* `brief` is the brief.md text or parseFidelityBlock output; `baseDir` resolves data-chart-source paths.
|
|
99
|
+
* @returns {{ defects: object[], gatesRun: string[] }}
|
|
100
|
+
*/
|
|
101
|
+
export function checkFidelity(html, { ledger, sourcesDir = null, claims = null, fillMap = null, brief, baseDir, recompute } = {}) {
|
|
102
|
+
const parsed = brief && typeof brief === "object" ? brief : parseFidelityBlock(String(brief ?? ""))
|
|
103
|
+
if (!isLocked(parsed)) return { defects: [incomplete(parsed)], gatesRun: ["fidelity_interview_incomplete"] }
|
|
104
|
+
const ctx = buildContext(parseHtml(html), { baseDir })
|
|
105
|
+
const defects = [
|
|
106
|
+
...valueChecks(ctx, ledger, fillMap, sourcesDir, { recompute, asOf: parsed.fields["as of"] }),
|
|
107
|
+
...bindingChecks(ctx, claims, ledger),
|
|
108
|
+
]
|
|
109
|
+
const pairs = fidelityPairs(ctx, ledger, sourcesDir)
|
|
110
|
+
const byId = new Map(pairs.map((pair) => [pair.pair_id, pair]))
|
|
111
|
+
for (const finding of lexiconChecks(pairs).findings) defects.push(ctx.defect(finding.code, byId.get(finding.pair_id).node, `${finding.pair_id}: ${finding.message}`))
|
|
112
|
+
return { defects: defects.map(withIntegrity).sort(compareDefects), gatesRun: [...FIDELITY_GATE_CODES] }
|
|
113
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
import { readFileSync } from "node:fs"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
|
|
5
|
+
import { indexClaims } from "./claims-index.mjs"
|
|
6
|
+
import { DEFECT_CODES, FIDELITY_CODES } from "./contracts.mjs"
|
|
7
|
+
import { checkFidelity } from "./gates-fidelity.mjs"
|
|
8
|
+
|
|
9
|
+
type Defect = { code: string; severity: string; integrity: boolean; selector: string | null; line: number | null; message: string; hint: string }
|
|
10
|
+
type Result = { defects: Defect[]; gatesRun: string[] }
|
|
11
|
+
|
|
12
|
+
const FIXTURES = join(import.meta.dir, "tests", "fixtures")
|
|
13
|
+
const FIX = join(FIXTURES, "fidelity")
|
|
14
|
+
const read = (path: string) => readFileSync(path, "utf8")
|
|
15
|
+
const OPTIONS = {
|
|
16
|
+
ledger: JSON.parse(read(join(FIX, "ledger-verify.json"))),
|
|
17
|
+
sourcesDir: join(FIX, "sources"),
|
|
18
|
+
claims: indexClaims(read(join(FIX, "claim-graph.md"))),
|
|
19
|
+
fillMap: null,
|
|
20
|
+
brief: read(join(FIXTURES, "fidelity-brief-locked.md")),
|
|
21
|
+
baseDir: FIX,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function run(html: string, extra: Record<string, unknown> = {}): Result {
|
|
25
|
+
return checkFidelity(html, { ...OPTIONS, ...extra }) as Result
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const codes = (result: Result) => result.defects.map((defect) => defect.code)
|
|
29
|
+
|
|
30
|
+
describe("checkFidelity", () => {
|
|
31
|
+
test("#given the filled good report with a locked brief #when checked #then zero defects", () => {
|
|
32
|
+
expect(run(read(join(FIX, "report-good.html"))).defects).toEqual([])
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test("#given the bad report #when checked #then the exact defect multiset, blockers first", () => {
|
|
36
|
+
const result = run(read(join(FIX, "report-bad.html")))
|
|
37
|
+
expect(codes(result)).toEqual([
|
|
38
|
+
"unit_mismatch",
|
|
39
|
+
"value_mismatch",
|
|
40
|
+
"quote_not_verbatim",
|
|
41
|
+
"unresolved_placeholder",
|
|
42
|
+
"claim_status_invalid",
|
|
43
|
+
"untraceable_number",
|
|
44
|
+
"unbound_sentence",
|
|
45
|
+
])
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test("#given any defect #when emitted #then it has the check shape with severity and integrity from the contract", () => {
|
|
49
|
+
for (const defect of run(read(join(FIX, "report-bad.html"))).defects) {
|
|
50
|
+
expect(Object.keys(defect).sort()).toEqual(["code", "hint", "integrity", "line", "message", "selector", "severity"])
|
|
51
|
+
expect(defect.severity).toBe(DEFECT_CODES[defect.code as keyof typeof DEFECT_CODES].severity)
|
|
52
|
+
expect(defect.integrity).toBe(DEFECT_CODES[defect.code as keyof typeof DEFECT_CODES].integrity)
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test("#given an unlocked brief #when checked #then only fidelity_interview_incomplete", () => {
|
|
57
|
+
const result = run(read(join(FIX, "report-bad.html")), { brief: read(join(FIXTURES, "fidelity-brief-pending.md")) })
|
|
58
|
+
expect(codes(result)).toEqual(["fidelity_interview_incomplete"])
|
|
59
|
+
expect(result.defects[0]?.integrity).toBe(true)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test("#given a row qualifier dropped in the report #when checked #then qualifier_dropped, and the :q rendering is clean", () => {
|
|
63
|
+
const dropped = '<h2>Findings</h2><p>The span is <data class="fact" data-fact="F1" data-unit="m">320 m</data> long [S4].</p>'
|
|
64
|
+
expect(codes(run(dropped))).toEqual(["qualifier_dropped"])
|
|
65
|
+
expect(run(dropped.replace(">320 m<", ">up to 320 m<")).defects).toEqual([])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test("#given the gate #when it runs #then every code it reports is a fidelity code", () => {
|
|
69
|
+
const { gatesRun } = run(read(join(FIX, "report-good.html")))
|
|
70
|
+
expect(gatesRun.length).toBeGreaterThan(0)
|
|
71
|
+
expect(gatesRun.every((code) => FIDELITY_CODES.includes(code))).toBe(true)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
@@ -18,14 +18,19 @@ import { PROSE_TAGS, proseText, selectorPath } from "./html-lite.mjs"
|
|
|
18
18
|
const CITATION_MARKER = /\[S\d+\]|\[Source\s*\d+\]|\[\uCD9C\uCC98[^\]]*\]|\[\^\d+\]/i
|
|
19
19
|
const ANCHOR_HREF = /^#(?:s|src|source|ref|fn)/i
|
|
20
20
|
const ANCHOR_TEXT = /^\[(?:\uCD9C\uCC98|Source\s*\d+|S\d+)\]$/i
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Closing ("how this report was made") heading; Korean alternates cover the same register. A
|
|
23
|
+
* heading that is exactly "Closing" (or the Korean word for it) also counts; a heading that only
|
|
24
|
+
* starts with it ("Closing the gap") does not.
|
|
25
|
+
*/
|
|
26
|
+
export const CLOSING_HEADING = /\b(?:method(?:ology)?|how)\b|\uB4B7\uBA74|\uBC29\uBC95|\uC5B4\uB5BB\uAC8C|\uB9CC\uB4E4\uC5B4|^\s*(?:closing|\uB9C8\uBB34\uB9AC)\s*$/i
|
|
23
27
|
export const SOURCES_HEADING = /references|sources|bibliography|\uCD9C\uCC98|\uCC38\uACE0\s*(?:\uBB38\uD5CC|\uC790\uB8CC)/i
|
|
24
|
-
|
|
28
|
+
/** Section kinds after sources and closing, in match order; HTML and Markdown share this table. */
|
|
29
|
+
export const OTHER_KINDS = Object.freeze([
|
|
25
30
|
["toc", /\b(?:contents|toc)\b|\uBAA9\uCC28/i],
|
|
26
31
|
["appendix", /appendix|\uBD80\uB85D/i],
|
|
27
32
|
["glossary", /glossary|\uC6A9\uC5B4/i],
|
|
28
|
-
]
|
|
33
|
+
])
|
|
29
34
|
const TEXT_SKIP = new Set(["code", "pre", "kbd", "samp", "script", "style", "svg", "template", "noscript"])
|
|
30
35
|
const HEADING_TAG = /^h[1-6]$/
|
|
31
36
|
/** The one sanctioned severity override: section-level lineage demotes unsourced_number. */
|
|
@@ -75,9 +80,25 @@ function findBody(doc) {
|
|
|
75
80
|
return doc
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Closing-heading test for both editions: CLOSING_HEADING plus the spec's optional pattern.
|
|
85
|
+
* @param {RegExp|string|null} [pattern]
|
|
86
|
+
* @returns {(text: string) => boolean}
|
|
87
|
+
*/
|
|
88
|
+
export function closingTest(pattern) {
|
|
89
|
+
const extra = pattern ? toRegExp(pattern) : null
|
|
90
|
+
return (text) => CLOSING_HEADING.test(text) || Boolean(extra?.test(text))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Section kind of an h2 heading text: sources, closing, toc, appendix, glossary, or null.
|
|
95
|
+
* @param {string} text
|
|
96
|
+
* @param {(text: string) => boolean} isClosing
|
|
97
|
+
* @returns {string|null}
|
|
98
|
+
*/
|
|
99
|
+
export function sectionKind(text, isClosing) {
|
|
79
100
|
if (SOURCES_HEADING.test(text)) return "sources"
|
|
80
|
-
if (
|
|
101
|
+
if (isClosing(text)) return "closing"
|
|
81
102
|
return OTHER_KINDS.find(([, re]) => re.test(text))?.[0] ?? null
|
|
82
103
|
}
|
|
83
104
|
|
|
@@ -108,10 +129,9 @@ function walkBody(ctx, node, state) {
|
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
|
|
111
|
-
function buildContext(doc, options) {
|
|
132
|
+
export function buildContext(doc, options) {
|
|
112
133
|
const lineageMode = options.lineageMode ?? "inline"
|
|
113
134
|
if (!LINEAGE_MODES.includes(lineageMode)) throw new TypeError(`lineageMode must be one of ${LINEAGE_MODES.join(", ")}`)
|
|
114
|
-
const closingPattern = options.closingPattern ? toRegExp(options.closingPattern) : null
|
|
115
135
|
const all = descendants(doc)
|
|
116
136
|
const styleBlocks = all.filter((node) => node.tag === "style").map((node) => ({ node, css: node.raw ?? "" }))
|
|
117
137
|
const styleAttrs = all.filter((node) => node.attrs.style).map((node) => ({ node, css: node.attrs.style }))
|
|
@@ -130,7 +150,7 @@ function buildContext(doc, options) {
|
|
|
130
150
|
requireSections: (options.requireSections ?? []).map(toRegExp),
|
|
131
151
|
baseDir: options.baseDir ?? null,
|
|
132
152
|
fs: options.fs ?? nodeFs,
|
|
133
|
-
isClosing: (
|
|
153
|
+
isClosing: closingTest(options.closingPattern),
|
|
134
154
|
util: { classTokens, closest, descendants, hasCitation, citationMarker: CITATION_MARKER },
|
|
135
155
|
kindOf: (scope) => (scope.closingH3 ? "closing" : (scope.section?.kind ?? null)),
|
|
136
156
|
defect(code, node, message) {
|
|
@@ -9,7 +9,7 @@ import { join } from "node:path"
|
|
|
9
9
|
import { proseText } from "./html-lite.mjs"
|
|
10
10
|
|
|
11
11
|
const MIN_SECTION_PROSE = 120
|
|
12
|
-
const UNCHECKED_KINDS = new Set(["closing", "sources", "toc", "appendix", "glossary"])
|
|
12
|
+
export const UNCHECKED_KINDS = new Set(["closing", "sources", "toc", "appendix", "glossary"])
|
|
13
13
|
const DEFINITION_TAGS = new Set(["p", "li", "dd", "dt", "td"])
|
|
14
14
|
const DEFINITION_LINE = /^\[(S|Source\s*)(\d+)\]/i
|
|
15
15
|
const MIN_DEFINITIONS = 3
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// Plain Node ESM, sibling imports only.
|
|
5
5
|
|
|
6
6
|
import { proseText } from "./html-lite.mjs"
|
|
7
|
+
import { CLAIMS, NOT_CLAIMS } from "./numerals.mjs"
|
|
7
8
|
|
|
8
9
|
const HANGUL = /[\uAC00-\uD7A3]/g
|
|
9
10
|
const KEEP_ALL = /word-break\s*:\s*keep-all/i
|
|
@@ -19,33 +20,6 @@ const MAX_HEADING_WORDS = 12
|
|
|
19
20
|
const LINEAGE_TOKEN = /\b(?:MEASURED|ASSUMED|DERIVED)\b/
|
|
20
21
|
const NUMBER_CONTAINERS = new Set(["figure", "table", "nav", "header", "footer"])
|
|
21
22
|
const MAX_UNSOURCED = 50
|
|
22
|
-
const MONTH = "(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\\.?"
|
|
23
|
-
/** Stripped before claim detection: dates, versions, figure refs, times, bare years. */
|
|
24
|
-
const NOT_CLAIMS = [
|
|
25
|
-
/\b\d{4}[-./]\d{1,2}(?:[-./]\d{1,2})?\b/g,
|
|
26
|
-
/\b\d{2}\.\d{2}\.\d{2}\b/g,
|
|
27
|
-
/\d{2,4}\s*\uB144\s*\d{1,2}\s*\uC6D4(?:\s*\d{1,2}\s*\uC77C)?/g,
|
|
28
|
-
/\d{1,2}\s*\uC6D4(?:\s*\d{1,2}\s*\uC77C)?/g,
|
|
29
|
-
/(?:19|20)\d{2}\s*\uB144/g,
|
|
30
|
-
new RegExp(`\\b${MONTH}\\s+\\d{1,2}(?:st|nd|rd|th)?(?:,?\\s+\\d{4})?`, "gi"),
|
|
31
|
-
new RegExp(`\\b\\d{1,2}(?:st|nd|rd|th)?\\s+${MONTH}(?:\\s+\\d{4})?`, "gi"),
|
|
32
|
-
/\bv\d+(?:\.\d+)*\b|\b\d+(?:\.\d+){2,}\b/gi,
|
|
33
|
-
/\b(?:version|ver\.?|release)\s*\d+(?:\.\d+)*/gi,
|
|
34
|
-
/\b(?:fig(?:ure)?\.?|table|chart|section|step|phase|wave|part)\s*\d+(?:\.\d+)*/gi,
|
|
35
|
-
/(?:\uADF8\uB9BC|\uB3C4\uD45C|\uD45C|\uBC84\uC804)\s*\d+(?:\.\d+)*/g,
|
|
36
|
-
/\b\d{1,2}:\d{2}\b/g,
|
|
37
|
-
/\b(?:19|20)\d{2}s?\b/g,
|
|
38
|
-
]
|
|
39
|
-
const NUM = "(?<![\\p{L}\\d.,])\\d+(?:[.,]\\d+)*"
|
|
40
|
-
const UNIT =
|
|
41
|
-
"(?:%|\\u2030|\\u00D7|\\uD37C\\uC13C\\uD2B8|\\uB2EC\\uB7EC|\\uC720\\uB85C|\\uC5D4|\\uC6D0|\\uB9CC|\\uC5B5|\\uC870|\\uCC9C|\\uCD08|\\uBD84|\\uC2DC\\uAC04|\\uC77C|\\uC8FC|\\uAC1C\\uC6D4|\\uB144|\\uBA85|\\uAC74|\\uAC1C|\\uD68C|\\uBC88|\\uBC30" +
|
|
42
|
-
"|(?:percent|pp|bps?|x|k|m|b|bn|million|billion|thousand|trillion|usd|krw|eur|ms|s|secs?|seconds?|mins?|minutes?|h|hrs?|hours?|days?|weeks?|months?|years?|kb|mb|gb|tb|users?|people|employees|engineers|tokens?|requests?|stars?|downloads?|customers?)(?![\\p{L}\\d]))"
|
|
43
|
-
const CLAIMS = [
|
|
44
|
-
new RegExp(`[$\\u20AC\\u00A3\\u00A5\\u20A9]\\s?${NUM}`, "u"),
|
|
45
|
-
new RegExp(`${NUM}\\s?${UNIT}`, "iu"),
|
|
46
|
-
/(?<![\d.,])\d{1,3}(?:,\d{3})+(?![\d,])/,
|
|
47
|
-
/(?<![\d.])\d+\.\d+(?![\d.])/,
|
|
48
|
-
]
|
|
49
23
|
|
|
50
24
|
function snippet(text, index, span = 24) {
|
|
51
25
|
return text.slice(Math.max(0, index - span), index + span).trim()
|
|
@@ -54,8 +54,8 @@ function skipSpaces(source, at) {
|
|
|
54
54
|
return at
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
/** Read `<name attrs...>` starting just after
|
|
58
|
-
function readTag(source, start) {
|
|
57
|
+
/** Read `<name attrs...>` starting just after `<`; the one attribute parser (any quoting). */
|
|
58
|
+
export function readTag(source, start) {
|
|
59
59
|
const end = source.length
|
|
60
60
|
let at = start
|
|
61
61
|
while (at < end && !isSpace(source[at]) && source[at] !== ">" && source[at] !== "/") at++
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Byte-preserving HTML boundaries for polish. No CSS or visibility inference.
|
|
2
|
+
import { readTag } from "./html-lite.mjs"
|
|
3
|
+
|
|
4
|
+
const RAW = new Set(["script", "style"])
|
|
5
|
+
const FROZEN = new Set([...RAW, "template"])
|
|
6
|
+
const VOID = new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"])
|
|
7
|
+
const isLetter = (ch) => /[a-z]/i.test(ch ?? "")
|
|
8
|
+
|
|
9
|
+
function scan(src, at, visit) {
|
|
10
|
+
while (at < src.length) {
|
|
11
|
+
const start = src.indexOf("<", at)
|
|
12
|
+
if (start === -1) return
|
|
13
|
+
const next = src[start + 1]
|
|
14
|
+
let kind
|
|
15
|
+
let end
|
|
16
|
+
let tag = null
|
|
17
|
+
if (src.startsWith("<!--", start)) {
|
|
18
|
+
// From start + 2 so the abrupt closes <!--> and <!---> end where the HTML tokenizer ends them.
|
|
19
|
+
kind = "skip"
|
|
20
|
+
const stop = src.indexOf("-->", start + 2)
|
|
21
|
+
end = stop === -1 ? src.length : stop + 3
|
|
22
|
+
} else if (next === "!" || next === "?" || (next === "/" && !isLetter(src[start + 2]))) {
|
|
23
|
+
// Declarations, <?...> and </ + non-letter (</> included) are bogus comments up to the next ">".
|
|
24
|
+
kind = "skip"
|
|
25
|
+
const stop = src.indexOf(">", start + 2)
|
|
26
|
+
end = stop === -1 ? src.length : stop + 1
|
|
27
|
+
} else if (isLetter(next) || (next === "/" && isLetter(src[start + 2]))) {
|
|
28
|
+
kind = next === "/" ? "close" : "open"
|
|
29
|
+
tag = readTag(src, start + (kind === "close" ? 2 : 1))
|
|
30
|
+
end = tag.end
|
|
31
|
+
} else {
|
|
32
|
+
at = start + 1
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
const resume = visit(kind, start, end, tag)
|
|
36
|
+
if (resume === Infinity) return
|
|
37
|
+
at = resume ?? (kind === "open" && RAW.has(tag.name) ? closeOf(src, end, tag.name) : end)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Script data with its escaped and double-escaped states: a </script> inside <!--<script>...-->
|
|
42
|
+
// does not end the script. Returns the end of the closing tag, or the end of input.
|
|
43
|
+
const SCRIPT_MARKS = { data: /<!--|<\/script(?=[\s/>])/gi, escaped: /-->|<\/?script(?=[\s/>])/gi, double: /-->|<\/script(?=[\s/>])/gi }
|
|
44
|
+
function scriptEnd(src, from) {
|
|
45
|
+
let state = "data"
|
|
46
|
+
let at = from
|
|
47
|
+
for (;;) {
|
|
48
|
+
const marks = SCRIPT_MARKS[state]
|
|
49
|
+
marks.lastIndex = at
|
|
50
|
+
const match = marks.exec(src)
|
|
51
|
+
if (!match) return src.length
|
|
52
|
+
const token = match[0].toLowerCase()
|
|
53
|
+
if (token === "-->") [state, at] = ["data", match.index + 3]
|
|
54
|
+
else if (token === "<!--") [state, at] = ["escaped", match.index + 2]
|
|
55
|
+
else if (token === "<script") [state, at] = ["double", match.index + 7]
|
|
56
|
+
else if (state === "double") [state, at] = ["escaped", match.index + 8]
|
|
57
|
+
else return readTag(src, match.index + 2).end
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function closeOf(src, from, name) {
|
|
62
|
+
if (name === "script") return scriptEnd(src, from)
|
|
63
|
+
if (RAW.has(name)) {
|
|
64
|
+
const close = new RegExp(`</${name}(?=[\\s/>])[^>]*>`, "gi")
|
|
65
|
+
close.lastIndex = from
|
|
66
|
+
const match = close.exec(src)
|
|
67
|
+
return match ? match.index + match[0].length : src.length
|
|
68
|
+
}
|
|
69
|
+
let depth = 0
|
|
70
|
+
let stop = src.length
|
|
71
|
+
scan(src, from, (kind, _start, end, tag) => {
|
|
72
|
+
if (tag?.name !== name) return undefined
|
|
73
|
+
if (kind === "open") depth++
|
|
74
|
+
else if (depth === 0) {
|
|
75
|
+
stop = end
|
|
76
|
+
return Infinity
|
|
77
|
+
} else depth--
|
|
78
|
+
return undefined
|
|
79
|
+
})
|
|
80
|
+
return stop
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const endOf = (src, end, tag) => VOID.has(tag.name) ? end : closeOf(src, end, tag.name)
|
|
84
|
+
|
|
85
|
+
/** Raw markup sequence, corresponding text slots, and markup with frozen elements omitted. */
|
|
86
|
+
export function markupParts(html) {
|
|
87
|
+
const src = String(html)
|
|
88
|
+
const markup = []
|
|
89
|
+
const text = []
|
|
90
|
+
let source = ""
|
|
91
|
+
let kept = 0
|
|
92
|
+
scan(src, 0, (kind, start, end, tag) => {
|
|
93
|
+
const frozen = kind === "open" && FROZEN.has(tag.name)
|
|
94
|
+
const stop = frozen ? endOf(src, end, tag) : end
|
|
95
|
+
text.push(src.slice(kept, start))
|
|
96
|
+
markup.push(src.slice(start, stop))
|
|
97
|
+
source += src.slice(kept, start) + (frozen || kind === "skip" ? " " : src.slice(start, stop))
|
|
98
|
+
kept = stop
|
|
99
|
+
return stop
|
|
100
|
+
})
|
|
101
|
+
text.push(src.slice(kept))
|
|
102
|
+
source += src.slice(kept)
|
|
103
|
+
return { markup, text, source }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Whole elements accepted by the caller; nested matches stay within the outer match. */
|
|
107
|
+
export function elementSpans(html, accept) {
|
|
108
|
+
const src = String(html)
|
|
109
|
+
const spans = []
|
|
110
|
+
scan(src, 0, (kind, start, end, tag) => {
|
|
111
|
+
if (kind !== "open" || !accept(tag.name, tag.attrs)) return undefined
|
|
112
|
+
const stop = endOf(src, end, tag)
|
|
113
|
+
spans.push({ start, end: stop, tag })
|
|
114
|
+
return stop
|
|
115
|
+
})
|
|
116
|
+
return spans
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function tagAttributes(html) {
|
|
120
|
+
const tags = []
|
|
121
|
+
scan(String(html), 0, (kind, _start, _end, tag) => {
|
|
122
|
+
if (kind === "open") tags.push({ name: tag.name, attrs: tag.attrs })
|
|
123
|
+
return undefined
|
|
124
|
+
})
|
|
125
|
+
return tags
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Constructs this tokenizer does not model exactly; renderer output never contains them, so polish
|
|
130
|
+
* refuses a document holding any of them instead of trusting the markup comparison.
|
|
131
|
+
*/
|
|
132
|
+
export function ambiguousMarkup(html) {
|
|
133
|
+
const src = String(html)
|
|
134
|
+
const found = new Set()
|
|
135
|
+
if (/<\/(?![a-z])/i.test(src)) found.add("</ before a non-letter")
|
|
136
|
+
if (/<!\[CDATA\[/i.test(src)) found.add("<![CDATA[")
|
|
137
|
+
if (src.includes("<?")) found.add("<?")
|
|
138
|
+
if (src.includes("--!>")) found.add("--!>")
|
|
139
|
+
scan(src, 0, (kind, start, end, tag) => {
|
|
140
|
+
if (kind !== "skip" && src.slice(start + 1, end).includes("<")) found.add("< inside a tag or attribute value")
|
|
141
|
+
if (kind === "open" && RAW.has(tag.name) && src.slice(end, closeOf(src, end, tag.name)).includes("<!--")) found.add(`<!-- inside ${tag.name}`)
|
|
142
|
+
return undefined
|
|
143
|
+
})
|
|
144
|
+
return [...found]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** One character reference token of a text node: & up to the first ; or non-name character. */
|
|
148
|
+
export const CHARACTER_REFERENCE = /&[^;\s<&]*;?/g
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The skeleton of a document: every markup token (tags, comments, bogus comments and the frozen
|
|
152
|
+
* content of script/style/template) and every character reference of a text node, in document
|
|
153
|
+
* order, each with its byte offset. Polish may change text node characters only, and an edit can
|
|
154
|
+
* carry neither <, > nor & and may not touch a character reference, so an edited span holds no
|
|
155
|
+
* skeleton token: a polished document keeps this sequence byte-identical.
|
|
156
|
+
*/
|
|
157
|
+
export function skeletonTokens(html) {
|
|
158
|
+
const { markup, text } = markupParts(html)
|
|
159
|
+
const tokens = []
|
|
160
|
+
let at = 0
|
|
161
|
+
text.forEach((slot, index) => {
|
|
162
|
+
for (const match of slot.matchAll(CHARACTER_REFERENCE)) tokens.push({ kind: "reference", value: match[0], offset: at + match.index })
|
|
163
|
+
at += slot.length
|
|
164
|
+
if (index < markup.length) {
|
|
165
|
+
tokens.push({ kind: "markup", value: markup[index], offset: at })
|
|
166
|
+
at += markup[index].length
|
|
167
|
+
}
|
|
168
|
+
})
|
|
169
|
+
return tokens
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const describeToken = (token) => (token ? `${token.kind} ${JSON.stringify(token.value)} at offset ${token.offset}` : "end of document")
|
|
173
|
+
|
|
174
|
+
/** The first skeleton token two documents disagree on, as a message, or null when they agree. */
|
|
175
|
+
export function skeletonChange(beforeHtml, afterHtml) {
|
|
176
|
+
const [before, after] = [skeletonTokens(beforeHtml), skeletonTokens(afterHtml)]
|
|
177
|
+
for (let index = 0; index < Math.max(before.length, after.length); index++) {
|
|
178
|
+
if (before[index]?.value === after[index]?.value) continue
|
|
179
|
+
return `skeleton changed at token ${index}: ${describeToken(before[index])} became ${describeToken(after[index])}`
|
|
180
|
+
}
|
|
181
|
+
return null
|
|
182
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Bilingual fidelity lexicon: data only, read by the fidelity checks and the meaning-pair router.
|
|
2
|
+
// Korean entries are \u escapes (this directory ships no Hangul); each list is frozen.
|
|
3
|
+
|
|
4
|
+
// Hedge tokens: a source hedge the report drops is hedge_dropped.
|
|
5
|
+
export const HEDGES = Object.freeze([
|
|
6
|
+
...["estimated", "about", "approximately", "may", "might", "expected", "forecast", "provisional", "not yet"],
|
|
7
|
+
...["\uCD94\uC815", "\uC57D", "\uAC00\uB2A5", "\uC804\uB9DD", "\uC608\uC0C1", "\uC7A0\uC815", "\uC544\uC9C1", "\uBBF8\uD655\uC815", "\uAC83\uC73C\uB85C \uBCF4\uC778\uB2E4"],
|
|
8
|
+
])
|
|
9
|
+
|
|
10
|
+
// Closed qualifier list for the ledger qualifier field (bounding or approximation words).
|
|
11
|
+
export const QUALIFIERS = Object.freeze([
|
|
12
|
+
...["up to", "at least", "at most", "about", "approximately", "nearly", "over", "under", "more than", "less than"],
|
|
13
|
+
...["\uCD5C\uB300", "\uCD5C\uC18C", "\uC57D", "\uC774\uC0C1", "\uC774\uD558", "\uBBF8\uB9CC", "\uCD08\uACFC", "\uB0B4\uC678", "\uAE4C\uC9C0"],
|
|
14
|
+
])
|
|
15
|
+
|
|
16
|
+
// Direction classes: a source in one class and an assertion in the other is direction_flipped.
|
|
17
|
+
export const DIRECTION = Object.freeze({
|
|
18
|
+
up: Object.freeze([...["increase", "rise", "grow", "up"], ...["\uC99D\uAC00", "\uC0C1\uC2B9", "\uB298"]]),
|
|
19
|
+
down: Object.freeze([...["decrease", "fall", "decline", "down"], ...["\uAC10\uC18C", "\uD558\uB77D", "\uC904"]]),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// Causal connectives: one in the assertion but in no supporting quote is causality_added.
|
|
23
|
+
export const CAUSAL = Object.freeze([
|
|
24
|
+
...["because", "due to", "leads to", "results in", "causes", "therefore"],
|
|
25
|
+
...["\uB54C\uBB38\uC5D0", "\uB85C \uC778\uD574", "\uB530\uB77C\uC11C", "\uADF8\uB798\uC11C", "\uCD08\uB798"],
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
// Concessive connectives for the hedge-position routing heuristic.
|
|
29
|
+
export const CONCESSIVE = Object.freeze([
|
|
30
|
+
...["although", "but", "however", "despite", "while"],
|
|
31
|
+
...["\uC73C\uB098", "\uC9C0\uB9CC", "\uC5D0\uB3C4 \uBD88\uAD6C\uD558\uACE0", "\uBC18\uBA74", "\uC640 \uB2EC\uB9AC"],
|
|
32
|
+
])
|
|
33
|
+
|
|
34
|
+
// Narrow-to-broad scope pairs [narrow, broad] for scope_widened_warn.
|
|
35
|
+
export const SCOPE_NARROW_TO_BROAD = Object.freeze([
|
|
36
|
+
Object.freeze(["\uBD81\uBBF8", "\uC804 \uC138\uACC4"]),
|
|
37
|
+
Object.freeze(["pilot", "system"]),
|
|
38
|
+
Object.freeze(["one region", "all regions"]),
|
|
39
|
+
Object.freeze(["\uC77C\uBD80", "\uC804\uCCB4"]),
|
|
40
|
+
Object.freeze(["\uD55C \uC9C0\uC5ED", "\uC804\uAD6D"]),
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
// Negation tokens; negated direction cases route to a reader instead of the lexicon.
|
|
44
|
+
export const NEGATION = Object.freeze([
|
|
45
|
+
...["not", "no", "never"],
|
|
46
|
+
...["\uC54A", "\uC5C6", "\uBABB"],
|
|
47
|
+
])
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
|
|
3
|
+
import { CAUSAL, CONCESSIVE, DIRECTION, HEDGES, NEGATION, QUALIFIERS, SCOPE_NARROW_TO_BROAD } from "./lexicon.mjs"
|
|
4
|
+
|
|
5
|
+
const LISTS = { HEDGES, QUALIFIERS, CAUSAL, CONCESSIVE, NEGATION, SCOPE_NARROW_TO_BROAD } as const
|
|
6
|
+
|
|
7
|
+
describe("lexicon", () => {
|
|
8
|
+
test("given each exported list when read then it is non-empty and frozen", () => {
|
|
9
|
+
for (const [name, list] of Object.entries(LISTS)) {
|
|
10
|
+
expect({ name, length: list.length > 0 }).toEqual({ name, length: true })
|
|
11
|
+
expect({ name, frozen: Object.isFrozen(list) }).toEqual({ name, frozen: true })
|
|
12
|
+
}
|
|
13
|
+
expect(Object.isFrozen(DIRECTION)).toBe(true)
|
|
14
|
+
expect(Object.isFrozen(DIRECTION.up)).toBe(true)
|
|
15
|
+
expect(Object.isFrozen(DIRECTION.down)).toBe(true)
|
|
16
|
+
for (const pair of SCOPE_NARROW_TO_BROAD) expect(Object.isFrozen(pair)).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test("given HEDGES when read then it carries the named English and Korean hedges", () => {
|
|
20
|
+
const english = ["estimated", "about", "approximately", "may", "might", "expected", "forecast", "provisional", "not yet"]
|
|
21
|
+
const korean = ["추정", "약", "가능", "전망", "예상", "잠정", "아직", "미확정", "것으로 보인다"]
|
|
22
|
+
expect(HEDGES).toEqual(expect.arrayContaining([...english, ...korean]))
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test("given QUALIFIERS when read then it is exactly the closed bilingual list", () => {
|
|
26
|
+
const korean = ["최대", "최소", "약", "이상", "이하", "미만", "초과", "내외", "까지"]
|
|
27
|
+
const english = ["up to", "at least", "at most", "about", "approximately", "nearly", "over", "under", "more than", "less than"]
|
|
28
|
+
expect([...QUALIFIERS].sort()).toEqual([...korean, ...english].sort())
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test("given DIRECTION when read then up and down carry both languages", () => {
|
|
32
|
+
expect(DIRECTION.up).toEqual(expect.arrayContaining(["증가", "상승", "늘", "increase", "rise", "grow", "up"]))
|
|
33
|
+
expect(DIRECTION.down).toEqual(expect.arrayContaining(["감소", "하락", "줄", "decrease", "fall", "decline", "down"]))
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("given CAUSAL, CONCESSIVE and NEGATION when read then they carry the named connectives", () => {
|
|
37
|
+
expect(CAUSAL).toEqual(
|
|
38
|
+
expect.arrayContaining(["because", "due to", "leads to", "results in", "causes", "therefore", "때문에", "로 인해", "따라서", "그래서", "초래"]),
|
|
39
|
+
)
|
|
40
|
+
expect(CONCESSIVE).toEqual(
|
|
41
|
+
expect.arrayContaining(["although", "but", "however", "despite", "while", "으나", "지만", "에도 불구하고", "반면", "와 달리"]),
|
|
42
|
+
)
|
|
43
|
+
expect(NEGATION).toEqual(expect.arrayContaining(["not", "no", "never", "않", "없", "못"]))
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test("given SCOPE_NARROW_TO_BROAD when read then it carries the named narrow-to-broad pairs", () => {
|
|
47
|
+
expect(SCOPE_NARROW_TO_BROAD).toEqual(
|
|
48
|
+
expect.arrayContaining([
|
|
49
|
+
["북미", "전 세계"],
|
|
50
|
+
["pilot", "system"],
|
|
51
|
+
["one region", "all regions"],
|
|
52
|
+
["일부", "전체"],
|
|
53
|
+
["한 지역", "전국"],
|
|
54
|
+
]),
|
|
55
|
+
)
|
|
56
|
+
})
|
|
57
|
+
})
|