oh-my-opencode 5.1.48 → 5.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/refusal-rule.d.ts +7 -0
- package/dist/cli/index.js +1194 -752
- package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
- package/dist/cli/service-auth/commands.d.ts +2 -4
- package/dist/cli/service-auth/index.d.ts +1 -1
- package/dist/cli/service-auth/keystore.d.ts +26 -2
- package/dist/cli/service-auth/protocol.d.ts +7 -1
- package/dist/cli/service-auth/session.d.ts +6 -0
- package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
- package/dist/cli-node/index.js +1194 -752
- package/dist/config/schema/hooks.d.ts +1 -0
- package/dist/create-hooks.d.ts +1 -0
- package/dist/features/boulder-state/storage.d.ts +1 -1
- package/dist/features/boulder-state/types.d.ts +1 -1
- package/dist/hooks/atlas/idle-continuation.d.ts +2 -1
- package/dist/hooks/atlas/types.d.ts +9 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/hook.d.ts +19 -0
- package/dist/hooks/momus-review-persistence/index.d.ts +1 -0
- package/dist/hooks/momus-review-persistence/review-resolution.d.ts +20 -0
- package/dist/hooks/prometheus-md-only/constants.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/fixtures/denial-log.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/guarded-hashline.d.ts +1 -0
- package/dist/hooks/prometheus-md-only/fixtures/invoke-before.d.ts +7 -0
- package/dist/hooks/prometheus-md-only/fixtures/opencode-patch-parser.d.ts +2 -0
- package/dist/hooks/prometheus-md-only/hook.d.ts +5 -1
- package/dist/hooks/prometheus-md-only/path-policy.d.ts +2 -9
- package/dist/hooks/prometheus-md-only/vendor/opencode-patch-parser.d.ts +22 -0
- package/dist/index.js +2322 -1045
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -0
- package/dist/plugin/hooks/create-tool-guard-hooks.d.ts +2 -1
- package/dist/shared/posthog-activity-state.d.ts +1 -0
- package/dist/shared/posthog.d.ts +1 -2
- package/dist/shared/resolve-file-write-path.d.ts +6 -0
- package/dist/skills/ast-grep/README.md +1 -1
- package/dist/skills/ast-grep/install.ps1 +5 -3
- package/dist/skills/ast-grep/install.sh +4 -5
- package/dist/skills/ast-grep/references/install.md +2 -2
- package/dist/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/dist/skills/coding-agent-sessions/SKILL.md +11 -11
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/dist/skills/coding-agent-sessions/references/codex.md +4 -4
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/dist/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/dist/skills/frontend/ATTRIBUTION.md +1 -1
- package/dist/skills/frontend/SKILL.md +34 -12
- package/dist/skills/frontend/references/design/README.md +2 -2
- package/dist/skills/frontend/references/design/_INDEX.md +2 -1
- package/dist/skills/frontend/references/design/component-catalogs.md +14 -10
- package/dist/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/dist/skills/frontend/references/design/grounding.md +29 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/dist/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/dist/skills/ultimate-browsing/SKILL.md +5 -4
- package/dist/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/dist/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/dist/skills/ultimate-browsing/engine/summary.py +1 -1
- package/dist/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/dist/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/dist/skills/ulw-research/AGENTS.md +8 -4
- package/dist/skills/ulw-research/SKILL.md +7 -316
- package/dist/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/dist/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/dist/skills/ulw-research/references/fact-ledger.md +42 -8
- package/dist/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/dist/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/dist/skills/ulw-research/references/report-gates.md +12 -5
- package/dist/skills/ulw-research/references/research-collection.md +195 -0
- package/dist/skills/ulw-research/references/research-delivery.md +123 -0
- package/dist/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/dist/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/dist/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/dist/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/dist/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -110
- package/dist/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/dist/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/dist/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/dist/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
- package/dist/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/dist/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/dist/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/dist/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/dist/skills/ulw-research/scripts/entities.mjs +13 -4
- package/dist/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/dist/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/dist/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/dist/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/dist/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/dist/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/dist/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/dist/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/dist/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/dist/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/dist/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/dist/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/dist/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/dist/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/dist/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/dist/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/dist/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/dist/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/dist/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/dist/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/dist/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/dist/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/dist/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/dist/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/dist/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/dist/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/dist/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/dist/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/dist/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/dist/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/dist/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/dist/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/dist/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/dist/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/dist/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/dist/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/dist/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/dist/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/dist/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/dist/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/dist/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/dist/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/dist/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/dist/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/dist/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/dist/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/dist/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/dist/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/dist/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/dist/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/dist/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/dist/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/dist/skills/ulw-research/scripts/report-tools.test.ts +5 -800
- package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/dist/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/dist/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/dist/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/dist/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/dist/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/dist/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/dist/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/dist/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/dist/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/dist/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/dist/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/dist/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/dist/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/dist/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/dist/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/dist/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/dist/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/dist/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/dist/skills/ulw-research/scripts/units.mjs +14 -3
- package/dist/skills/ulw-research/scripts/units.test.ts +10 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/dist/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/dist/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/dist/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/dist/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/dist/tools/delegate-task/executor-types.d.ts +1 -0
- package/dist/tools/delegate-task/sync-session-existence.d.ts +4 -0
- package/dist/tools/delegate-task/types.d.ts +1 -0
- package/dist/tools/skill/description-formatter.d.ts +2 -1
- package/dist/tools/skill/types.d.ts +6 -0
- package/dist/tui.js +131 -33
- package/package.json +18 -15
- package/packages/git-bash-mcp/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
- package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
- package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
- package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
- package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
- package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
- package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
- package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
- package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -316
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
- package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
- package/packages/shared-skills/skill-source-filter.mjs +6 -2
- package/packages/shared-skills/skills/ast-grep/README.md +1 -1
- package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
- package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
- package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
- package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
- package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
- package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
- package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
- package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
- package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
- package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
- package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -316
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +23 -21
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
- package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
- package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
- package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
- package/packages/shared-skills/skills/ulw-research/references/report-gates.md +12 -5
- package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
- package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
- package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
- package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -110
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
- package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
- package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
- package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
- package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +11 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +13 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +40 -18
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +25 -8
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +35 -16
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
- package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
- package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +6 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
- package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +4 -4
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
- package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
- package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
- package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
- package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
- package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
- package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
- package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
- package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
- package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
- package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
- package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
- package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
- package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
- package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
- package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
- package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
- package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +5 -800
- package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +79 -26
- package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
- package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
- package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
- package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
- package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
- package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
- package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
- package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { readFileSync, unlinkSync, writeFileSync } from "node:fs"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
|
|
5
|
+
import { sha256Of } from "./cli-support.mjs"
|
|
6
|
+
import { MEANING_RECORD, writeFidelityRecord } from "./fidelity-records.mjs"
|
|
7
|
+
import { delivered, expectRefused, fullyRecorded, LOCKED_BRIEF, meaningFile, type Recorded } from "./tests/delivery-barrier-session.ts"
|
|
8
|
+
|
|
9
|
+
/** A delivered, fidelity-verified html edition in a session whose locked brief sets `meaning check`. */
|
|
10
|
+
async function meaningSession(meaning: "on" | "off", codes: string[] | null) {
|
|
11
|
+
const session = await fullyRecorded(LOCKED_BRIEF.replace("meaning check: on", `meaning check: ${meaning}`))
|
|
12
|
+
if (codes === null) unlinkSync(session.recordPath.meaning)
|
|
13
|
+
else session.write("meaning", { defects: codes.map((code) => ({ code, severity: "major", message: code })) })
|
|
14
|
+
return session
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (const code of ["meaning_drift_confirmed", "meaning_unverified"]) {
|
|
18
|
+
test(`#given a meaning record with ${code} #when verified and finished #then delivery refuses`, async () => {
|
|
19
|
+
const session = await meaningSession("on", [code])
|
|
20
|
+
await expectRefused(session, { code: "fidelity_unresolved", codes: [code], path: session.recordPath.meaning })
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test("#given the brief says meaning check on and the meaning step was skipped #when verified and finished #then delivery refuses: meaning gate not run", async () => {
|
|
25
|
+
const session = await meaningSession("on", null)
|
|
26
|
+
await expectRefused(session, { message: expect.stringContaining("meaning gate not run") })
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test("#given a malformed ## Fidelity block that tries to turn meaning check off #when no meaning record exists #then delivery refuses: meaning gate not run", async () => {
|
|
30
|
+
const malformed = LOCKED_BRIEF.replace("meaning check: on (answered_by: default)", "meaning check: on (answered_by: default)\nmeaning check: off (answered_by: user)")
|
|
31
|
+
const session = await fullyRecorded(malformed)
|
|
32
|
+
unlinkSync(session.recordPath.meaning)
|
|
33
|
+
await expectRefused(session, { message: expect.stringContaining("meaning gate not run") })
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("#given the brief says meaning check off and no meaning record #when verified and finished #then delivery passes", async () => {
|
|
37
|
+
const session = await meaningSession("off", null)
|
|
38
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test("#given a clean meaning record (warn only) under meaning check on #when verified #then delivery passes", async () => {
|
|
42
|
+
const { invoke } = await meaningSession("on", ["meaning_drift_warn"])
|
|
43
|
+
expect((await invoke(["verify"])).exitCode).toBe(0)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test("#given meaning check on, no fidelity evidence, and an explicit fidelity not_run #when verified #then the logged exemption covers the meaning step too", async () => {
|
|
47
|
+
const { dir, invoke } = await delivered()
|
|
48
|
+
writeFileSync(join(dir, "brief.md"), LOCKED_BRIEF)
|
|
49
|
+
await invoke(["gate", "fidelity", "not_run", "--reason", "No factual content in this edition"])
|
|
50
|
+
expect((await invoke(["verify"])).exitCode).toBe(0)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test("#given an edition meaning record but no fidelity record #when the fidelity gate is skipped with a reason #then delivery still refuses", async () => {
|
|
54
|
+
const { dir, path, invoke } = await delivered()
|
|
55
|
+
writeFileSync(join(dir, "brief.md"), LOCKED_BRIEF)
|
|
56
|
+
writeFidelityRecord(meaningFile(dir, "html"), "meaning", { artifact_sha256: sha256Of(readFileSync(path)), report: path, defects: [] })
|
|
57
|
+
await invoke(["gate", "fidelity", "not_run", "--reason", "This harness has no verifier"])
|
|
58
|
+
const result = await invoke(["verify"])
|
|
59
|
+
expect(result.exitCode).toBe(1)
|
|
60
|
+
expect(JSON.stringify(result.json.problems)).toContain("fidelity gate not run")
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
/** Deliver a second edition with byte-different text and its own clean fidelity record. */
|
|
64
|
+
async function secondEdition(session: Recorded, format: string, text: string) {
|
|
65
|
+
const path = join(session.dir, `second.${format}`)
|
|
66
|
+
const record = join(session.dir, "second-fidelity.json")
|
|
67
|
+
writeFileSync(path, text)
|
|
68
|
+
writeFidelityRecord(record, "fidelity", { artifact_sha256: sha256Of(text), report: path, defects: [] })
|
|
69
|
+
await session.invoke(["set", format, "delivered", "--path", path, "--verified-by", record])
|
|
70
|
+
const meaning = meaningFile(session.dir, format)
|
|
71
|
+
const writeMeaning = (fields: Record<string, unknown> = {}) => writeFidelityRecord(meaning, "meaning", { artifact_sha256: sha256Of(text), report: path, defects: [], ...fields })
|
|
72
|
+
const problems = async () => (await session.invoke(["verify"])).json.problems
|
|
73
|
+
return { path, meaning, writeMeaning, problems }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const [format, text] of [["md", "Report in Markdown."], ["post", "Report in a post."]]) {
|
|
77
|
+
test(`#given html and ${format} delivered, each with its own meaning record #when verified and finished #then delivery passes`, async () => {
|
|
78
|
+
const session = await fullyRecorded()
|
|
79
|
+
const second = await secondEdition(session, format, text)
|
|
80
|
+
second.writeMeaning()
|
|
81
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test(`#given html and ${format} delivered but only html has a meaning record #when verified #then only ${format} refuses: meaning gate not run`, async () => {
|
|
85
|
+
const session = await fullyRecorded()
|
|
86
|
+
const second = await secondEdition(session, format, text)
|
|
87
|
+
expect(await second.problems()).toEqual([expect.objectContaining({ code: "edition_unverified", format, path: second.meaning, message: expect.stringContaining(`meaning gate not run; run fact pairs and fact meaning-check --edition ${format}`) })])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test(`#given the ${format} meaning record is for other bytes #when verified #then only ${format} refuses: a different edition`, async () => {
|
|
91
|
+
const session = await fullyRecorded()
|
|
92
|
+
const second = await secondEdition(session, format, text)
|
|
93
|
+
second.writeMeaning({ artifact_sha256: sha256Of("an earlier draft") })
|
|
94
|
+
expect(await second.problems()).toEqual([expect.objectContaining({ code: "edition_unverified", format, path: second.meaning, message: expect.stringContaining("is for a different edition") })])
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
test(`#given the ${format} meaning record carries a confirmed drift #when verified #then only that record blocks`, async () => {
|
|
98
|
+
const session = await fullyRecorded()
|
|
99
|
+
const second = await secondEdition(session, format, text)
|
|
100
|
+
second.writeMeaning({ defects: [{ code: "meaning_drift_confirmed", severity: "major", message: "drift" }] })
|
|
101
|
+
expect(await second.problems()).toEqual([expect.objectContaining({ code: "fidelity_unresolved", format, codes: ["meaning_drift_confirmed"], path: second.meaning })])
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
test(`#given one legacy session meaning record checked on html and ${format} delivered #when verified #then ${format} refuses: a different edition`, async () => {
|
|
105
|
+
const session = await fullyRecorded()
|
|
106
|
+
unlinkSync(session.recordPath.meaning)
|
|
107
|
+
writeFidelityRecord(join(session.dir, MEANING_RECORD), "meaning", { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects: [] })
|
|
108
|
+
const second = await secondEdition(session, format, text)
|
|
109
|
+
expect(await second.problems()).toEqual([expect.objectContaining({ code: "edition_unverified", format, path: join(session.dir, MEANING_RECORD), message: expect.stringContaining("is for a different edition") })])
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
test("#given a single edition and only the legacy session meaning record for its bytes #when verified and finished #then delivery passes", async () => {
|
|
114
|
+
const session = await fullyRecorded()
|
|
115
|
+
unlinkSync(session.recordPath.meaning)
|
|
116
|
+
writeFidelityRecord(join(session.dir, MEANING_RECORD), "meaning", { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects: [] })
|
|
117
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test("#given a pdf rendered from the html source #when only the html edition has a meaning record #then the pdf shares it and delivery passes", async () => {
|
|
121
|
+
const session = await fullyRecorded()
|
|
122
|
+
const pdf = join(session.dir, "report.pdf")
|
|
123
|
+
writeFileSync(pdf, "%PDF-1.7 rendered")
|
|
124
|
+
await session.invoke(["set", "pdf", "delivered", "--path", pdf, "--rendered-from", session.path, "--verified-by", session.record])
|
|
125
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test("#given html and a byte-identical md copy at another path #when only the html edition has a meaning record #then the md binds to it by bytes and delivery passes", async () => {
|
|
129
|
+
const session = await fullyRecorded()
|
|
130
|
+
const second = await secondEdition(session, "md", readFileSync(session.path, "utf8"))
|
|
131
|
+
expect(await second.problems()).toEqual([])
|
|
132
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// Reader runs on the same bytes are ordered by their records' written_at, never by file name.
|
|
136
|
+
const EARLIER = new Date("2026-01-01T10:00:00.000Z")
|
|
137
|
+
const LATER = new Date("2026-01-01T11:00:00.000Z")
|
|
138
|
+
const DRIFT = [{ code: "meaning_drift_confirmed", severity: "major", message: "drift" }]
|
|
139
|
+
|
|
140
|
+
/** Write a meaning record for the delivered html bytes at an explicit time. */
|
|
141
|
+
const meaningAt = (session: Recorded, path: string, at: Date, defects: Record<string, unknown>[] = []) =>
|
|
142
|
+
writeFidelityRecord(path, "meaning", { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects }, at)
|
|
143
|
+
|
|
144
|
+
/** Deliver a pdf rendered from the html source; it has no meaning record of its own. */
|
|
145
|
+
const deliverPdf = async (session: Recorded) => {
|
|
146
|
+
const pdf = join(session.dir, "report.pdf")
|
|
147
|
+
writeFileSync(pdf, "%PDF-1.7 rendered")
|
|
148
|
+
await session.invoke(["set", "pdf", "delivered", "--path", pdf, "--rendered-from", session.path, "--verified-by", session.record])
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
test("#given a clean own record written after a legacy record confirming drift on the same bytes #when verified and finished #then the newer clean run passes", async () => {
|
|
152
|
+
const session = await fullyRecorded()
|
|
153
|
+
meaningAt(session, join(session.dir, MEANING_RECORD), EARLIER, DRIFT)
|
|
154
|
+
meaningAt(session, session.recordPath.meaning, LATER)
|
|
155
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test("#given a legacy record confirming drift written after a clean own record on the same bytes #when verified and finished #then the newer drift refuses", async () => {
|
|
159
|
+
const session = await fullyRecorded()
|
|
160
|
+
meaningAt(session, session.recordPath.meaning, EARLIER)
|
|
161
|
+
meaningAt(session, join(session.dir, MEANING_RECORD), LATER, DRIFT)
|
|
162
|
+
await expectRefused(session, { code: "fidelity_unresolved", codes: ["meaning_drift_confirmed"], path: join(session.dir, MEANING_RECORD) })
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test("#given a clean own record and a legacy drift record written at the same time on the same bytes #when verified and finished #then the more severe verdict refuses", async () => {
|
|
166
|
+
const session = await fullyRecorded()
|
|
167
|
+
meaningAt(session, session.recordPath.meaning, LATER)
|
|
168
|
+
meaningAt(session, join(session.dir, MEANING_RECORD), LATER, DRIFT)
|
|
169
|
+
await expectRefused(session, { code: "fidelity_unresolved", codes: ["meaning_drift_confirmed"], path: join(session.dir, MEANING_RECORD) })
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test("#given two edition records for the same bytes, the alphabetically-first clean and older #when a pdf of those bytes is verified and finished #then the newer drift refuses", async () => {
|
|
173
|
+
const session = await fullyRecorded()
|
|
174
|
+
await deliverPdf(session)
|
|
175
|
+
meaningAt(session, meaningFile(session.dir, "html"), EARLIER)
|
|
176
|
+
meaningAt(session, meaningFile(session.dir, "post"), LATER, DRIFT)
|
|
177
|
+
await expectRefused(session, { code: "fidelity_unresolved", codes: ["meaning_drift_confirmed"], path: meaningFile(session.dir, "post") })
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
test("#given two edition records for the same bytes, the alphabetically-first confirming drift and older #when verified and finished #then the newer clean run passes", async () => {
|
|
181
|
+
const session = await fullyRecorded()
|
|
182
|
+
await deliverPdf(session)
|
|
183
|
+
meaningAt(session, meaningFile(session.dir, "html"), EARLIER, DRIFT)
|
|
184
|
+
meaningAt(session, meaningFile(session.dir, "post"), LATER)
|
|
185
|
+
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
186
|
+
})
|
|
@@ -1,28 +1,12 @@
|
|
|
1
1
|
import { describe, expect, onTestFinished, test } from "bun:test"
|
|
2
|
-
import {
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs"
|
|
3
3
|
import { tmpdir } from "node:os"
|
|
4
|
-
import { join } from "node:path"
|
|
4
|
+
import { dirname, join } from "node:path"
|
|
5
5
|
|
|
6
6
|
import { sha256Of } from "./cli-support.mjs"
|
|
7
7
|
import { DEFECT_CODES } from "./contracts.mjs"
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { run } from "./report-tools.mjs"
|
|
11
|
-
|
|
12
|
-
async function delivered(format = "html", codes: string[] | null = null) {
|
|
13
|
-
const root = mkdtempSync(join(tmpdir(), "delivery-barrier-"))
|
|
14
|
-
onTestFinished(() => rmSync(root, { recursive: true, force: true }))
|
|
15
|
-
const dir = join(root, "20260101-120000")
|
|
16
|
-
mkdirSync(dir)
|
|
17
|
-
const path = join(dir, `report.${format}`)
|
|
18
|
-
const record = join(dir, "fidelity-defects.json")
|
|
19
|
-
writeFileSync(path, "<p>Report</p>")
|
|
20
|
-
if (codes !== null) writeFidelityRecord(record, "fidelity", { artifact_sha256: sha256Of(readFileSync(path)), report: path, defects: codes.map((code) => ({ code, severity: "minor", message: code })) })
|
|
21
|
-
const invoke = (args: string[]) => run(["outcome", ...args, "--session-dir", dir])
|
|
22
|
-
await invoke(["init", "--promised", format])
|
|
23
|
-
expect((await invoke(["set", format, "delivered", "--path", path, ...(codes === null ? [] : ["--verified-by", record])])).exitCode).toBe(0)
|
|
24
|
-
return { dir, path, record, invoke }
|
|
25
|
-
}
|
|
8
|
+
import { fidelityProblems, FIDELITY_RECORDS, RECORD_ENVELOPE, writeFidelityRecord } from "./fidelity-records.mjs"
|
|
9
|
+
import { BLOCKER, delivered, expectRefused, fullyRecorded } from "./tests/delivery-barrier-session.ts"
|
|
26
10
|
|
|
27
11
|
// Enumerate the source registry, not a second list of today's fidelity codes.
|
|
28
12
|
for (const [code, entry] of Object.entries(DEFECT_CODES)) {
|
|
@@ -113,32 +97,6 @@ test("#given an explicit skip and an existing blocker #when verified #then the s
|
|
|
113
97
|
expect((await invoke(["verify"])).exitCode).toBe(1)
|
|
114
98
|
})
|
|
115
99
|
|
|
116
|
-
const LOCKED_BRIEF = readFileSync(join(import.meta.dir, "tests", "fixtures", "fidelity-brief-locked.md"), "utf8")
|
|
117
|
-
const BLOCKER = Object.keys(DEFECT_CODES).find((code) => blocksDelivery({ code })) as string
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* A delivered html edition whose locked brief requires every table record, each present, fresh for
|
|
121
|
-
* the delivered bytes, and clean. recordPath is where the session keeps each row's record; a table
|
|
122
|
-
* row with no entry here fails the coverage test below, so a new row brings its own cases.
|
|
123
|
-
*/
|
|
124
|
-
async function fullyRecorded(brief = LOCKED_BRIEF) {
|
|
125
|
-
const session = await delivered("html", [])
|
|
126
|
-
writeFileSync(join(session.dir, "brief.md"), brief)
|
|
127
|
-
const recordPath: Record<string, string> = { fidelity: session.record, meaning: join(session.dir, MEANING_RECORD) }
|
|
128
|
-
const write = (kind: string, fields: Record<string, unknown> = {}) =>
|
|
129
|
-
writeFidelityRecord(recordPath[kind], kind, { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects: [], ...fields })
|
|
130
|
-
write("meaning")
|
|
131
|
-
const outcomes = async () => Promise.all(["verify", "finish"].map((command) => session.invoke([command])))
|
|
132
|
-
return { ...session, recordPath, write, outcomes }
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function expectRefused(session: Awaited<ReturnType<typeof fullyRecorded>>, problem: Record<string, unknown>) {
|
|
136
|
-
for (const result of await session.outcomes()) {
|
|
137
|
-
expect(result.exitCode).toBe(1)
|
|
138
|
-
expect(result.json.problems).toContainEqual(expect.objectContaining(problem))
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
100
|
test("#given the record table #when every row is read #then each row has every rule column and an arranged session path", async () => {
|
|
143
101
|
const { recordPath } = await fullyRecorded()
|
|
144
102
|
expect(Object.keys(recordPath).sort()).toEqual(FIDELITY_RECORDS.map((entry) => entry.kind).sort())
|
|
@@ -148,7 +106,7 @@ test("#given the record table #when every row is read #then each row has every r
|
|
|
148
106
|
}
|
|
149
107
|
})
|
|
150
108
|
|
|
151
|
-
// The table is the barrier's spec: every row gets the same
|
|
109
|
+
// The table is the barrier's spec: every row gets the same six cases.
|
|
152
110
|
for (const entry of FIDELITY_RECORDS) {
|
|
153
111
|
describe(`record row ${entry.kind}`, () => {
|
|
154
112
|
test("#given the record is missing while required #when verified and finished #then delivery refuses", async () => {
|
|
@@ -157,6 +115,13 @@ for (const entry of FIDELITY_RECORDS) {
|
|
|
157
115
|
await expectRefused(session, { code: "edition_unverified", path: session.recordPath[entry.kind] })
|
|
158
116
|
})
|
|
159
117
|
|
|
118
|
+
test("#given the record is missing and the row names none #when verified and finished #then delivery refuses: the step was not run", async () => {
|
|
119
|
+
const session = await fullyRecorded()
|
|
120
|
+
unlinkSync(session.recordPath[entry.kind])
|
|
121
|
+
await session.invoke(["set", "html", "delivered", "--path", session.path])
|
|
122
|
+
await expectRefused(session, { code: "edition_unverified", message: expect.stringContaining(`${entry.step} not run`) })
|
|
123
|
+
})
|
|
124
|
+
|
|
160
125
|
test("#given the record is for other bytes #when verified and finished #then delivery refuses: a different edition", async () => {
|
|
161
126
|
const session = await fullyRecorded()
|
|
162
127
|
session.write(entry.kind, { artifact_sha256: sha256Of("an earlier draft") })
|
|
@@ -191,6 +156,12 @@ for (const entry of FIDELITY_RECORDS) {
|
|
|
191
156
|
})
|
|
192
157
|
}
|
|
193
158
|
|
|
159
|
+
test("#given a row whose --verified-by record is gone #when verified and finished #then delivery refuses: the record is missing", async () => {
|
|
160
|
+
const session = await fullyRecorded()
|
|
161
|
+
unlinkSync(session.record)
|
|
162
|
+
await expectRefused(session, { code: "edition_unverified", format: "html", path: session.record, message: `html: fidelity record ${session.record} is missing` })
|
|
163
|
+
})
|
|
164
|
+
|
|
194
165
|
test("#given a record kind outside the table or a malformed envelope #when written #then the writer refuses", () => {
|
|
195
166
|
const dir = mkdtempSync(join(tmpdir(), "delivery-barrier-writer-"))
|
|
196
167
|
onTestFinished(() => rmSync(dir, { recursive: true, force: true }))
|
|
@@ -200,46 +171,28 @@ test("#given a record kind outside the table or a malformed envelope #when writt
|
|
|
200
171
|
expect(() => writeFidelityRecord(join(dir, "c.json"), "meaning", { ...fields, gatesRun: [] })).toThrow("unknown field")
|
|
201
172
|
})
|
|
202
173
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
174
|
+
test("#given an unattached session fidelity blocker and a clean attached record #when verified and finished #then the session blocker refuses", async () => {
|
|
175
|
+
const session = await fullyRecorded()
|
|
176
|
+
const other = join(session.dir, "other.json")
|
|
177
|
+
writeFidelityRecord(other, "fidelity", { artifact_sha256: sha256Of(readFileSync(session.path)), report: session.path, defects: [] })
|
|
178
|
+
await session.invoke(["set", "html", "delivered", "--path", session.path, "--verified-by", other])
|
|
179
|
+
session.write("fidelity", { defects: [{ code: BLOCKER }] })
|
|
180
|
+
await expectRefused(session, { code: "fidelity_unresolved", codes: [BLOCKER], path: session.record })
|
|
181
|
+
})
|
|
210
182
|
|
|
211
|
-
for (const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
183
|
+
for (const [name, alias] of [
|
|
184
|
+
["a dot segment", (dir: string) => `${dir}/./fidelity-defects.json`],
|
|
185
|
+
["a directory link", (dir: string) => {
|
|
186
|
+
const link = join(dirname(dir), "alias")
|
|
187
|
+
symlinkSync(dir, link, "junction")
|
|
188
|
+
return join(link, "fidelity-defects.json")
|
|
189
|
+
}],
|
|
190
|
+
] as const) {
|
|
191
|
+
test(`#given two target paths reaching one blocking record through ${name} #when the barrier runs #then it reports the blocker once`, async () => {
|
|
192
|
+
const session = await fullyRecorded()
|
|
193
|
+
session.write("fidelity", { defects: [{ code: BLOCKER }] })
|
|
194
|
+
const manifest = JSON.parse(readFileSync(join(session.dir, "outcome.json"), "utf8"))
|
|
195
|
+
manifest.deliverables.push({ ...manifest.deliverables[0], format: "md", verifiedBy: alias(session.dir) })
|
|
196
|
+
expect(fidelityProblems(session.dir, manifest).filter((problem) => problem.code === "fidelity_unresolved")).toHaveLength(1)
|
|
215
197
|
})
|
|
216
198
|
}
|
|
217
|
-
|
|
218
|
-
test("#given the brief says meaning check on and the meaning step was skipped #when verified and finished #then delivery refuses: meaning gate not run", async () => {
|
|
219
|
-
const session = await meaningSession("on", null)
|
|
220
|
-
await expectRefused(session, { message: expect.stringContaining("meaning gate not run") })
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
test("#given a malformed ## Fidelity block that tries to turn meaning check off #when no meaning record exists #then delivery refuses: meaning gate not run", async () => {
|
|
224
|
-
const malformed = LOCKED_BRIEF.replace("meaning check: on (answered_by: default)", "meaning check: on (answered_by: default)\nmeaning check: off (answered_by: user)")
|
|
225
|
-
const session = await fullyRecorded(malformed)
|
|
226
|
-
unlinkSync(session.recordPath.meaning)
|
|
227
|
-
await expectRefused(session, { message: expect.stringContaining("meaning gate not run") })
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
test("#given the brief says meaning check off and no meaning record #when verified and finished #then delivery passes", async () => {
|
|
231
|
-
const session = await meaningSession("off", null)
|
|
232
|
-
expect((await session.outcomes()).map((result) => result.exitCode)).toEqual([0, 0])
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
test("#given a clean meaning record (warn only) under meaning check on #when verified #then delivery passes", async () => {
|
|
236
|
-
const { invoke } = await meaningSession("on", ["meaning_drift_warn"])
|
|
237
|
-
expect((await invoke(["verify"])).exitCode).toBe(0)
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
test("#given meaning check on, no fidelity evidence, and an explicit fidelity not_run #when verified #then the logged exemption covers the meaning step too", async () => {
|
|
241
|
-
const { dir, invoke } = await delivered()
|
|
242
|
-
writeFileSync(join(dir, "brief.md"), LOCKED_BRIEF)
|
|
243
|
-
await invoke(["gate", "fidelity", "not_run", "--reason", "No factual content in this edition"])
|
|
244
|
-
expect((await invoke(["verify"])).exitCode).toBe(0)
|
|
245
|
-
})
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
// entities.mjs - HTML character reference decoding for html-lite.mjs.
|
|
2
2
|
//
|
|
3
|
-
// Supports a fixed set of named entities plus decimal and hex numeric references.
|
|
4
|
-
// malformed references stay verbatim. Single indexOf scan; plain Node ESM, no dependencies.
|
|
3
|
+
// Supports a fixed set of named entities (NAMED_ENTITIES) plus decimal and hex numeric references.
|
|
4
|
+
// Unknown or malformed references stay verbatim. Single indexOf scan; plain Node ESM, no dependencies.
|
|
5
5
|
|
|
6
|
+
// Beyond the common set, every named reference whose character a number reader treats specially is
|
|
7
|
+
// listed (signs, dashes, the space separators that group digits, and Markdown punctuation), so the
|
|
8
|
+
// conversion probe reads `−5` and `1 234` as a converter does.
|
|
6
9
|
const NAMED_ENTITIES = {
|
|
7
10
|
amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: "\u00a0", mdash: "\u2014", ndash: "\u2013",
|
|
8
11
|
hellip: "\u2026", copy: "\u00a9", reg: "\u00ae", times: "\u00d7", middot: "\u00b7",
|
|
12
|
+
minus: "\u2212", hyphen: "\u2010", dash: "\u2010", NonBreakingSpace: "\u00a0", thinsp: "\u2009",
|
|
13
|
+
ThinSpace: "\u2009", numsp: "\u2007", puncsp: "\u2008", hairsp: "\u200a", VeryThinSpace: "\u200a",
|
|
14
|
+
ensp: "\u2002", emsp: "\u2003", emsp13: "\u2004", emsp14: "\u2005", MediumSpace: "\u205f",
|
|
15
|
+
comma: ",", period: ".", plus: "+", lowbar: "_", UnderBar: "_", ast: "*", midast: "*", grave: "`",
|
|
16
|
+
DiacriticalGrave: "`", lpar: "(", rpar: ")", lsqb: "[", lbrack: "[", rsqb: "]", rbrack: "]",
|
|
9
17
|
}
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
/** One reference body (between `&` and `;`), or null when unsupported. */
|
|
20
|
+
export function decodeOne(body) {
|
|
12
21
|
if (Object.hasOwn(NAMED_ENTITIES, body)) return NAMED_ENTITIES[body]
|
|
13
22
|
if (body[0] !== "#") return null
|
|
14
23
|
const hex = body[1] === "x" || body[1] === "X"
|
|
@@ -26,7 +35,7 @@ export function decodeEntities(text) {
|
|
|
26
35
|
let at = source.indexOf("&")
|
|
27
36
|
while (at !== -1) {
|
|
28
37
|
const semi = source.indexOf(";", at + 1)
|
|
29
|
-
const decoded = semi !== -1 && semi - at <=
|
|
38
|
+
const decoded = semi !== -1 && semi - at <= 32 ? decodeOne(source.slice(at + 1, semi)) : null
|
|
30
39
|
if (decoded !== null) {
|
|
31
40
|
out += source.slice(last, at) + decoded
|
|
32
41
|
last = semi + 1
|
|
@@ -13,10 +13,13 @@ import { dirname, extname, resolve } from "node:path"
|
|
|
13
13
|
|
|
14
14
|
import { CliError, sha256Of, writeJsonAtomic } from "./cli-support.mjs"
|
|
15
15
|
import { DEFECT_CODES } from "./contracts.mjs"
|
|
16
|
+
import { markdownAsHtml } from "./fact-commands-verify.mjs"
|
|
16
17
|
import { FILL_FORMATS, fill } from "./fact-fill.mjs"
|
|
17
18
|
import { readLedger, writeLedger } from "./fact-ledger.mjs"
|
|
18
19
|
import { briefHashOf, fillPolicy, lockedBrief, policyErrors } from "./fidelity-policy.mjs"
|
|
19
20
|
import { readState, writeState } from "./fidelity-state.mjs"
|
|
21
|
+
import { withBoundUnits } from "./fidelity-value-unit.mjs"
|
|
22
|
+
import { parseMarkdown } from "./md-lite.mjs"
|
|
20
23
|
import { findPlaceholders } from "./placeholder.mjs"
|
|
21
24
|
import { sessionDirOf } from "./source-commands.mjs"
|
|
22
25
|
|
|
@@ -28,6 +31,13 @@ export const FILL_INPUT_FORMAT_RULES = Object.freeze({
|
|
|
28
31
|
export const FILL_INPUT_FORMATS = Object.freeze([...FILL_FORMATS, ...Object.keys(FILL_INPUT_FORMAT_RULES.aliases)])
|
|
29
32
|
const fillFormatOf = (format) => FILL_INPUT_FORMAT_RULES.aliases[format] ?? format
|
|
30
33
|
|
|
34
|
+
/** Value-mode entries carry the unit fill saw bound to them (unit_bound), read off the edition verify will check. */
|
|
35
|
+
function boundUnits(out, entries, ledger, format) {
|
|
36
|
+
if (!entries.some((entry) => entry.mode === "value")) return entries
|
|
37
|
+
const html = fillFormatOf(format) === "html" ? out : parseMarkdown(out).problems.length === 0 ? markdownAsHtml(out, entries, ledger).html : null
|
|
38
|
+
return html === null ? entries : withBoundUnits(html, entries, new Map(ledger.rows.map((row) => [row.fact_id, row])))
|
|
39
|
+
}
|
|
40
|
+
|
|
31
41
|
function readText(path) {
|
|
32
42
|
try {
|
|
33
43
|
return readFileSync(path, "utf8")
|
|
@@ -80,7 +90,7 @@ export function runFactFill(args) {
|
|
|
80
90
|
const artifact = sha256Of(out)
|
|
81
91
|
const map = `${resolve(flags.out)}.fill-map.json`
|
|
82
92
|
const brief = briefHashOf(parsed)
|
|
83
|
-
writeJsonAtomic(map, { schemaVersion: 1, format, artifact: resolve(flags.out), artifact_sha256: artifact, brief_sha256: brief, entries })
|
|
93
|
+
writeJsonAtomic(map, { schemaVersion: 1, format, artifact: resolve(flags.out), artifact_sha256: artifact, brief_sha256: brief, entries: boundUnits(out, entries, ledger, format) })
|
|
84
94
|
const data = { out: resolve(flags.out), map, artifact_sha256: artifact, brief_sha256: brief, occurrences: entries.length, warnings }
|
|
85
95
|
return { json: { command: "fact fill", status: "pass", exitCode: 0, defects: [], data }, summary: `fact fill: wrote ${flags.out} (${entries.length} pointer(s))`, exitCode: 0 }
|
|
86
96
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// fact-commands-meaning.mjs - `fact pairs` and `fact meaning-check`, the script half of the
|
|
2
2
|
// separate-session meaning verifier. fact pairs writes the (source, report sentence) pairs a
|
|
3
|
-
// reader lane gets and nothing else (with --changed-since, only the pairs whose sentence
|
|
4
|
-
//
|
|
3
|
+
// reader lane gets and nothing else (with --changed-since, only the pairs whose sentence changed
|
|
4
|
+
// since the pre-polish fill map's artifact, or all when those bytes are gone); it honours the brief's `meaning check` field and writes
|
|
5
5
|
// `{ skipped: true }` when it is off. fact meaning-check ingests the readers' verdict files
|
|
6
|
-
// (meaning-check.mjs), writes
|
|
6
|
+
// (meaning-check.mjs), writes the meaning record of one edition (fidelity-meaning-defects.<format>.json
|
|
7
|
+
// with --edition, else the legacy fidelity-meaning-defects.json; a fidelity record bound to the pairs'
|
|
7
8
|
// artifact_sha256 and report, through writeFidelityRecord), and records the run in
|
|
8
9
|
// fidelity-calibration.jsonl: a header with the promotion criterion on first write, then per run
|
|
9
10
|
// one run line plus one line per flagged pair. The run id hashes the inputs only, so a rerun or a
|
|
@@ -15,13 +16,13 @@ import { existsSync, readFileSync } from "node:fs"
|
|
|
15
16
|
import { dirname, join, resolve } from "node:path"
|
|
16
17
|
|
|
17
18
|
import { CliError, parseArgs, readJsonFile, sha256Of, writeJsonAtomic, writeTextAtomic } from "./cli-support.mjs"
|
|
18
|
-
import { countDefects } from "./contracts.mjs"
|
|
19
|
+
import { countDefects, DELIVERABLE_FORMATS } from "./contracts.mjs"
|
|
19
20
|
import { ledgerFrom, markdownAsHtml, readEdition, sessionOf } from "./fact-commands-verify.mjs"
|
|
20
21
|
import { pairsChangedSince } from "./fact-commands-polish.mjs"
|
|
21
22
|
import { extractPairs, PAIR_KINDS } from "./fact-pairs.mjs"
|
|
22
23
|
import { FIDELITY_INCOMPLETE } from "./fidelity-brief.mjs"
|
|
23
24
|
import { briefPathOf, lockedBrief, meaningCheckEnabled } from "./fidelity-policy.mjs"
|
|
24
|
-
import { MEANING_RECORD, writeFidelityRecord } from "./fidelity-records.mjs"
|
|
25
|
+
import { MEANING_RECORD, meaningRecordName, writeFidelityRecord } from "./fidelity-records.mjs"
|
|
25
26
|
import { blocksDelivery } from "./gates-fidelity.mjs"
|
|
26
27
|
import { ingestVerdicts, unverifiedDefects, VERDICT_SCHEMA } from "./meaning-check.mjs"
|
|
27
28
|
|
|
@@ -57,10 +58,12 @@ function runPairs(args) {
|
|
|
57
58
|
const ledger = ledgerFrom(flags, session)
|
|
58
59
|
const html = edition.format === "md" ? markdownAsHtml(edition.text, edition.entries, ledger).html : edition.text
|
|
59
60
|
const all = extractPairs(html, ledger, claims)
|
|
60
|
-
const
|
|
61
|
+
const since = flags["changed-since"] === undefined ? null : pairsChangedSince(all, flags["changed-since"], ledger, claims)
|
|
62
|
+
const pairs = since?.pairs ?? all
|
|
61
63
|
const counts = { total: pairs.length, force_strong: pairs.filter((pair) => pair.force_strong).length }
|
|
62
64
|
for (const kind of PAIR_KINDS) counts[kind] = pairs.filter((pair) => pair.kind === kind).length
|
|
63
|
-
const
|
|
65
|
+
const changed = since === null ? {} : { changed_since: { fill_map: since.fill_map, narrowed: since.narrowed } }
|
|
66
|
+
const record = { schemaVersion: 1, skipped: false, report: resolve(report), format: edition.format, artifact_sha256: sha256Of(edition.text), pairs_sha256: sha256Of(JSON.stringify(pairs)), counts, ...changed, verdict_schema: VERDICT_SCHEMA, pairs }
|
|
64
67
|
writeJsonAtomic(out, record)
|
|
65
68
|
const summary = `fact pairs: ${counts.total} pair(s), ${counts.force_strong} routed to the strong reader`
|
|
66
69
|
return { json: { command: "fact pairs", status: "pass", exitCode: 0, data: { out, ...record, pairs: undefined } }, summary, exitCode: 0 }
|
|
@@ -124,8 +127,9 @@ function skippedRefusal(flags, parsed) {
|
|
|
124
127
|
|
|
125
128
|
function runMeaningCheck(args) {
|
|
126
129
|
const { flags } = args
|
|
127
|
-
const usage = "usage: fact meaning-check --pairs pairs.json --verdicts cheap.json [--verdicts strong.json] [--dispute P<n> --reason TEXT] [--run-id ID] [--calibration F] [--brief brief.md] [--out F]"
|
|
130
|
+
const usage = "usage: fact meaning-check --pairs pairs.json --verdicts cheap.json [--verdicts strong.json] [--dispute P<n> --reason TEXT] [--run-id ID] [--calibration F] [--brief brief.md] [--edition FORMAT] [--out F]"
|
|
128
131
|
if (flags.pairs === undefined || !Array.isArray(flags.verdicts)) throw new CliError(usage)
|
|
132
|
+
if (flags.edition !== undefined && !DELIVERABLE_FORMATS.includes(flags.edition)) throw new CliError(`--edition must be a deliverable format (${DELIVERABLE_FORMATS.join(", ")}), got ${flags.edition}`)
|
|
129
133
|
const session = sessionOf(flags)
|
|
130
134
|
const { parsed, refusal } = lockedBrief("fact meaning-check", flags)
|
|
131
135
|
if (refusal) return { ...refusal, json: { ...refusal.json, error: FIDELITY_INCOMPLETE } }
|
|
@@ -146,7 +150,7 @@ function runMeaningCheck(args) {
|
|
|
146
150
|
} catch (error) {
|
|
147
151
|
throw new CliError(`invalid verdict input: ${error.message}`)
|
|
148
152
|
}
|
|
149
|
-
const out = resolve(flags.out ?? inSession(session, MEANING_RECORD, "--out"))
|
|
153
|
+
const out = resolve(flags.out ?? inSession(session, flags.edition === undefined ? MEANING_RECORD : meaningRecordName(flags.edition), "--out"))
|
|
150
154
|
const calibration = resolve(flags.calibration ?? join(session ?? dirname(out), CALIBRATION_FILE))
|
|
151
155
|
const runId = flags["run-id"] ?? sha256Of([pairsText, ...verdictTexts].join("\0")).slice(0, 16)
|
|
152
156
|
const pairsSha = pairsDoc.pairs_sha256 ?? sha256Of(pairsText)
|
|
@@ -6,18 +6,24 @@
|
|
|
6
6
|
// rejected (major) or unlocated (minor) edit leaves its region unchanged and is listed with its
|
|
7
7
|
// index and reason so the orchestrator can re-send it; every rejection reason is printed verbatim, one
|
|
8
8
|
// line per rejected edit (index and the first 60 characters of its before), in the summary and in
|
|
9
|
-
// data.rejected_reasons. It exits 0 whenever it wrote the output.
|
|
9
|
+
// data.rejected_reasons. It exits 0 whenever it wrote the output; json.applied is false when
|
|
10
|
+
// any edit was rejected or unlocated, independently of data.applied's accepted-edit count.
|
|
11
|
+
// polish-apply never rewrites a fill map: it checks that the edition's map (fillMapOf) records the
|
|
12
|
+
// input's bytes, refusing otherwise, and writes `<out>.polished.fill-map.json` beside the output
|
|
13
|
+
// (artifact = the polished file, its hash, and polishedFrom = the fill map's path and sha256).
|
|
10
14
|
// polish-diff is the whole-document backstop (polish-diff.mjs) between the pre-polish artifact
|
|
11
|
-
// and any later copy; it exits 1 on a blocker. pairsChangedSince
|
|
12
|
-
//
|
|
13
|
-
// meaning readers re-check exactly what
|
|
15
|
+
// and any later copy; it exits 1 on a blocker. pairsChangedSince always reads the pre-polish fill
|
|
16
|
+
// map (following a polished map's polishedFrom) and keeps only the pairs whose sentence text
|
|
17
|
+
// (normalized) is not in the artifact it names, so the meaning readers re-check exactly what
|
|
18
|
+
// changed; when that artifact no longer hashes to the map (polished in place, or edited) nothing
|
|
19
|
+
// can be ruled out and every pair is kept. No model, no network.
|
|
14
20
|
|
|
15
21
|
import { existsSync, readFileSync } from "node:fs"
|
|
16
22
|
import { join, resolve } from "node:path"
|
|
17
23
|
|
|
18
24
|
import { CliError, parseArgs, readJsonFile, sha256Of, writeJsonAtomic, writeTextAtomic } from "./cli-support.mjs"
|
|
19
25
|
import { countDefects, DEFECT_CODES } from "./contracts.mjs"
|
|
20
|
-
import { editionFormatOf, ledgerFrom, markdownAsHtml, sessionOf } from "./fact-commands-verify.mjs"
|
|
26
|
+
import { editionFormatOf, fillMapOf, ledgerFrom, markdownAsHtml, sessionOf } from "./fact-commands-verify.mjs"
|
|
21
27
|
import { extractPairs } from "./fact-pairs.mjs"
|
|
22
28
|
import { lockedBrief } from "./fidelity-policy.mjs"
|
|
23
29
|
import { applyEdits, POLISH_EDIT_FIELDS, validatePolishEdits } from "./polish-apply.mjs"
|
|
@@ -58,7 +64,7 @@ const rejectionLine = (entry, edit) => ` rejected edit ${entry.index} ("${befor
|
|
|
58
64
|
function runPolishApply(args) {
|
|
59
65
|
const [report] = args.positionals
|
|
60
66
|
const { flags } = args
|
|
61
|
-
if (!report || flags.edits === undefined || flags.out === undefined) throw new CliError("usage: fact polish-apply <report.html> --edits polish-edits.json --out <report.polished.html> [--ledger F] [--brief brief.md] [--session-dir D]")
|
|
67
|
+
if (!report || flags.edits === undefined || flags.out === undefined) throw new CliError("usage: fact polish-apply <report.html> --edits polish-edits.json --out <report.polished.html> [--fill-map F] [--ledger F] [--brief brief.md] [--session-dir D]")
|
|
62
68
|
if (editionFormatOf(report, flags.format) === "md") throw new CliError("fact polish-apply takes the filled HTML edition; polish a Markdown edition through its HTML source")
|
|
63
69
|
const { refusal } = lockedBrief("fact polish-apply", flags)
|
|
64
70
|
if (refusal) return refusal
|
|
@@ -71,13 +77,18 @@ function runPolishApply(args) {
|
|
|
71
77
|
throw new CliError(`${flags.edits} must be an array of {${Object.keys(POLISH_EDIT_FIELDS).join(", ")}} objects: ${error.message}`)
|
|
72
78
|
}
|
|
73
79
|
const result = applyEdits(html, edits, ledgerFrom(flags))
|
|
80
|
+
const mapPath = fillMapOf(report, html, flags["fill-map"])
|
|
81
|
+
const map = mapPath === null ? null : readJsonFile(mapPath)
|
|
82
|
+
if (map !== null && map.artifact_sha256 !== sha256Of(html)) throw new CliError(`${mapPath} does not record the bytes of ${report} (artifact_sha256 differs); refusing to carry its brief binding to the polished edition`)
|
|
83
|
+
const polishedFrom = map?.polishedFrom ?? (map && { map: resolve(mapPath), sha256: sha256Of(readText(mapPath)) })
|
|
74
84
|
writeTextAtomic(flags.out, result.out)
|
|
85
|
+
if (map) writeJsonAtomic(`${resolve(flags.out)}.polished.fill-map.json`, { ...map, artifact: resolve(flags.out), artifact_sha256: sha256Of(result.out), polishedFrom })
|
|
75
86
|
const defects = [...result.rejected, ...result.unlocated].sort((a, b) => a.index - b.index).map(withSeverity)
|
|
76
87
|
const counts = { applied: result.applied.length, rejected: result.rejected.length, unlocated: result.unlocated.length }
|
|
77
88
|
const data = { out: resolve(flags.out), ...counts, applied_indexes: result.applied, input_sha256: sha256Of(html), edits_sha256: sha256Of(editsText), out_sha256: sha256Of(result.out) }
|
|
78
89
|
const rejected_reasons = result.rejected.map((entry) => rejectionLine(entry, edits[entry.index]))
|
|
79
90
|
const summary = [`fact polish-apply: ${counts.applied} applied, ${counts.rejected} rejected, ${counts.unlocated} unlocated of ${edits.length} edit(s)`, ...rejected_reasons].join("\n")
|
|
80
|
-
return { json: { command: "fact polish-apply", status: "pass", exitCode: 0, defects, data: { ...data, rejected_reasons } }, summary, exitCode: 0 }
|
|
91
|
+
return { json: { command: "fact polish-apply", status: "pass", exitCode: 0, applied: counts.rejected === 0 && counts.unlocated === 0, defects, data: { ...data, rejected_reasons } }, summary, exitCode: 0 }
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
function runPolishDiff(args) {
|
|
@@ -100,29 +111,40 @@ function runPolishDiff(args) {
|
|
|
100
111
|
|
|
101
112
|
const pairKey = (pair) => [pair.kind, pair.sentence_key, pair.claim_id ?? "", normalizeText(pair.sentence)].join("\u0000")
|
|
102
113
|
|
|
114
|
+
/** The pre-polish fill map behind --changed-since: a polished map leads to it through polishedFrom, whose sha256 it must still match. */
|
|
115
|
+
function prePolishMap(mapPath) {
|
|
116
|
+
const given = readJsonFile(mapPath)
|
|
117
|
+
if (given.polishedFrom === undefined) return { path: resolve(mapPath), map: given }
|
|
118
|
+
const { map: path, sha256 } = given.polishedFrom
|
|
119
|
+
if (typeof path !== "string" || sha256Of(readText(path)) !== sha256) throw new CliError(`${path} changed after polish wrote ${mapPath}; --changed-since needs the pre-polish fill map it names`)
|
|
120
|
+
return { path, map: readJsonFile(path) }
|
|
121
|
+
}
|
|
122
|
+
|
|
103
123
|
/**
|
|
104
|
-
* The pairs whose sentence text changed since the pre-polish artifact
|
|
105
|
-
* kept unless the same (kind, sentence key, normalized sentence) occurs in that artifact.
|
|
106
|
-
*
|
|
107
|
-
*
|
|
124
|
+
* The pairs whose sentence text changed since the pre-polish artifact the fill map names: a pair is
|
|
125
|
+
* kept unless the same (kind, sentence key, normalized sentence) occurs in that artifact. Only bytes
|
|
126
|
+
* that still hash to the map's `artifact_sha256` narrow the set; otherwise (the report was polished
|
|
127
|
+
* in place, or edited) every pair is kept, so nothing changed escapes the meaning re-check.
|
|
108
128
|
* @param {object[]} pairs extractPairs output on the polished edition
|
|
109
|
-
* @param {string} mapPath
|
|
129
|
+
* @param {string} mapPath fact fill's `<out>.fill-map.json`, or polish-apply's `<out>.polished.fill-map.json`
|
|
130
|
+
* @returns {{ pairs: object[], fill_map: string, narrowed: boolean }}
|
|
110
131
|
*/
|
|
111
132
|
export function pairsChangedSince(pairs, mapPath, ledger, claims) {
|
|
112
|
-
const map =
|
|
113
|
-
if (typeof map.artifact !== "string"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (sha256Of(text) !== map.artifact_sha256)
|
|
133
|
+
const { path, map } = prePolishMap(mapPath)
|
|
134
|
+
if (typeof map.artifact !== "string") throw new CliError(`${path} names no pre-polish artifact`)
|
|
135
|
+
if (typeof map.artifact_sha256 !== "string") throw new CliError(`${path} fill map has no artifact_sha256; --changed-since needs the pre-polish hash`)
|
|
136
|
+
const text = existsSync(map.artifact) ? readText(map.artifact) : null
|
|
137
|
+
if (text === null || sha256Of(text) !== map.artifact_sha256) return { pairs, fill_map: path, narrowed: false }
|
|
117
138
|
const html = map.format === "md" ? markdownAsHtml(text, map.entries, ledger).html : text
|
|
118
139
|
const before = new Map()
|
|
119
140
|
for (const pair of extractPairs(html, ledger, claims)) before.set(pairKey(pair), (before.get(pairKey(pair)) ?? 0) + 1)
|
|
120
|
-
|
|
141
|
+
const kept = pairs.filter((pair) => {
|
|
121
142
|
const left = before.get(pairKey(pair)) ?? 0
|
|
122
143
|
if (left === 0) return true
|
|
123
144
|
before.set(pairKey(pair), left - 1)
|
|
124
145
|
return false
|
|
125
146
|
})
|
|
147
|
+
return { pairs: kept, fill_map: path, narrowed: true }
|
|
126
148
|
}
|
|
127
149
|
|
|
128
150
|
/** @param {string[]} argv the arguments after `fact polish-apply` or `fact polish-diff` */
|