oh-my-opencode 5.1.47 → 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 -259
- package/dist/skills/ulw-research/references/deliverable-phase.md +68 -24
- 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 +14 -6
- 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 +16 -15
- package/dist/skills/ulw-research/scripts/contracts.test.ts +6 -109
- 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-fidelity-policy.test.ts +156 -0
- package/dist/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
- 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 +96 -0
- package/dist/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/dist/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/dist/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/dist/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- 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 +9 -6
- 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 +183 -0
- 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 +6 -560
- package/dist/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
- package/dist/skills/ulw-research/scripts/source-commands.mjs +87 -29
- 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 -259
- package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +68 -24
- 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 +14 -6
- 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 +16 -15
- 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 +96 -0
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- 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 +9 -6
- 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 +183 -0
- 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 +87 -29
- 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 -259
- package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +68 -24
- 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 +14 -6
- 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 +16 -15
- package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -109
- 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-fidelity-policy.test.ts +156 -0
- package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
- 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 +96 -0
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
- package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +40 -62
- 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 +9 -6
- 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 +183 -0
- 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 +6 -560
- 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 +87 -29
- 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
|
@@ -78,7 +78,7 @@ describe("the polish edit contract is polish-apply's", () => {
|
|
|
78
78
|
return "refused"
|
|
79
79
|
}
|
|
80
80
|
})()
|
|
81
|
-
const cli = outcome(() => runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--out", join(dir, "out.html")]))
|
|
81
|
+
const cli = outcome(() => runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--brief", BRIEF, "--out", join(dir, "out.html")]))
|
|
82
82
|
expect(cli === "ok" ? "ok" : "refused").toBe(direct)
|
|
83
83
|
if (cli !== "ok") expect(cli).toContain(editsPath)
|
|
84
84
|
})
|
|
@@ -87,7 +87,7 @@ describe("the polish edit contract is polish-apply's", () => {
|
|
|
87
87
|
|
|
88
88
|
describe("the ledger loader is one shared helper", () => {
|
|
89
89
|
const pairs = (extra: string[]) => () => runFactMeaning("pairs", [reportPath, "--brief", BRIEF, "--out", join(dir, "pairs.json"), ...extra])
|
|
90
|
-
const diff = (extra: string[]) => () => runFactPolish("polish-diff", ["--before", reportPath, "--after", reportPath, ...extra])
|
|
90
|
+
const diff = (extra: string[]) => () => runFactPolish("polish-diff", ["--before", reportPath, "--after", reportPath, "--brief", BRIEF, ...extra])
|
|
91
91
|
|
|
92
92
|
test("#given the command modules #when read #then neither defines its own ledger loader or session resolver", () => {
|
|
93
93
|
expect(polishCommand.ledgerFrom).toBe(ledgerFrom)
|
|
@@ -122,7 +122,7 @@ describe("the edition format comes from verify's grammar", () => {
|
|
|
122
122
|
expect(source("fact-commands-polish.mjs")).not.toMatch(/md\|markdown/u)
|
|
123
123
|
for (const name of ["r.md", "R.MD", "r.markdown", "R.Markdown", "r.html", "r.HTML"]) {
|
|
124
124
|
const path = file(name, readFileSync(reportPath, "utf8"))
|
|
125
|
-
const result = outcome(() => runFactPolish("polish-apply", [path, "--edits", editsPath, "--ledger", ledgerPath, "--out", join(dir, "out.html")]))
|
|
125
|
+
const result = outcome(() => runFactPolish("polish-apply", [path, "--edits", editsPath, "--ledger", ledgerPath, "--brief", BRIEF, "--out", join(dir, "out.html")]))
|
|
126
126
|
expect(result.includes("takes the filled HTML edition"), name).toBe(editionFormatOf(path, undefined) === "md")
|
|
127
127
|
}
|
|
128
128
|
})
|
|
@@ -130,7 +130,7 @@ describe("the edition format comes from verify's grammar", () => {
|
|
|
130
130
|
|
|
131
131
|
describe("polish-diff counts with contracts and exits on blockers only", () => {
|
|
132
132
|
type DiffRun = { exitCode: number; json: { counts: Record<string, number>; defects: { severity: string }[] } }
|
|
133
|
-
const run = (before: string, after: string) => runFactPolish("polish-diff", ["--before", file("b.html", doc(before)), "--after", file("a.html", doc(after)), "--ledger", ledgerPath]) as unknown as DiffRun
|
|
133
|
+
const run = (before: string, after: string) => runFactPolish("polish-diff", ["--before", file("b.html", doc(before)), "--after", file("a.html", doc(after)), "--ledger", ledgerPath, "--brief", BRIEF]) as unknown as DiffRun
|
|
134
134
|
|
|
135
135
|
test("#given every registry code #when polishDiffFails classifies it #then only registry blockers fail", () => {
|
|
136
136
|
for (const [code, entry] of Object.entries(DEFECT_CODES) as [string, { severity: string }][]) expect(polishDiffFails([{ code, severity: "minor" }]), code).toBe(entry.severity === "blocker")
|
|
@@ -161,7 +161,7 @@ describe("fact polish-apply prints every rejection reason verbatim", () => {
|
|
|
161
161
|
test("#given an edit holding & #when fact polish-apply runs #then the printed line carries polish-apply's own markup reason", () => {
|
|
162
162
|
const before = "Revenue & profit rose across the year"
|
|
163
163
|
const editsPath = file("edits-markup-ampersand.json", JSON.stringify([{ before, after: "Revenue and profit rose across the year", reason: "wording" }]))
|
|
164
|
-
const run = runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--out", join(dir, "ampersand.html")]) as unknown as ApplyRun
|
|
164
|
+
const run = runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--brief", BRIEF, "--out", join(dir, "ampersand.html")]) as unknown as ApplyRun
|
|
165
165
|
|
|
166
166
|
expect(run.exitCode).toBe(0)
|
|
167
167
|
expect(run.json.data.rejected).toBe(1)
|
|
@@ -173,7 +173,7 @@ describe("fact polish-apply prints every rejection reason verbatim", () => {
|
|
|
173
173
|
})
|
|
174
174
|
|
|
175
175
|
describe("--changed-since stays fail-closed", () => {
|
|
176
|
-
const { pairsChangedSince } = polishCommand as unknown as { pairsChangedSince: (pairs: unknown[], mapPath: string, ledger: unknown, claims: unknown) => unknown
|
|
176
|
+
const { pairsChangedSince } = polishCommand as unknown as { pairsChangedSince: (pairs: unknown[], mapPath: string, ledger: unknown, claims: unknown) => unknown }
|
|
177
177
|
const artifact = file("pre-polish.html", doc("<p>The span is 320 m [S1].</p>"))
|
|
178
178
|
|
|
179
179
|
test("#given a fill map without artifact_sha256 #when --changed-since reads it #then it refuses", () => {
|
|
@@ -181,9 +181,10 @@ describe("--changed-since stays fail-closed", () => {
|
|
|
181
181
|
expect(outcome(() => pairsChangedSince([], mapPath, LEDGER, null))).toContain("fill map has no artifact_sha256")
|
|
182
182
|
})
|
|
183
183
|
|
|
184
|
-
test("#given a fill map whose artifact changed since fill #when read #then
|
|
184
|
+
test("#given a fill map whose artifact changed since fill #when read #then nothing is filtered out: every pair is re-checked", () => {
|
|
185
185
|
const mapPath = file("fill-map-stale.json", JSON.stringify({ artifact, artifact_sha256: "0".repeat(64), format: "html", entries: [] }))
|
|
186
|
-
|
|
186
|
+
const pairs = [{ kind: "quote", sentence_key: "s1", claim_id: null, sentence: "The span is 320 m [S1]." }]
|
|
187
|
+
expect(pairsChangedSince(pairs, mapPath, LEDGER, null)).toEqual({ pairs, fill_map: mapPath, narrowed: false })
|
|
187
188
|
})
|
|
188
189
|
})
|
|
189
190
|
|
|
@@ -203,7 +204,7 @@ describe("polish-apply writes atomically and honours --format", () => {
|
|
|
203
204
|
|
|
204
205
|
test("#given --format md on an .html report #when polish-apply runs #then it refuses the Markdown edition", () => {
|
|
205
206
|
const editsPath = file("edits-format.json", "[]")
|
|
206
|
-
const result = outcome(() => runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--out", join(dir, "fmt.html"), "--format", "md"]))
|
|
207
|
+
const result = outcome(() => runFactPolish("polish-apply", [reportPath, "--edits", editsPath, "--ledger", ledgerPath, "--brief", BRIEF, "--out", join(dir, "fmt.html"), "--format", "md"]))
|
|
207
208
|
expect(result).toContain("takes the filled HTML edition")
|
|
208
209
|
})
|
|
209
210
|
})
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// css-hiding.mjs - whether CSS hides an element of a page from every reader, from its inline style and
|
|
2
|
+
// the page's own <style> rules (external stylesheets and scripts are not evaluated).
|
|
3
|
+
//
|
|
4
|
+
// Text counts as reader-visible when it is visible under at least one condition. So a rule can hide
|
|
5
|
+
// only when it certainly applies: it sits outside every at-rule except @layer (and @media all), its
|
|
6
|
+
// <style> element applies everywhere (no media other than all, CSS type, not in <noscript>), and its
|
|
7
|
+
// selector is one tag (case-insensitive), one .class or one #id (case-sensitive). A rule that only
|
|
8
|
+
// might apply (inside @media, @supports, @container, @scope, @starting-style, @document, @keyframes,
|
|
9
|
+
// nested in another style rule, or with a compound, combinator, attribute or pseudo-class selector)
|
|
10
|
+
// never hides, but it can make text visible when its subject could match and it outranks the hiding
|
|
11
|
+
// declaration in the cascade (origin and importance, inline style, layer order, specificity, order).
|
|
12
|
+
// Hiding properties: display:none and content-visibility:hidden remove the subtree;
|
|
13
|
+
// visibility:hidden|collapse is inherited and a descendant's visibility:visible shows it again.
|
|
14
|
+
// The hidden attribute (except hidden="until-found") and a closed <dialog> are the user-agent
|
|
15
|
+
// display:none, which any author display declaration overrides. opacity, clip, zero size, font-size,
|
|
16
|
+
// off-screen positions and colors do not hide: the text still renders or is read aloud.
|
|
17
|
+
// Plain Node ESM, sibling imports only.
|
|
18
|
+
|
|
19
|
+
import { scanRules } from "./css-lite.mjs"
|
|
20
|
+
|
|
21
|
+
const PROPS = new Set(["display", "visibility", "content-visibility"])
|
|
22
|
+
const INHERITED = new Set(["inherit", "unset", "revert", "revert-layer"])
|
|
23
|
+
const IMPORTANT = /!\s*important\s*$/i
|
|
24
|
+
const SIMPLE = /^(?:[.#][^\s.#:[\]>+~,()*"'\\]+|[a-z][a-z0-9-]*)$/iu
|
|
25
|
+
const PSEUDO_ELEMENT = /::|:(?:before|after|first-line|first-letter)\b/i
|
|
26
|
+
const NAME = "[^\\s.#:[\\]>+~,()*\"'\\\\]+"
|
|
27
|
+
const STYLE_IN_SVG = /<style\b[^>]*>([\s\S]*?)<\/style\s*>/gi
|
|
28
|
+
|
|
29
|
+
/** [tier (0 user agent, 1 author, 2 author !important), inline, layer, specificity, order]: higher wins. */
|
|
30
|
+
const outranks = (a, b) => {
|
|
31
|
+
for (let k = 0; k < a.length; k++) if (a[k] !== b[k]) return a[k] > b[k]
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function specificity(selector) {
|
|
36
|
+
const core = selector.replace(/\[[^\]]*\]/g, " [] ")
|
|
37
|
+
const ids = core.match(new RegExp(`#${NAME}`, "gu"))?.length ?? 0
|
|
38
|
+
const classes = (core.match(new RegExp(`\\.${NAME}`, "gu"))?.length ?? 0) + (core.match(/\[\]|:(?!:)[\w-]+/g)?.length ?? 0)
|
|
39
|
+
const tags = core.match(/(?:^|[\s>+~(])[a-z][\w-]*/gi)?.length ?? 0
|
|
40
|
+
return ids * 10000 + classes * 100 + tags
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The subject compound of a selector: its tag, classes and ids (attribute and pseudo-class parts dropped). */
|
|
44
|
+
function subject(selector) {
|
|
45
|
+
const compound = selector.trim().match(/(?:[^\s>+~[\]()]|\[[^\]]*\]|\([^)]*\))+$/)?.[0] ?? ""
|
|
46
|
+
const core = compound.replace(/\([^)]*\)/g, "").replace(/\[[^\]]*\]/g, "").replace(/:+[\w-]+/g, "")
|
|
47
|
+
const tag = core.match(/^[a-z][a-z0-9-]*/i)?.[0].toLowerCase() ?? null
|
|
48
|
+
const classes = [...core.matchAll(new RegExp(`\\.(${NAME})`, "gu"))].map((match) => match[1])
|
|
49
|
+
const ids = [...core.matchAll(new RegExp(`#(${NAME})`, "gu"))].map((match) => match[1])
|
|
50
|
+
return { tag, classes, ids, key: ids[0] ? `#${ids[0]}` : classes[0] ? `.${classes[0]}` : tag ?? "*" }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const classList = (node) => String(node.attrs?.class ?? "").split(/[ \t\n\f\r]+/).filter(Boolean)
|
|
54
|
+
|
|
55
|
+
function matches(sub, node) {
|
|
56
|
+
if (sub.tag !== null && sub.tag !== node.tag) return false
|
|
57
|
+
const names = classList(node)
|
|
58
|
+
return sub.classes.every((name) => names.includes(name)) && sub.ids.every((id) => id === node.attrs?.id)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Whether every enclosing at-rule leaves the rule unconditional (@layer, @media all), its layer name, and keyframe steps. */
|
|
62
|
+
function context(atRule) {
|
|
63
|
+
const entries = atRule ? atRule.split(/\s(?=@)/) : []
|
|
64
|
+
const layers = entries.filter((entry) => /^@layer\b/i.test(entry)).map((entry) => entry.slice(6).trim())
|
|
65
|
+
const conditional = entries.some((entry) => !/^@layer\b/i.test(entry) && !/^@media(?:\s+all)?\s*$/i.test(entry))
|
|
66
|
+
return { conditional, layer: layers.length ? layers.join(".") : null, keyframe: entries.some((entry) => /^@(?:-[a-z]+-)?keyframes\b/i.test(entry)) }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const declaration = (value) => ({ value: value.replace(IMPORTANT, "").trim().toLowerCase(), important: IMPORTANT.test(value) })
|
|
70
|
+
|
|
71
|
+
/** Every <style> text that applies to the page, with whether it applies only under a condition. */
|
|
72
|
+
function sheets(root) {
|
|
73
|
+
const found = []
|
|
74
|
+
const visit = (node, conditional) => {
|
|
75
|
+
if (node.tag === "template") return
|
|
76
|
+
const inner = conditional || node.tag === "noscript"
|
|
77
|
+
if (node.tag === "style") {
|
|
78
|
+
const type = String(node.attrs?.type ?? "").trim().toLowerCase()
|
|
79
|
+
const media = String(node.attrs?.media ?? "").trim().toLowerCase()
|
|
80
|
+
if (type === "" || type === "text/css") found.push({ css: String(node.raw ?? ""), conditional: inner || (media !== "" && media !== "all") })
|
|
81
|
+
}
|
|
82
|
+
if (node.tag === "svg") for (const match of String(node.raw ?? "").matchAll(STYLE_IN_SVG)) found.push({ css: match[1], conditional: inner })
|
|
83
|
+
for (const child of node.children ?? []) visit(child, inner)
|
|
84
|
+
}
|
|
85
|
+
visit(root, false)
|
|
86
|
+
return found
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Index every rule declaring display, visibility or content-visibility by its subject key. */
|
|
90
|
+
function indexRules(root) {
|
|
91
|
+
const index = new Map()
|
|
92
|
+
const layers = []
|
|
93
|
+
const layerRank = (name, important) => {
|
|
94
|
+
if (name === null) return important ? -1 : 1e6
|
|
95
|
+
if (!layers.includes(name)) layers.push(name)
|
|
96
|
+
return important ? 1e6 - layers.indexOf(name) : layers.indexOf(name)
|
|
97
|
+
}
|
|
98
|
+
let order = 0
|
|
99
|
+
for (const sheet of sheets(root)) {
|
|
100
|
+
const css = sheet.css.replace(/<!--|-->/g, " ")
|
|
101
|
+
for (const match of css.replace(/\/\*[\s\S]*?(?:\*\/|$)/g, "").matchAll(/@layer\s+([^{;]*)[{;]/gi)) {
|
|
102
|
+
for (const name of match[1].split(",").map((part) => part.trim())) if (name && !layers.includes(name)) layers.push(name)
|
|
103
|
+
}
|
|
104
|
+
for (const rule of scanRules(css)) {
|
|
105
|
+
const decls = rule.declarations.filter((entry) => PROPS.has(entry.prop))
|
|
106
|
+
if (!decls.length || rule.selector.startsWith("@")) continue
|
|
107
|
+
const { conditional, layer, keyframe } = context(rule.atRule)
|
|
108
|
+
if (keyframe) continue
|
|
109
|
+
for (const selector of rule.selector.split(/,(?![^()[\]]*[)\]])/).map((part) => part.trim())) {
|
|
110
|
+
if (!selector || PSEUDO_ELEMENT.test(selector)) continue
|
|
111
|
+
const sub = subject(selector)
|
|
112
|
+
const certain = !sheet.conditional && !conditional && !rule.nested && SIMPLE.test(selector)
|
|
113
|
+
const spec = specificity(selector)
|
|
114
|
+
for (const entry of decls) {
|
|
115
|
+
const { value, important } = declaration(entry.value)
|
|
116
|
+
const rank = [important ? 2 : 1, 0, layerRank(layer, important), spec, order++]
|
|
117
|
+
if (!index.has(sub.key)) index.set(sub.key, [])
|
|
118
|
+
index.get(sub.key).push({ sub, prop: entry.prop, value, rank, certain })
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return index
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** The values a property can take on the element: the certain winner, plus every possible rule that outranks it. */
|
|
127
|
+
function possible(candidates, prop) {
|
|
128
|
+
let top = null
|
|
129
|
+
for (const entry of candidates) if (entry.prop === prop && entry.certain && (top === null || outranks(entry.rank, top.rank))) top = entry
|
|
130
|
+
const values = [top === null ? "unset" : top.value]
|
|
131
|
+
for (const entry of candidates) if (entry.prop === prop && !entry.certain && (top === null || outranks(entry.rank, top.rank))) values.push(entry.value)
|
|
132
|
+
return values
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* cssVisibility(root) -> (node, parentShown) => null when CSS removes the element and its subtree from every
|
|
137
|
+
* rendering, else whether its own text can be seen (visibility, inherited from parentShown).
|
|
138
|
+
*/
|
|
139
|
+
export function cssVisibility(root) {
|
|
140
|
+
const index = indexRules(root)
|
|
141
|
+
return (node, parentShown) => {
|
|
142
|
+
const attrs = node.attrs ?? {}
|
|
143
|
+
const keys = ["*", node.tag, ...classList(node).map((name) => `.${name}`), attrs.id === undefined ? null : `#${attrs.id}`]
|
|
144
|
+
const candidates = []
|
|
145
|
+
for (const key of new Set(keys)) for (const entry of index.get(key) ?? []) if (matches(entry.sub, node)) candidates.push(entry)
|
|
146
|
+
const hiddenAttr = attrs.hidden !== undefined && String(attrs.hidden).trim().toLowerCase() !== "until-found"
|
|
147
|
+
if (hiddenAttr || (node.tag === "dialog" && attrs.open === undefined)) candidates.push({ prop: "display", value: "none", rank: [0, 0, 0, 0, -1], certain: true })
|
|
148
|
+
const inline = attrs.style ? (scanRules(`x{${attrs.style}}`)[0]?.declarations ?? []) : []
|
|
149
|
+
inline.forEach((entry, at) => {
|
|
150
|
+
if (!PROPS.has(entry.prop)) return
|
|
151
|
+
const { value, important } = declaration(entry.value)
|
|
152
|
+
candidates.push({ prop: entry.prop, value, rank: [important ? 2 : 1, 1, 0, 0, at], certain: true })
|
|
153
|
+
})
|
|
154
|
+
if (possible(candidates, "display").every((value) => value === "none")) return null
|
|
155
|
+
if (possible(candidates, "content-visibility").every((value) => value === "hidden")) return null
|
|
156
|
+
return possible(candidates, "visibility").some((value) => (INHERITED.has(value) ? parentShown : value !== "hidden" && value !== "collapse"))
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -57,8 +57,9 @@ function parseDeclarations(text) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* @returns {{ selector: string, declarations: { prop: string, value: string }[], atRule?: string }[]}
|
|
61
|
-
* atRule is the chain of enclosing grouping at-rule preludes joined by a space
|
|
60
|
+
* @returns {{ selector: string, declarations: { prop: string, value: string }[], atRule?: string, nested?: true }[]}
|
|
61
|
+
* atRule is the chain of enclosing grouping at-rule preludes joined by a space; nested is true for a
|
|
62
|
+
* rule written inside another style rule (CSS nesting).
|
|
62
63
|
*/
|
|
63
64
|
export function scanRules(css) {
|
|
64
65
|
if (typeof css !== "string") return []
|
|
@@ -88,6 +89,7 @@ export function scanRules(css) {
|
|
|
88
89
|
const atChain = stack.filter((entry) => entry.group).map((entry) => entry.prelude)
|
|
89
90
|
const rule = { selector: frame.prelude, declarations: parseDeclarations(frame.body + buffer) }
|
|
90
91
|
if (atChain.length) rule.atRule = atChain.join(" ")
|
|
92
|
+
if (stack.some((entry) => !entry.group)) rule.nested = true
|
|
91
93
|
slots[frame.slot] = rule
|
|
92
94
|
}
|
|
93
95
|
buffer = ""
|
|
@@ -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
|
-
})
|