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,193 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test"
|
|
2
|
+
import { spawnSync } from "node:child_process"
|
|
3
|
+
import { readFileSync } from "node:fs"
|
|
4
|
+
import { join } from "node:path"
|
|
5
|
+
|
|
6
|
+
import { CLAIM_ATTRIBUTE, CLAIM_KINDS, CLAIM_TABLE_BEGIN, CLAIM_TABLE_END, renderClaimKindTable, unmarkedKinds } from "./claim-kinds.mjs"
|
|
7
|
+
import { DEFECT_CODES } from "./contracts.mjs"
|
|
8
|
+
import { valueChecks } from "./fidelity-values.mjs"
|
|
9
|
+
import { buildContext } from "./gates-static.mjs"
|
|
10
|
+
import { parseHtml } from "./html-lite.mjs"
|
|
11
|
+
|
|
12
|
+
// Protects the claim-kind contract the writer (fill) and the gate share: a fact marked with a
|
|
13
|
+
// claim kind must cite a row that kind accepts, a mark binds only the facts it owns, and the doc
|
|
14
|
+
// table writers read is rendered from CLAIM_KINDS. Expectations come from ORACLE below, written by
|
|
15
|
+
// hand from the design, never from the table under test.
|
|
16
|
+
|
|
17
|
+
type Defect = { code: string; severity: string }
|
|
18
|
+
type Row = Record<string, unknown> & { fact_id: string; kind: string; source_id: string | null; raw?: string; quote?: string }
|
|
19
|
+
|
|
20
|
+
const FIX = join(import.meta.dir, "tests", "fixtures", "fidelity")
|
|
21
|
+
const BASE: { rows: Row[] } = JSON.parse(readFileSync(join(FIX, "ledger-verify.json"), "utf8"))
|
|
22
|
+
const byId = (id: string) => BASE.rows.find((row) => row.fact_id === id) as Row
|
|
23
|
+
const [F1, F7, F8, Q1] = ["F1", "F7", "F8", "Q1"].map(byId) as [Row, Row, Row, Row]
|
|
24
|
+
const plain = { render: null, operation: null, operands: [], derived_from: [], formula: null, factor: null }
|
|
25
|
+
const F9: Row = { ...F8, ...plain, fact_id: "F9", kind: "assumed", label: "growth_rate", raw: "15%", value: "15", unit: "%", exact: { num: "15", den: "1" }, rationale: "planning assumption" }
|
|
26
|
+
const F10: Row = { ...F8, ...plain, fact_id: "F10", kind: "derived", label: "share_sum", raw: "39%", value: "39", unit: "%", exact: { num: "39", den: "1" }, operation: "sum", operands: ["F5", "F6"] }
|
|
27
|
+
const F11: Row = { ...F7, fact_id: "F11", locator: null }
|
|
28
|
+
const F12: Row = { ...F7, fact_id: "F12", locator: { artifact: "missing.txt", char_start: 0, char_end: 9 } }
|
|
29
|
+
const F13: Row = { ...F7, fact_id: "F13", locator: { artifact: "../S4/text.txt", char_start: 0, char_end: 9 } }
|
|
30
|
+
const LEDGER = { ...BASE, rows: [...BASE.rows, F9, F10, F11, F12, F13] }
|
|
31
|
+
const SUBJECTS = [F1, F7, F8, F9, F10, F11, F12, F13, Q1]
|
|
32
|
+
|
|
33
|
+
/** Hand-written oracle: the ledger row kinds each claim kind accepts, and whether the cited row must be command-backed. */
|
|
34
|
+
const ORACLE: Record<string, { rows: string[]; command: boolean }> = {
|
|
35
|
+
fact: { rows: ["measured", "converted", "derived"], command: false },
|
|
36
|
+
quote: { rows: ["quote"], command: false },
|
|
37
|
+
verified: { rows: ["measured", "quote"], command: true },
|
|
38
|
+
derived: { rows: ["derived", "converted"], command: false },
|
|
39
|
+
assumed: { rows: ["assumed"], command: false },
|
|
40
|
+
}
|
|
41
|
+
/** Rows an unmarked element refuses (an unmarked numeral reads as a fact, so an assumption needs its A mark). */
|
|
42
|
+
const UNMARKED_REFUSED = new Set(["F9"])
|
|
43
|
+
/** Rows whose own locator artifact sits in a snapshot whose meta.json kind is command (S5/text.txt). */
|
|
44
|
+
const COMMAND_BACKED = new Set(["F7"])
|
|
45
|
+
const MAJOR_FOR: Record<string, string> = { fact: "claim_kind_mismatch", quote: "claim_kind_mismatch", verified: "unsupported_verification", derived: "claim_kind_mismatch", assumed: "claim_kind_mismatch" }
|
|
46
|
+
const expected = (kind: string, row: Row) => {
|
|
47
|
+
const rule = ORACLE[kind] as { rows: string[]; command: boolean }
|
|
48
|
+
return rule.rows.includes(row.kind) && (!rule.command || COMMAND_BACKED.has(row.fact_id)) ? [] : [MAJOR_FOR[kind] as string]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const CLAIM_CODES = new Set(["claim_kind_mismatch", "unsupported_verification", "verification_claim_unmarked"])
|
|
52
|
+
const run = (body: string) => valueChecks(buildContext(parseHtml(`<h2>Findings</h2>\n${body}`), { baseDir: FIX }), LEDGER, null, join(FIX, "sources"), {}) as Defect[]
|
|
53
|
+
const claims = (body: string) => run(body).filter((d) => CLAIM_CODES.has(d.code))
|
|
54
|
+
const codes = (body: string) => claims(body).map((d) => d.code).sort()
|
|
55
|
+
|
|
56
|
+
const value = (row: Row, kind?: string) => {
|
|
57
|
+
const mark = kind ? ` ${CLAIM_ATTRIBUTE}="${kind}"` : ""
|
|
58
|
+
return row.kind === "quote" ? `<q data-fact="${row.fact_id}"${mark} data-quote-sel="full">${row.quote}</q>` : `<data class="fact"${mark} data-fact="${row.fact_id}">${row.raw}</data>`
|
|
59
|
+
}
|
|
60
|
+
const prose = (inner: string, lead = "The figure is") => `<p>${lead} ${inner} [S4].</p>`
|
|
61
|
+
const cell = (inner: string) => `<table><tr><th>Item</th><td>${inner}</td></tr></table>`
|
|
62
|
+
|
|
63
|
+
describe("every claim kind against the hand-written oracle", () => {
|
|
64
|
+
for (const kind of Object.keys(ORACLE)) {
|
|
65
|
+
for (const row of SUBJECTS) {
|
|
66
|
+
const want = expected(kind, row)
|
|
67
|
+
const label = want.length === 0 ? "no claim defect" : `${want[0]} major`
|
|
68
|
+
test(`#given ${kind} marked on ${row.fact_id} (${row.kind}) in prose and in a table cell #then ${label}`, () => {
|
|
69
|
+
for (const body of [prose(value(row, kind)), cell(value(row, kind))]) {
|
|
70
|
+
expect(codes(body)).toEqual(want)
|
|
71
|
+
for (const defect of claims(body)) expect(defect.severity).toBe("major")
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
test(`#given ${kind} marked on an enclosing element over ${row.fact_id} #then the parent's mark binds it: ${label}`, () => {
|
|
75
|
+
expect(codes(`<p><span ${CLAIM_ATTRIBUTE}="${kind}">The figure is ${value(row)}</span> [S4].</p>`)).toEqual(want)
|
|
76
|
+
})
|
|
77
|
+
test(`#given ${kind} marked on ${row.fact_id} beside an unmarked command row #then the neighbour never satisfies it: ${label}`, () => {
|
|
78
|
+
expect(codes(prose(`${value(row, kind)}, and the suite reported ${value(F7)}`))).toEqual(want)
|
|
79
|
+
})
|
|
80
|
+
for (const inner of Object.keys(ORACLE).filter((other) => other !== kind)) {
|
|
81
|
+
test(`#given ${inner} nested inside ${kind} over ${row.fact_id} #then mismatch, the parent owns nothing, and the inner kind is still checked`, () => {
|
|
82
|
+
const body = `<p><span ${CLAIM_ATTRIBUTE}="${kind}">The figure is ${value(row, inner)}</span> [S4].</p>`
|
|
83
|
+
expect(codes(body)).toEqual(["claim_kind_mismatch", MAJOR_FOR[kind] as string, ...expected(inner, row)].sort())
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const row of SUBJECTS) {
|
|
90
|
+
const refused = UNMARKED_REFUSED.has(row.fact_id) ? ["claim_kind_mismatch:major"] : []
|
|
91
|
+
const refusedLabel = refused.length ? "claim_kind_mismatch major" : "no claim code"
|
|
92
|
+
test(`#given ${row.fact_id} unmarked in a first-person run sentence #then the minor verification_claim_unmarked, plus ${refusedLabel}`, () => {
|
|
93
|
+
const found = claims(prose(value(row), "We ran the check and it reported"))
|
|
94
|
+
expect(found.map((d) => `${d.code}:${d.severity}`).sort()).toEqual([...refused, "verification_claim_unmarked:minor"].sort())
|
|
95
|
+
})
|
|
96
|
+
test(`#given ${row.fact_id} unmarked in a plain sentence in prose and in a table cell #then ${refusedLabel}`, () => {
|
|
97
|
+
for (const body of [prose(value(row)), cell(value(row))]) expect(claims(body).map((d) => `${d.code}:${d.severity}`)).toEqual(refused)
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
test("#given an unknown claim kind #then claim_kind_mismatch", () => {
|
|
102
|
+
expect(codes(prose(value(F1, "rumoured")))).toEqual(["claim_kind_mismatch"])
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test("#given every defect and warning code the table names #then contracts defines it, and warnings are never major", () => {
|
|
106
|
+
for (const entry of Object.values(CLAIM_KINDS) as { defect: string; unmarked: { code: string } | null }[]) {
|
|
107
|
+
expect(DEFECT_CODES[entry.defect]).toBeDefined()
|
|
108
|
+
if (entry.unmarked) expect(DEFECT_CODES[entry.unmarked.code].severity).toBe("minor")
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
describe("design-check regressions", () => {
|
|
114
|
+
test("#given verified wrapping a fact-marked page row (F1 shadowing) #then the parent is unsupported and the nesting is a mismatch", () => {
|
|
115
|
+
expect(codes(`<p><span ${CLAIM_ATTRIBUTE}="verified">The inspection put the span at ${value(F1, "fact")}</span> [S4].</p>`)).toEqual(["claim_kind_mismatch", "unsupported_verification"])
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test("#given one verified value and an unmarked value in the same run sentence (F2) #then the unmarked one still warns", () => {
|
|
119
|
+
expect(codes(prose(`${value(F7, "verified")}, and the span is ${value(F1)}`, "We ran the suite and it reported"))).toEqual(["verification_claim_unmarked"])
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test("#given a truthful converted and derived value marked fact (F3) #then no stricter than unmarked", () => {
|
|
123
|
+
for (const row of [F8, F9, F10]) expect(codes(prose(value(row, "fact")))).toEqual(codes(prose(value(row))))
|
|
124
|
+
expect(codes(prose(value(F8, "fact")))).toEqual([])
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test("#given the assumed row F9 unmarked or marked fact #then both refuse it, and the unmarked message names the A mark", () => {
|
|
128
|
+
expect(codes(prose(value(F9)))).toEqual(["claim_kind_mismatch"])
|
|
129
|
+
expect(codes(prose(value(F9, "fact")))).toEqual(["claim_kind_mismatch"])
|
|
130
|
+
expect(JSON.stringify(claims(prose(value(F9))))).toContain("{{A:F9}}")
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
test("#given the assumed row F9 marked {{A:F9}} (data-claim-kind=assumed) #then no claim defect", () => {
|
|
134
|
+
expect(codes(prose(value(F9, "assumed")))).toEqual([])
|
|
135
|
+
expect(codes(cell(value(F9, "assumed")))).toEqual([])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test("#given verified citing a command-sourced row with no, a missing, or an escaping locator artifact (F4) #then unsupported_verification", () => {
|
|
139
|
+
for (const row of [F11, F12, F13]) expect(codes(prose(value(row, "verified")))).toEqual(["unsupported_verification"])
|
|
140
|
+
})
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
describe("unmarked phrases", () => {
|
|
144
|
+
const fires = [
|
|
145
|
+
"We verified the span by running the measurement script.",
|
|
146
|
+
"We ran the suite twice.",
|
|
147
|
+
"We executed the export.",
|
|
148
|
+
"We verified by hand-counting the rows.",
|
|
149
|
+
"We have run the tests.",
|
|
150
|
+
"I ran the suite.",
|
|
151
|
+
"Our numbers were obtained by running the script.",
|
|
152
|
+
"우리가 실행해 확인한 길이",
|
|
153
|
+
"저희가 스크립트를 실행하여 검증한 값",
|
|
154
|
+
"저희가 테스트를 돌렸다",
|
|
155
|
+
"우리 팀이 벤치마크를 돌려 얻은 값",
|
|
156
|
+
"그래서 우리는 스크립트를 실행했다",
|
|
157
|
+
"직접 실행한 결과",
|
|
158
|
+
]
|
|
159
|
+
const quiet = [
|
|
160
|
+
"The tests showed a 12 % drop.",
|
|
161
|
+
"The bridge, which ran across the river, spans 320 m.",
|
|
162
|
+
"The span, as confirmed with the annual inspection report, is 320 m.",
|
|
163
|
+
"Clinical tests confirmed the diagnosis.",
|
|
164
|
+
"The authors obtained estimates by running simulations.",
|
|
165
|
+
"We ran out of time.",
|
|
166
|
+
"확인된 길이는 최대 320 m",
|
|
167
|
+
"개발자가 직접 실행한 결과를 보고했다",
|
|
168
|
+
"실행해 확인한 길이",
|
|
169
|
+
"우리나라에서 실행된 정책은 320개다",
|
|
170
|
+
"우리 정부가 실행한 예산",
|
|
171
|
+
"우리가 의뢰한 업체가 테스트를 돌렸다",
|
|
172
|
+
"우리는 결과를 확인했다",
|
|
173
|
+
]
|
|
174
|
+
for (const text of fires) test(`#given "${text}" #then verified`, () => expect(unmarkedKinds(text)).toEqual(["verified"]))
|
|
175
|
+
for (const text of quiet) test(`#given "${text}" #then nothing`, () => expect(unmarkedKinds(text)).toEqual([]))
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe("references/fidelity-claim-kinds.md is rendered from CLAIM_KINDS", () => {
|
|
179
|
+
const doc = readFileSync(join(import.meta.dir, "..", "references", "fidelity-claim-kinds.md"), "utf8")
|
|
180
|
+
|
|
181
|
+
test("the committed table section equals renderClaimKindTable() byte for byte", () => {
|
|
182
|
+
const [begin, end] = [doc.indexOf(CLAIM_TABLE_BEGIN), doc.indexOf(CLAIM_TABLE_END)]
|
|
183
|
+
expect(begin).toBeGreaterThanOrEqual(0)
|
|
184
|
+
expect(end).toBeGreaterThan(begin)
|
|
185
|
+
expect(doc.slice(begin + CLAIM_TABLE_BEGIN.length + 1, end)).toBe(renderClaimKindTable())
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test("node claim-kinds.mjs --render-doc prints the same table", () => {
|
|
189
|
+
const result = spawnSync("node", [join(import.meta.dir, "claim-kinds.mjs"), "--render-doc"], { encoding: "utf8" })
|
|
190
|
+
expect(result.status).toBe(0)
|
|
191
|
+
expect(result.stdout).toBe(renderClaimKindTable())
|
|
192
|
+
})
|
|
193
|
+
})
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// claims-index.mjs - deterministic index of claim-graph.md: the one Markdown table whose header
|
|
2
|
+
// names claim_id, statement, risk tier, and status, plus the ids listed under the
|
|
3
|
+
// `## verified-claims` digest. Pure function of the text; node: builtins only.
|
|
4
|
+
|
|
5
|
+
const CLAIM_ID = /^C\d+$/
|
|
6
|
+
const REQUIRED_COLUMNS = Object.freeze({ claim_id: "claim_id", statement: "statement", risk: "risk tier", status: "status" })
|
|
7
|
+
|
|
8
|
+
/** Split one table line on unescaped pipes; drops the leading and trailing border cells. */
|
|
9
|
+
function splitRow(line) {
|
|
10
|
+
const cells = []
|
|
11
|
+
let current = ""
|
|
12
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
13
|
+
const char = line[index]
|
|
14
|
+
if (char === "\\" && line[index + 1] === "|") {
|
|
15
|
+
current += "|"
|
|
16
|
+
index += 1
|
|
17
|
+
} else if (char === "|") {
|
|
18
|
+
cells.push(current)
|
|
19
|
+
current = ""
|
|
20
|
+
} else current += char
|
|
21
|
+
}
|
|
22
|
+
cells.push(current)
|
|
23
|
+
const trimmed = cells.map((value) => value.trim())
|
|
24
|
+
if (line.trim().startsWith("|")) trimmed.shift()
|
|
25
|
+
if (line.trim().endsWith("|")) trimmed.pop()
|
|
26
|
+
return trimmed
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function normalizeHeader(value) {
|
|
30
|
+
return value.replace(/`/g, "").trim().toLowerCase().replace(/[\s_-]+/g, " ")
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function columnIndexes(header) {
|
|
34
|
+
const names = header.map(normalizeHeader)
|
|
35
|
+
const indexes = {}
|
|
36
|
+
for (const [key, name] of Object.entries(REQUIRED_COLUMNS)) indexes[key] = names.indexOf(normalizeHeader(name))
|
|
37
|
+
return Object.values(indexes).every((index) => index >= 0) ? indexes : null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isSeparator(line) {
|
|
41
|
+
return /^\s*\|?\s*:?-+:?\s*(\|\s*:?-+:?\s*)*\|?\s*$/.test(line)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const DIGEST_HEADING = normalizeHeader("verified-claims")
|
|
45
|
+
|
|
46
|
+
/** `offset` is the index of `lines[0]` in the document, for line numbers in errors. */
|
|
47
|
+
function verifiedIds(lines, offset, errors) {
|
|
48
|
+
const ids = []
|
|
49
|
+
let inside = false
|
|
50
|
+
for (const [index, line] of lines.entries()) {
|
|
51
|
+
const heading = /^(#{1,6})\s+(.*)$/.exec(line)
|
|
52
|
+
if (heading) {
|
|
53
|
+
const name = normalizeHeader(heading[2])
|
|
54
|
+
inside = name === DIGEST_HEADING
|
|
55
|
+
if (!inside && name.startsWith(DIGEST_HEADING)) {
|
|
56
|
+
errors.push(`line ${offset + index + 1}: heading "${line.trim()}" is not the digest heading "## verified-claims"; drop the suffix so its entries are read`)
|
|
57
|
+
}
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
if (!inside) continue
|
|
61
|
+
// An entry is a list item or a table row; prose lines never verify. Only the id an entry
|
|
62
|
+
// starts with is verified; ids mentioned later in the line are not.
|
|
63
|
+
const leading = /^\s*(?:(?:[-*+]|\d+[.)])\s+|\|\s*)`?(C\d+)\b/.exec(line)
|
|
64
|
+
if (leading && !ids.includes(leading[1])) ids.push(leading[1])
|
|
65
|
+
}
|
|
66
|
+
return ids
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Blank every line of a fenced code block (``` or ~~~, fences included) so nothing in it is read. */
|
|
70
|
+
function unfenced(lines) {
|
|
71
|
+
let fence = null
|
|
72
|
+
return lines.map((line) => {
|
|
73
|
+
const marker = /^\s{0,3}(`{3,}|~{3,})/.exec(line)
|
|
74
|
+
if (fence === null) {
|
|
75
|
+
if (marker) fence = marker[1]
|
|
76
|
+
return marker ? "" : line
|
|
77
|
+
}
|
|
78
|
+
const closes = marker && marker[1][0] === fence[0] && marker[1].length >= fence.length && line.trim() === marker[1]
|
|
79
|
+
if (closes) fence = null
|
|
80
|
+
return ""
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @returns {{ claims: { claim_id: string, statement: string, risk: string, status: string, in_verified: boolean }[], errors: string[] }} */
|
|
85
|
+
export function indexClaims(markdown) {
|
|
86
|
+
const lines = unfenced(markdown.split(/\r?\n/))
|
|
87
|
+
const errors = []
|
|
88
|
+
const headerAt = lines.findIndex((line) => line.trim().startsWith("|") && columnIndexes(splitRow(line)) !== null)
|
|
89
|
+
if (headerAt < 0) {
|
|
90
|
+
return { claims: [], errors: ["no claim table: a Markdown table with claim_id, statement, risk tier, and status columns is required"] }
|
|
91
|
+
}
|
|
92
|
+
const header = splitRow(lines[headerAt])
|
|
93
|
+
const columns = columnIndexes(header)
|
|
94
|
+
const hasSeparator = isSeparator(lines[headerAt + 1] ?? "")
|
|
95
|
+
if (!hasSeparator) errors.push(`line ${headerAt + 2}: claim table header must be followed by a separator row`)
|
|
96
|
+
const firstRow = headerAt + (hasSeparator ? 2 : 1)
|
|
97
|
+
const rows = []
|
|
98
|
+
let tableEnd = firstRow
|
|
99
|
+
for (let index = firstRow; index < lines.length && lines[index].trim().startsWith("|"); index += 1) {
|
|
100
|
+
tableEnd = index + 1
|
|
101
|
+
const cells = splitRow(lines[index])
|
|
102
|
+
const at = `line ${index + 1}`
|
|
103
|
+
if (cells.length !== header.length) {
|
|
104
|
+
errors.push(`${at}: expected ${header.length} cells, found ${cells.length}`)
|
|
105
|
+
continue
|
|
106
|
+
}
|
|
107
|
+
const claimId = cells[columns.claim_id].replace(/`/g, "")
|
|
108
|
+
if (!CLAIM_ID.test(claimId)) {
|
|
109
|
+
errors.push(`${at}: claim_id "${claimId}" must match C<n>`)
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
if (rows.some((row) => row.claim_id === claimId)) {
|
|
113
|
+
errors.push(`${at}: duplicate claim_id ${claimId}`)
|
|
114
|
+
continue
|
|
115
|
+
}
|
|
116
|
+
rows.push({ claim_id: claimId, statement: cells[columns.statement], risk: cells[columns.risk], status: cells[columns.status] })
|
|
117
|
+
}
|
|
118
|
+
// The digest section ends at the claim table: scan each side on its own so it cannot carry across.
|
|
119
|
+
const verified = [...new Set([...verifiedIds(lines.slice(0, headerAt), 0, errors), ...verifiedIds(lines.slice(tableEnd), tableEnd, errors)])]
|
|
120
|
+
for (const id of verified) {
|
|
121
|
+
if (!rows.some((row) => row.claim_id === id)) errors.push(`verified-claims lists ${id}, which has no claim row`)
|
|
122
|
+
}
|
|
123
|
+
const claims = rows.map((row) => ({ ...row, in_verified: verified.includes(row.claim_id) }))
|
|
124
|
+
return { claims, errors }
|
|
125
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
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
|
+
|
|
7
|
+
const FIXTURE = join(import.meta.dir, "tests", "fixtures", "fidelity", "claim-graph.md")
|
|
8
|
+
|
|
9
|
+
describe("indexClaims", () => {
|
|
10
|
+
test("indexes the fixture claim graph", () => {
|
|
11
|
+
const { claims, errors } = indexClaims(readFileSync(FIXTURE, "utf8"))
|
|
12
|
+
expect(errors).toEqual([])
|
|
13
|
+
expect(claims.map((claim: { claim_id: string; in_verified: boolean }) => claim.claim_id)).toEqual(["C1", "C2", "C3"])
|
|
14
|
+
expect(claims.filter((claim: { claim_id: string; in_verified: boolean }) => claim.in_verified).map((claim: { claim_id: string; in_verified: boolean }) => claim.claim_id)).toEqual(["C1"])
|
|
15
|
+
expect(claims[0]).toEqual({
|
|
16
|
+
claim_id: "C1",
|
|
17
|
+
statement: "The bridge span is up to 320 m.",
|
|
18
|
+
risk: "high",
|
|
19
|
+
status: "supported",
|
|
20
|
+
in_verified: true,
|
|
21
|
+
})
|
|
22
|
+
expect(claims[2].status).toBe("refuted")
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test("a malformed table returns errors", () => {
|
|
26
|
+
const bad = [
|
|
27
|
+
"| claim_id | statement | risk tier | status |",
|
|
28
|
+
"|---|---|---|---|",
|
|
29
|
+
"| X1 | bad id | high | supported |",
|
|
30
|
+
"| C2 | too few cells |",
|
|
31
|
+
].join("\n")
|
|
32
|
+
const { errors } = indexClaims(bad)
|
|
33
|
+
expect(errors.length).toBeGreaterThanOrEqual(2)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("fenced code blocks are skipped: a fenced heading does not end the digest and a fenced entry does not verify", () => {
|
|
37
|
+
const text = [
|
|
38
|
+
"| claim_id | statement | risk tier | status |",
|
|
39
|
+
"|---|---|---|---|",
|
|
40
|
+
"| C1 | one | high | supported |",
|
|
41
|
+
"| C2 | two | low | supported |",
|
|
42
|
+
"",
|
|
43
|
+
"## verified-claims",
|
|
44
|
+
"```",
|
|
45
|
+
"# not a heading",
|
|
46
|
+
"- C2",
|
|
47
|
+
"```",
|
|
48
|
+
"- C1",
|
|
49
|
+
].join("\n")
|
|
50
|
+
const { claims, errors } = indexClaims(text)
|
|
51
|
+
expect(errors).toEqual([])
|
|
52
|
+
expect(claims.map((claim: { in_verified: boolean }) => claim.in_verified)).toEqual([true, false])
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test("a document without the claim table returns an error", () => {
|
|
56
|
+
const { claims, errors } = indexClaims("# claim graph\n\nno table here\n")
|
|
57
|
+
expect(claims).toEqual([])
|
|
58
|
+
expect(errors.length).toBe(1)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test("a verified id with no claim row is an error", () => {
|
|
62
|
+
const text = "## verified-claims\n\n- C9\n\n| claim_id | statement | risk tier | status |\n|---|---|---|---|\n| C1 | a | high | supported |\n"
|
|
63
|
+
expect(indexClaims(text).errors.some((e: string) => e.includes("C9"))).toBe(true)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test("only the leading claim id of a verified entry is verified", () => {
|
|
67
|
+
const text = [
|
|
68
|
+
"## verified-claims",
|
|
69
|
+
"",
|
|
70
|
+
"- C1 (merged from C2)",
|
|
71
|
+
"",
|
|
72
|
+
"| claim_id | statement | risk tier | status |",
|
|
73
|
+
"|---|---|---|---|",
|
|
74
|
+
"| C1 | a, see C2 | high | supported |",
|
|
75
|
+
"| C2 | b | high | unresolved |",
|
|
76
|
+
].join("\n")
|
|
77
|
+
const { claims, errors } = indexClaims(text)
|
|
78
|
+
expect(errors).toEqual([])
|
|
79
|
+
expect(claims.map((claim: { claim_id: string; in_verified: boolean }) => [claim.claim_id, claim.in_verified])).toEqual([
|
|
80
|
+
["C1", true],
|
|
81
|
+
["C2", false],
|
|
82
|
+
])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test("a verified-claims line verifies only as a list item or a table row, never as prose", () => {
|
|
86
|
+
const text = [
|
|
87
|
+
"## verified-claims",
|
|
88
|
+
"",
|
|
89
|
+
"- C1",
|
|
90
|
+
"C2 is pending review",
|
|
91
|
+
"1) C3",
|
|
92
|
+
"| C4 | merged |",
|
|
93
|
+
"",
|
|
94
|
+
"| claim_id | statement | risk tier | status |",
|
|
95
|
+
"|---|---|---|---|",
|
|
96
|
+
"| C1 | a | high | supported |",
|
|
97
|
+
"| C2 | b | high | unresolved |",
|
|
98
|
+
"| C3 | c | high | supported |",
|
|
99
|
+
"| C4 | d | high | supported |",
|
|
100
|
+
].join("\n")
|
|
101
|
+
const { claims, errors } = indexClaims(text)
|
|
102
|
+
expect(errors).toEqual([])
|
|
103
|
+
expect(claims.map((claim: { claim_id: string; in_verified: boolean }) => [claim.claim_id, claim.in_verified])).toEqual([
|
|
104
|
+
["C1", true],
|
|
105
|
+
["C2", false],
|
|
106
|
+
["C3", true],
|
|
107
|
+
["C4", true],
|
|
108
|
+
])
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test("the SKILL.md synthesis heading 'Verified claims' is recognized", () => {
|
|
112
|
+
const text = "## Verified claims\n\n- C1\n\n| claim_id | statement | risk tier | status |\n|---|---|---|---|\n| C1 | a | high | supported |\n"
|
|
113
|
+
expect(indexClaims(text).claims[0].in_verified).toBe(true)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test("a digest heading with a suffix is an error naming the heading, not a silently empty digest", () => {
|
|
117
|
+
const text = "## Verified claims (2)\n\n- C1\n\n| claim_id | statement | risk tier | status |\n|---|---|---|---|\n| C1 | a | high | supported |\n"
|
|
118
|
+
const { claims, errors } = indexClaims(text)
|
|
119
|
+
expect(claims[0].in_verified).toBe(false)
|
|
120
|
+
expect(errors.some((e: string) => e.startsWith("line 1:") && e.includes('"## Verified claims (2)"'))).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test("the verified-claims section ends at the claim table", () => {
|
|
124
|
+
const text = [
|
|
125
|
+
"## verified-claims",
|
|
126
|
+
"- C1",
|
|
127
|
+
"",
|
|
128
|
+
"| claim_id | statement | risk tier | status |",
|
|
129
|
+
"|---|---|---|---|",
|
|
130
|
+
"| C1 | a | high | supported |",
|
|
131
|
+
"| C2 | b | high | unresolved |",
|
|
132
|
+
"",
|
|
133
|
+
"C2 still pending",
|
|
134
|
+
].join("\n")
|
|
135
|
+
const { claims, errors } = indexClaims(text)
|
|
136
|
+
expect(errors).toEqual([])
|
|
137
|
+
expect(claims.map((claim: { claim_id: string; in_verified: boolean }) => [claim.claim_id, claim.in_verified])).toEqual([
|
|
138
|
+
["C1", true],
|
|
139
|
+
["C2", false],
|
|
140
|
+
])
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test("a GFM two-dash separator row is accepted and the first data row is read", () => {
|
|
144
|
+
const text = "| claim_id | statement | risk tier | status |\n|--|--|--|--|\n| C1 | a | high | supported |\n| C2 | b | normal | unresolved |\n"
|
|
145
|
+
const { claims, errors } = indexClaims(text)
|
|
146
|
+
expect(errors).toEqual([])
|
|
147
|
+
expect(claims.map((claim: { claim_id: string }) => claim.claim_id)).toEqual(["C1", "C2"])
|
|
148
|
+
})
|
|
149
|
+
})
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// cli-support.mjs - argument parsing, typed usage errors, exit-code mapping, and JSON file IO
|
|
2
2
|
// shared by every report-tools subcommand. node: builtins only.
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { createHash } from "node:crypto"
|
|
5
|
+
import { readFileSync, renameSync, rmSync, writeFileSync } from "node:fs"
|
|
5
6
|
import { basename, dirname, join } from "node:path"
|
|
6
7
|
|
|
7
8
|
/** A usage or input error: always exit code 2. */
|
|
@@ -87,11 +88,24 @@ export function readJsonFile(path) {
|
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
/**
|
|
91
|
-
export
|
|
91
|
+
/** The sha256 hex digest of a string or bytes: the one hash every record and receipt carries. */
|
|
92
|
+
export const sha256Of = (content) => createHash("sha256").update(content).digest("hex")
|
|
93
|
+
|
|
94
|
+
/** Write text through a sibling temp file + rename; a failed write removes the temp file. */
|
|
95
|
+
export function writeTextAtomic(path, text) {
|
|
92
96
|
const temp = join(dirname(path), `.${basename(path)}.${process.pid}.${Date.now()}.tmp`)
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
try {
|
|
98
|
+
writeFileSync(temp, text)
|
|
99
|
+
renameSync(temp, path)
|
|
100
|
+
} catch (error) {
|
|
101
|
+
rmSync(temp, { force: true })
|
|
102
|
+
throw error
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Write JSON through writeTextAtomic, so a crash never leaves a half-written file. */
|
|
107
|
+
export function writeJsonAtomic(path, value) {
|
|
108
|
+
writeTextAtomic(path, `${JSON.stringify(value, null, 2)}\n`)
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/** Print a result: JSON on stdout, one summary line on stderr. */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, expect, onTestFinished, test } from "bun:test"
|
|
2
|
-
import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
3
3
|
import { tmpdir } from "node:os"
|
|
4
4
|
import { join } from "node:path"
|
|
5
5
|
import { pathToFileURL } from "node:url"
|
|
6
6
|
|
|
7
|
-
import { CliError, exitCodeFor, parseArgs, readJsonFile, writeJsonAtomic } from "./cli-support.mjs"
|
|
7
|
+
import { CliError, exitCodeFor, parseArgs, readJsonFile, writeJsonAtomic, writeTextAtomic } from "./cli-support.mjs"
|
|
8
8
|
import { isCliEntry } from "./entry-guard.mjs"
|
|
9
9
|
|
|
10
10
|
function tempDir() {
|
|
@@ -65,6 +65,17 @@ describe("JSON files", () => {
|
|
|
65
65
|
expect(leftovers).toEqual([])
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
+
test("#given a target the rename cannot replace #when written atomically #then the write throws and no temp file is left", () => {
|
|
69
|
+
// given: a non-empty directory where the file should go
|
|
70
|
+
const dir = tempDir()
|
|
71
|
+
const target = join(dir, "calibration.jsonl")
|
|
72
|
+
mkdirSync(target)
|
|
73
|
+
writeFileSync(join(target, "keep"), "x")
|
|
74
|
+
// when / then
|
|
75
|
+
expect(() => writeTextAtomic(target, "line\n")).toThrow()
|
|
76
|
+
expect(readdirSync(dir)).toEqual(["calibration.jsonl"])
|
|
77
|
+
})
|
|
78
|
+
|
|
68
79
|
test("#given a missing or malformed file #when read #then a CliError names the path", () => {
|
|
69
80
|
const dir = tempDir()
|
|
70
81
|
expect(() => readJsonFile(join(dir, "missing.json"))).toThrow(CliError)
|