clearotron 0.2.1 → 0.2.3
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/.env.example +82 -1
- package/.nvmrc +1 -1
- package/CONTRIBUTING.md +3 -3
- package/INSTALL.md +64 -58
- package/README.md +11 -16
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/bin/brandowner.mjs +1 -1
- package/bin/clearotron.mjs +26 -4
- package/bin/connect.mjs +2 -2
- package/bin/example.mjs +31 -11
- package/bin/grant.mjs +3 -3
- package/bin/key.mjs +1 -1
- package/bin/onboard.mjs +252 -136
- package/bin/start.mjs +176 -33
- package/bin/stop.mjs +65 -3
- package/bin/update.mjs +7 -7
- package/bin/uspto-sync.mjs +1 -1
- package/build-info.json +2 -2
- package/demo/full-country-search/run/_driver/framework.json +1 -1
- package/demo/global-preliminary-search/run/_driver/framework.json +1 -1
- package/demo/knockout-search/run/_driver/framework.json +1 -1
- package/demo/multi-country-focus-search/run/_driver/framework.json +1 -1
- package/docs/DELIVERY.md +6 -2
- package/docs/E2E.md +5 -5
- package/docs/PORTAL.md +2 -2
- package/docs/README.md +5 -4
- package/docs/SECURITY.md +17 -0
- package/docs/architecture/01-product-overview.md +2 -2
- package/docs/architecture/02-architecture.md +2 -2
- package/docs/architecture/04-configuration-reference.md +8 -3
- package/docs/architecture/05-config-governance.md +52 -5
- package/docs/architecture/05-customer-profiles.md +2 -2
- package/docs/architecture/06-operations-runbook.md +13 -1
- package/docs/architecture/09-security-and-data.md +1 -1
- package/docs/configuration.md +4 -3
- package/docs/decisions/0004-documentation-structure.md +1 -1
- package/driver/CHANGELOG.md +121 -1
- package/driver/README.md +2 -2
- package/driver/ask-ledger.mjs +3 -3
- package/driver/authority-trees.mjs +1 -1
- package/driver/call-capture.mjs +1 -1
- package/driver/card-frame.mjs +1 -1
- package/driver/case-law-ledger.mjs +1 -1
- package/driver/claim-liveness.mjs +1 -1
- package/driver/common-law-receipts.mjs +2 -2
- package/driver/commonlaw-carry.mjs +1 -1
- package/driver/config-inventory.mjs +1 -1
- package/driver/config-staleness.mjs +1 -1
- package/driver/connotation-search.mjs +12 -12
- package/driver/contract-audit.mjs +5 -5
- package/driver/contract-dictation-registry.mjs +4 -4
- package/driver/contract-dictation.mjs +2 -2
- package/driver/contract-e3-backlog.mjs +6 -6
- package/driver/contract-vocabulary.mjs +3 -3
- package/driver/corrections-feedforward.mjs +1 -1
- package/driver/coverage-form-io.mjs +2 -2
- package/driver/coverage-form.mjs +4 -4
- package/driver/coverage-ledger.mjs +3 -3
- package/driver/coverage-union.mjs +1 -1
- package/driver/declination-call.mjs +35 -3
- package/driver/declination-duty.mjs +1 -1
- package/driver/deliver-trigger.sh +3 -3
- package/driver/deploy-live-run-guard.mjs +6 -2
- package/driver/dev-portal.mjs +3 -3
- package/driver/disposition-call.mjs +4 -4
- package/driver/disposition-tool.mjs +4 -4
- package/driver/disposition-union.mjs +2 -2
- package/driver/doc-constants.mjs +1 -1
- package/driver/door-gates.mjs +2 -2
- package/driver/doubt-selection.mjs +2 -2
- package/driver/drainer-identity.mjs +1 -1
- package/driver/driver.config.mjs +64 -12
- package/driver/e2e-rounds.mjs +2 -2
- package/driver/effort-model.mjs +2 -2
- package/driver/engine/anthropic-agent.mjs +24 -24
- package/driver/engine/auth.mjs +1 -1
- package/driver/engine/cli-version.mjs +103 -0
- package/driver/engine/common.mjs +1 -1
- package/driver/engine/deny-authority-write.mjs +1 -1
- package/driver/engine/jx-turn.mjs +1 -1
- package/driver/engine/mcp/clarivate-server.mjs +1 -1
- package/driver/engine/mcp/corsearch-server.mjs +1 -1
- package/driver/engine/mcp/declination-server.mjs +1 -1
- package/driver/engine/mcp/dispositions-server.mjs +1 -1
- package/driver/engine/mcp/euipo-server.mjs +1 -1
- package/driver/engine/mcp/fetch-server.mjs +1 -1
- package/driver/engine/mcp/free-tier-server.mjs +2 -2
- package/driver/engine/mcp/gather-config.mjs +11 -11
- package/driver/engine/mcp/perplexity-server.mjs +1 -1
- package/driver/engine/mcp/recording-server.mjs +8 -4
- package/driver/engine/mcp/signa-server.mjs +1 -1
- package/driver/engine/mcp/uspto-local-server.mjs +1 -1
- package/driver/engine/openai-agent.mjs +2 -2
- package/driver/engine-build.mjs +2 -2
- package/driver/enqueue-schema.mjs +10 -10
- package/driver/enqueue.mjs +1 -1
- package/driver/envelope-settle.mjs +1 -1
- package/driver/evidence-claim-invariant.mjs +2 -2
- package/driver/feedback-store.mjs +1 -1
- package/driver/findings-model.mjs +60 -10
- package/driver/flag-snapshot.mjs +20 -0
- package/driver/floor-duty.mjs +1 -1
- package/driver/form-neighbourhood.mjs +1 -1
- package/driver/framework.mjs +2 -2
- package/driver/gateway.mjs +45 -23
- package/driver/grounds-grammar.mjs +1 -1
- package/driver/hit-list.mjs +1 -1
- package/driver/jurisdiction-systems.mjs +1 -1
- package/driver/jx-lanes.mjs +1 -1
- package/driver/jx-units.mjs +1 -1
- package/driver/jx.mjs +3 -3
- package/driver/knockout-assess-record.mjs +5 -1
- package/driver/narrative-refutation-record.mjs +3 -3
- package/driver/numeric-setting.mjs +1 -1
- package/driver/owner-use-check.mjs +184 -0
- package/driver/package.json +4 -4
- package/driver/party-facts.mjs +2 -2
- package/driver/phase0.mjs +2 -2
- package/driver/pipeline-knockout.mjs +52 -4
- package/driver/pipeline.mjs +180 -67
- package/driver/placement-diff.mjs +2 -2
- package/driver/placement-form.mjs +4 -4
- package/driver/placement-union.mjs +1 -1
- package/driver/plain-register.mjs +120 -0
- package/driver/portal-access.mjs +1 -1
- package/driver/portal-acks.mjs +1 -1
- package/driver/portal-config-view.mjs +42 -3
- package/driver/portal-families.mjs +1 -1
- package/driver/portal-local-auth.mjs +1 -1
- package/driver/portal-report.mjs +7 -7
- package/driver/portal-service.mjs +41 -22
- package/driver/portal-upstream.mjs +2 -2
- package/driver/predelivery-lint.mjs +149 -11
- package/driver/prelim-variants-record.mjs +2 -2
- package/driver/profile-page.html +11 -3
- package/driver/profile-selection.mjs +1 -1
- package/driver/profile-service.mjs +6 -6
- package/driver/profiles/README.md +3 -3
- package/driver/profiles.mjs +145 -13
- package/driver/progress.mjs +6 -6
- package/driver/provider-usage.mjs +1 -1
- package/driver/publish/demo-marking.mjs +1 -1
- package/driver/publish/index.mjs +49 -8
- package/driver/publish/knockout.mjs +42 -14
- package/driver/publish/parse.mjs +4 -4
- package/driver/publish/publish-inputs.mjs +2 -2
- package/driver/publish/register-presence.mjs +1 -1
- package/driver/publish/render-knockout.mjs +646 -144
- package/driver/publish/render.mjs +2 -2
- package/driver/publish/report-data.mjs +13 -3
- package/driver/queue-watch-probe.mjs +1 -1
- package/driver/queue-watch-verdict.mjs +1 -1
- package/driver/recall-reconciliation.mjs +1 -1
- package/driver/recipe-service.mjs +1 -1
- package/driver/record-carry.mjs +5 -5
- package/driver/recording-agreement.mjs +3 -3
- package/driver/reference-score.mjs +7 -7
- package/driver/reference-strip-signatures.mjs +20 -0
- package/driver/refusal-bound.mjs +3 -3
- package/driver/register-availability.mjs +2 -2
- package/driver/register-count.mjs +1 -1
- package/driver/register-grant-vocabulary.mjs +2 -2
- package/driver/register-plan.mjs +8 -8
- package/driver/register-records.mjs +2 -2
- package/driver/registry-fidelity.mjs +3 -3
- package/driver/remedy-accounting.mjs +1 -1
- package/driver/repair-composers.mjs +2 -2
- package/driver/repair-digest.mjs +3 -3
- package/driver/repairs.mjs +6 -6
- package/driver/replay-archive.mjs +2 -0
- package/driver/report-card-record.mjs +2 -2
- package/driver/result-noun-fields.mjs +10 -3
- package/driver/run-economics.mjs +2 -2
- package/driver/run-integrity.mjs +1 -1
- package/driver/runner.mjs +22 -22
- package/driver/scope-rules.mjs +1 -1
- package/driver/search-policy.mjs +5 -5
- package/driver/skeptic-search.mjs +1 -1
- package/driver/skills/blind-frame/SKILL.md +2 -2
- package/driver/skills/case-law-citation/SKILL.md +2 -2
- package/driver/skills/knockout-assess/SKILL.md +94 -4
- package/driver/skills/matter-frame/SKILL.md +6 -6
- package/driver/skills/matter-frame/watchlist-reference.md +2 -2
- package/driver/skills/prelim-common-law/SKILL.md +1 -1
- package/driver/skills/prelim-search/SKILL.md +3 -3
- package/driver/skills/prelim-search/report-prose.md +82 -0
- package/driver/skills/prelim-search/risk-framework-demo.manifest.json +1 -1
- package/driver/skills/prelim-search/risk-framework-triage.manifest.json +1 -1
- package/driver/skills/prelim-search/risk-framework.manifest.json +1 -1
- package/driver/skills/prelim-search/synthesis-rules.md +1 -1
- package/driver/skills/prelim-search/template-formatting.md +1 -1
- package/driver/skills/prelim-search/templates/email/generic.md +1 -1
- package/driver/skills/prelim-search/worked-examples.md +1 -1
- package/driver/skills/prelim-variants/SKILL.md +5 -5
- package/driver/stage-context.mjs +1 -1
- package/driver/stages-knockout.mjs +55 -4
- package/driver/stages.mjs +101 -44
- package/driver/stray-artifacts.mjs +2 -2
- package/driver/suite-census.json +275 -65
- package/driver/synthesis-record.mjs +1 -1
- package/driver/systemd/clearotron-client-mcp.service +1 -1
- package/driver/systemd/clearotron-portal.service +1 -1
- package/driver/systemd/render-units.mjs +1 -1
- package/driver/tokens.mjs +1 -1
- package/driver/tool-calls.mjs +1 -1
- package/driver/turnaround-bands.mjs +1 -1
- package/driver/unit-file-drift.mjs +1 -1
- package/driver/unit-inventory.mjs +297 -80
- package/driver/unit-state-verdict.mjs +20 -12
- package/driver/verify-knockout.mjs +10 -2
- package/driver/verify.mjs +13 -13
- package/driver/whatif-memo-run.mjs +72 -9
- package/driver/whatif-memo.mjs +19 -1
- package/driver/whatif-queue.mjs +1 -1
- package/driver/whatif-worker.mjs +1 -1
- package/examples/README.md +2 -2
- package/examples/grants.example.json +6 -7
- package/mcp-server/CHANGELOG.md +6 -0
- package/mcp-server/README.md +3 -3
- package/mcp-server/http-server.mjs +44 -1
- package/mcp-server/key-socket.mjs +184 -0
- package/mcp-server/lib/audit-view.mjs +69 -2
- package/mcp-server/lib/brief.mjs +15 -0
- package/mcp-server/lib/driver.mjs +7 -1
- package/mcp-server/lib/events.mjs +1 -1
- package/mcp-server/lib/http-handler.mjs +1 -1
- package/mcp-server/lib/knockout.mjs +435 -0
- package/mcp-server/lib/ops.mjs +4 -4
- package/mcp-server/lib/options.mjs +1 -1
- package/mcp-server/lib/plan.mjs +1 -1
- package/mcp-server/lib/runs.mjs +1 -1
- package/mcp-server/lib/scrub.mjs +2 -2
- package/mcp-server/lib/whatif.mjs +5 -5
- package/mcp-server/mint-token.mjs +1 -1
- package/mcp-server/package.json +2 -2
- package/mcp-server/packs/ops/EXAMPLES.md +2 -2
- package/mcp-server/server.mjs +77 -12
- package/package.json +30 -12
- package/portal-ui/dist/assets/{index-Ct3iQtZ2.css → index-1ziUJX1E.css} +43 -2
- package/portal-ui/dist/assets/{index-BUGgiYtF.js → index-CEYvXdqH.js} +226 -49
- package/portal-ui/dist/index.html +2 -2
- package/portal-ui/package.json +1 -1
- package/providers/_shared/enumerate.mjs +1 -1
- package/providers/_shared/ledger-path.mjs +3 -3
- package/providers/_shared/ledger.mjs +1 -1
- package/providers/_shared/result-shape.mjs +3 -3
- package/providers/_shared/term-shape.mjs +2 -2
- package/providers/corsearch/src/core.js +1 -1
- package/providers/jx-subclass/BUILDING.md +1 -1
- package/providers/oauth-mcp-bridge/CHANGELOG.md +6 -0
- package/providers/oauth-mcp-bridge/package.json +1 -1
- package/providers/oauth-mcp-bridge/stdin-guard.mjs +2 -2
- package/providers/uspto-local/src/index-store.js +2 -2
- package/scripts/README.md +1 -1
- package/scripts/added-reference-check.mjs +29 -1
- package/scripts/authority-boundary-probe.mjs +1 -1
- package/scripts/backfill-started-at.mjs +1 -1
- package/scripts/citation-line-check.mjs +124 -5
- package/scripts/compare.mjs +2 -2
- package/scripts/contract-dictation-scan.mjs +2 -2
- package/scripts/dead-names.mjs +1 -1
- package/scripts/drain-preflight.mjs +5 -5
- package/scripts/e2e-unread-terminals.mjs +1 -1
- package/scripts/e2e.mjs +8 -8
- package/scripts/env-audit.mjs +7 -7
- package/scripts/env-classify.mjs +206 -18
- package/scripts/freeze-example-run.mjs +3 -3
- package/scripts/head-arrived-gated.mjs +1 -1
- package/scripts/headless-page.mjs +51 -2
- package/scripts/live-surface-check.mjs +129 -19
- package/scripts/main-health.mjs +1 -1
- package/scripts/merge-presence-check.mjs +3 -3
- package/scripts/mint-suite-census.mjs +6 -6
- package/scripts/nightly-notice.mjs +1 -3
- package/scripts/preinstall-node-check.mjs +24 -0
- package/scripts/reconcile-runs.mjs +1 -1
- package/scripts/release-await-cut.mjs +6 -4
- package/scripts/release-version-pr-checks.mjs +1 -1
- package/scripts/release-version.mjs +2 -2
- package/scripts/render-check.mjs +66 -7
- package/scripts/report-frame-check.mjs +1 -1
- package/scripts/report-screenshot.mjs +1 -1
- package/scripts/revisit-render-check.mjs +1 -1
- package/scripts/score.mjs +4 -4
- package/scripts/strip-tracker-citations.mjs +139 -0
- package/scripts/test-run.mjs +19 -3
- package/scripts/third-party-notices.mjs +3 -3
- package/scripts/travelling-predicates.mjs +3 -3
- package/scripts/unexecuted-asserts.mjs +2 -2
- package/scripts/verify-publishable.mjs +2 -2
- package/scripts/write-up-form-census.mjs +1 -1
- package/shared/access-audience.mjs +1 -1
- package/shared/anon-overlay.mjs +3 -3
- package/shared/brand.mjs +13 -13
- package/shared/citation-scan.mjs +1 -1
- package/shared/client-door.mjs +7 -7
- package/shared/customer-store.mjs +1 -1
- package/shared/driver-dir.mjs +1 -1
- package/shared/env-aliases.mjs +0 -48
- package/shared/env-local.mjs +1 -1
- package/shared/identifier-scan.mjs +3 -3
- package/shared/invocation.mjs +29 -1
- package/shared/names-in-force.mjs +4 -0
- package/shared/node-floor.mjs +97 -0
- package/shared/product-owned-names.mjs +1 -1
- package/shared/register-selection.mjs +1 -1
- package/shared/scope.mjs +5 -5
- package/shared/server-units.mjs +4 -4
- package/shared/staff-domain.mjs +154 -0
- package/shared/store-in-repo.mjs +25 -4
- package/shared/suite-census.mjs +4 -4
- package/shared/tty-style.mjs +1 -1
- package/shared/uspto-index-size.mjs +1 -1
- package/shared/vacuous-pass.mjs +1 -1
- package/skills/clearotron-account/SKILL.md +42 -13
- package/skills/clearotron-ops/SKILL.md +1 -1
- package/driver/recipes/README.md +0 -49
- package/driver/skills/prelim-search/risk-framework-aurora.manifest.json +0 -19
- package/driver/skills/prelim-search/risk-framework-aurora.md +0 -77
- package/driver/skills/prelim-search/risk-framework-zephyr.manifest.json +0 -14
- package/driver/skills/prelim-search/risk-framework-zephyr.md +0 -33
- package/driver/skills/prelim-search/worked-examples-aurora.md +0 -10
- package/driver/skills/prelim-search/worked-examples-zephyr.md +0 -10
- package/driver/systemd/prelim-driver.path +0 -69
- package/driver/systemd/prelim-driver.service +0 -86
- package/driver/systemd/prelim-driver.timer +0 -14
- package/driver/systemd/prelim-outbox.path +0 -27
- package/driver/systemd/prelim-outbox.service +0 -37
- package/driver/systemd/prelim-outbox.timer +0 -21
- package/node_modules/exceljs/README_zh.md +0 -2878
- package/node_modules/exceljs/dist/LICENSE +0 -22
- package/node_modules/exceljs/dist/es5/csv/csv.js +0 -182
- package/node_modules/exceljs/dist/es5/csv/csv.js.map +0 -1
- package/node_modules/exceljs/dist/es5/csv/line-buffer.js +0 -68
- package/node_modules/exceljs/dist/es5/csv/line-buffer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/csv/stream-converter.js +0 -110
- package/node_modules/exceljs/dist/es5/csv/stream-converter.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/anchor.js +0 -73
- package/node_modules/exceljs/dist/es5/doc/anchor.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/cell.js +0 -961
- package/node_modules/exceljs/dist/es5/doc/cell.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/column.js +0 -274
- package/node_modules/exceljs/dist/es5/doc/column.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/data-validations.js +0 -18
- package/node_modules/exceljs/dist/es5/doc/data-validations.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/defined-names.js +0 -173
- package/node_modules/exceljs/dist/es5/doc/defined-names.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/enums.js +0 -49
- package/node_modules/exceljs/dist/es5/doc/enums.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/image.js +0 -69
- package/node_modules/exceljs/dist/es5/doc/image.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/modelcontainer.js +0 -16
- package/node_modules/exceljs/dist/es5/doc/modelcontainer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/note.js +0 -64
- package/node_modules/exceljs/dist/es5/doc/note.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/range.js +0 -229
- package/node_modules/exceljs/dist/es5/doc/range.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/row.js +0 -382
- package/node_modules/exceljs/dist/es5/doc/row.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/table.js +0 -443
- package/node_modules/exceljs/dist/es5/doc/table.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/workbook.js +0 -202
- package/node_modules/exceljs/dist/es5/doc/workbook.js.map +0 -1
- package/node_modules/exceljs/dist/es5/doc/worksheet.js +0 -900
- package/node_modules/exceljs/dist/es5/doc/worksheet.js.map +0 -1
- package/node_modules/exceljs/dist/es5/exceljs.bare.js +0 -14
- package/node_modules/exceljs/dist/es5/exceljs.bare.js.map +0 -1
- package/node_modules/exceljs/dist/es5/exceljs.browser.js +0 -36
- package/node_modules/exceljs/dist/es5/exceljs.browser.js.map +0 -1
- package/node_modules/exceljs/dist/es5/exceljs.nodejs.js +0 -15
- package/node_modules/exceljs/dist/es5/exceljs.nodejs.js.map +0 -1
- package/node_modules/exceljs/dist/es5/index.js +0 -15
- package/node_modules/exceljs/dist/es5/stream/xlsx/hyperlink-reader.js +0 -90
- package/node_modules/exceljs/dist/es5/stream/xlsx/hyperlink-reader.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-comments-writer.js +0 -94
- package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-comments-writer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-rels-writer.js +0 -94
- package/node_modules/exceljs/dist/es5/stream/xlsx/sheet-rels-writer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-reader.js +0 -362
- package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-reader.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-writer.js +0 -347
- package/node_modules/exceljs/dist/es5/stream/xlsx/workbook-writer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-reader.js +0 -392
- package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-reader.js.map +0 -1
- package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-writer.js +0 -652
- package/node_modules/exceljs/dist/es5/stream/xlsx/worksheet-writer.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/auto-drain.js +0 -18
- package/node_modules/exceljs/dist/es5/utils/auto-drain.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/browser-buffer-decode.js +0 -15
- package/node_modules/exceljs/dist/es5/utils/browser-buffer-decode.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/browser-buffer-encode.js +0 -18
- package/node_modules/exceljs/dist/es5/utils/browser-buffer-encode.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/cell-matrix.js +0 -149
- package/node_modules/exceljs/dist/es5/utils/cell-matrix.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/col-cache.js +0 -258
- package/node_modules/exceljs/dist/es5/utils/col-cache.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/copy-style.js +0 -43
- package/node_modules/exceljs/dist/es5/utils/copy-style.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/encryptor.js +0 -58
- package/node_modules/exceljs/dist/es5/utils/encryptor.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/iterate-stream.js +0 -46
- package/node_modules/exceljs/dist/es5/utils/iterate-stream.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/parse-sax.js +0 -47
- package/node_modules/exceljs/dist/es5/utils/parse-sax.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/shared-formula.js +0 -42
- package/node_modules/exceljs/dist/es5/utils/shared-formula.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/shared-strings.js +0 -32
- package/node_modules/exceljs/dist/es5/utils/shared-strings.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/stream-base64.js +0 -66
- package/node_modules/exceljs/dist/es5/utils/stream-base64.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/stream-buf.js +0 -343
- package/node_modules/exceljs/dist/es5/utils/stream-buf.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/string-buf.js +0 -73
- package/node_modules/exceljs/dist/es5/utils/string-buf.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/string-builder.js +0 -32
- package/node_modules/exceljs/dist/es5/utils/string-builder.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/stuttered-pipe.js +0 -61
- package/node_modules/exceljs/dist/es5/utils/stuttered-pipe.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/typed-stack.js +0 -23
- package/node_modules/exceljs/dist/es5/utils/typed-stack.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/under-dash.js +0 -168
- package/node_modules/exceljs/dist/es5/utils/under-dash.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/utils.js +0 -171
- package/node_modules/exceljs/dist/es5/utils/utils.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/xml-stream.js +0 -151
- package/node_modules/exceljs/dist/es5/utils/xml-stream.js.map +0 -1
- package/node_modules/exceljs/dist/es5/utils/zip-stream.js +0 -79
- package/node_modules/exceljs/dist/es5/utils/zip-stream.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/defaultnumformats.js +0 -230
- package/node_modules/exceljs/dist/es5/xlsx/defaultnumformats.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/rel-type.js +0 -18
- package/node_modules/exceljs/dist/es5/xlsx/rel-type.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/base-xform.js +0 -139
- package/node_modules/exceljs/dist/es5/xlsx/xform/base-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/defined-name-xform.js +0 -85
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/defined-name-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/sheet-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/sheet-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-calc-properties-xform.js +0 -24
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-calc-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-properties-xform.js +0 -27
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-view-xform.js +0 -51
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-view-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-xform.js +0 -234
- package/node_modules/exceljs/dist/es5/xlsx/xform/book/workbook-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comment-xform.js +0 -103
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comment-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comments-xform.js +0 -76
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/comments-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-position-xform.js +0 -35
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-position-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-protection-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/style/vml-protection-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-anchor-xform.js +0 -53
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-anchor-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-client-data-xform.js +0 -97
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-client-data-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-notes-xform.js +0 -107
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-notes-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-shape-xform.js +0 -92
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-shape-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-textbox-xform.js +0 -61
- package/node_modules/exceljs/dist/es5/xlsx/xform/comment/vml-textbox-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/composite-xform.js +0 -51
- package/node_modules/exceljs/dist/es5/xlsx/xform/composite-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-heading-pairs-xform.js +0 -30
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-heading-pairs-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-titles-of-parts-xform.js +0 -27
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-titles-of-parts-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-xform.js +0 -93
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/app-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/content-types-xform.js +0 -112
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/content-types-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/core-xform.js +0 -158
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/core-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationship-xform.js +0 -23
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationship-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationships-xform.js +0 -65
- package/node_modules/exceljs/dist/es5/xlsx/xform/core/relationships-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/base-cell-anchor-xform.js +0 -47
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/base-cell-anchor-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-fill-xform.js +0 -61
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-fill-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-xform.js +0 -40
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/blip-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pic-pr-xform.js +0 -35
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pic-pr-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pr-xform.js +0 -62
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/c-nv-pr-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/cell-position-xform.js +0 -82
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/cell-position-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/drawing-xform.js +0 -98
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/drawing-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-lst-xform.js +0 -40
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-lst-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-xform.js +0 -38
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/hlink-click-xform.js +0 -38
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/hlink-click-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/nv-pic-pr-xform.js +0 -59
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/nv-pic-pr-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/one-cell-anchor-xform.js +0 -63
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/one-cell-anchor-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/pic-xform.js +0 -67
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/pic-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/sp-pr.js +0 -30
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/sp-pr.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/two-cell-anchor-xform.js +0 -62
- package/node_modules/exceljs/dist/es5/xlsx/xform/drawing/two-cell-anchor-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/list-xform.js +0 -91
- package/node_modules/exceljs/dist/es5/xlsx/xform/list-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/auto-filter-xform.js +0 -40
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/auto-filter-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cell-xform.js +0 -451
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cell-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cf-rule-xform.js +0 -275
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cf-rule-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cfvo-xform.js +0 -25
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/cfvo-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/color-scale-xform.js +0 -38
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/color-scale-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formatting-xform.js +0 -45
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formatting-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formattings-xform.js +0 -77
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/conditional-formattings-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/databar-xform.js +0 -42
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/databar-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +0 -71
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/ext-lst-ref-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/formula-xform.js +0 -22
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/formula-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/icon-set-xform.js +0 -43
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf/icon-set-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +0 -28
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +0 -88
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +0 -38
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +0 -52
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +0 -43
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +0 -75
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/databar-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/f-ext-xform.js +0 -22
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/f-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +0 -66
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +0 -22
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/col-xform.js +0 -78
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/col-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/data-validations-xform.js +0 -247
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/data-validations-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/dimension-xform.js +0 -28
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/dimension-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/drawing-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/drawing-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/ext-lst-xform.js +0 -69
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/ext-lst-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/header-footer-xform.js +0 -126
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/header-footer-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/hyperlink-xform.js +0 -50
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/hyperlink-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merge-cell-xform.js +0 -26
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merge-cell-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merges.js +0 -52
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/merges.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/outline-properties-xform.js +0 -35
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/outline-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-breaks-xform.js +0 -24
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-breaks-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-margins-xform.js +0 -46
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-margins-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-properties-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-xform.js +0 -99
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/page-setup-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/picture-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/picture-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/print-options-xform.js +0 -45
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/print-options-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-breaks-xform.js +0 -37
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-breaks-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-xform.js +0 -128
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/row-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-format-properties-xform.js +0 -51
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-format-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-properties-xform.js +0 -83
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-properties-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-protection-xform.js +0 -84
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-protection-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-view-xform.js +0 -190
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/sheet-view-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/table-part-xform.js +0 -32
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/table-part-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/worksheet-xform.js +0 -513
- package/node_modules/exceljs/dist/es5/xlsx/xform/sheet/worksheet-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/boolean-xform.js +0 -27
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/boolean-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/date-xform.js +0 -58
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/date-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/float-xform.js +0 -47
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/float-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/integer-xform.js +0 -53
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/integer-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/string-xform.js +0 -47
- package/node_modules/exceljs/dist/es5/xlsx/xform/simple/string-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/static-xform.js +0 -61
- package/node_modules/exceljs/dist/es5/xlsx/xform/static-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/phonetic-text-xform.js +0 -98
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/phonetic-text-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/rich-text-xform.js +0 -92
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/rich-text-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-string-xform.js +0 -99
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-string-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-strings-xform.js +0 -114
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/shared-strings-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/text-xform.js +0 -39
- package/node_modules/exceljs/dist/es5/xlsx/xform/strings/text-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/alignment-xform.js +0 -139
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/alignment-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/border-xform.js +0 -185
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/border-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/color-xform.js +0 -66
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/color-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/dxf-xform.js +0 -106
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/dxf-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/fill-xform.js +0 -308
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/fill-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/font-xform.js +0 -175
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/font-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/numfmt-xform.js +0 -59
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/numfmt-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/protection-xform.js +0 -53
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/protection-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/style-xform.js +0 -118
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/style-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/styles-xform.js +0 -612
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/styles-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/underline-xform.js +0 -46
- package/node_modules/exceljs/dist/es5/xlsx/xform/style/underline-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/auto-filter-xform.js +0 -75
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/auto-filter-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/custom-filter-xform.js +0 -30
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/custom-filter-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-column-xform.js +0 -89
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-column-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-xform.js +0 -28
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/filter-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-column-xform.js +0 -42
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-column-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-style-info-xform.js +0 -40
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-style-info-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-xform.js +0 -123
- package/node_modules/exceljs/dist/es5/xlsx/xform/table/table-xform.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xlsx.js +0 -697
- package/node_modules/exceljs/dist/es5/xlsx/xlsx.js.map +0 -1
- package/node_modules/exceljs/dist/es5/xlsx/xml/theme1.js +0 -5
- package/node_modules/exceljs/dist/es5/xlsx/xml/theme1.js.map +0 -1
- package/node_modules/exceljs/dist/exceljs.bare.js +0 -55253
- package/node_modules/exceljs/dist/exceljs.bare.js.map +0 -761
- package/node_modules/exceljs/dist/exceljs.bare.min.js +0 -45
- package/node_modules/exceljs/dist/exceljs.bare.min.js.map +0 -1
- package/node_modules/exceljs/dist/exceljs.js +0 -59900
- package/node_modules/exceljs/dist/exceljs.js.map +0 -1083
- package/node_modules/exceljs/dist/exceljs.min.js +0 -45
- package/node_modules/exceljs/dist/exceljs.min.js.map +0 -1
- package/scripts/ai-page-render-check.mjs +0 -532
- package/scripts/clearances-render-check.mjs +0 -480
- package/scripts/composer-render-check.mjs +0 -1027
- package/scripts/deploy-test.sh +0 -309
- package/scripts/home-render-check.mjs +0 -526
- package/scripts/portal-lifecycle-check.mjs +0 -639
|
@@ -21,10 +21,20 @@
|
|
|
21
21
|
// ~60 lines of duplicated document shell, and it is the right price: the alternative is exporting the
|
|
22
22
|
// shell out of the frozen file, which is a bigger break than the duplication saves.
|
|
23
23
|
//
|
|
24
|
-
// ONE report. There is no client variant and no internal variant
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
24
|
+
// ONE report. There is no client variant and no internal variant, and that is
|
|
25
|
+
// still the rule — it is what removes the whole class of "the wrong link got sent".
|
|
26
|
+
//
|
|
27
|
+
// WHAT CHANGED, 2026-09-07 (owner ruling, tracker issue 274): the one report now CARRIES the reviewer's
|
|
28
|
+
// notes rather than routing them to the audit workbook alone. The earlier reading of "one report" was
|
|
29
|
+
// that internal working material is simply not part of it; the ruling is that there is one report and the
|
|
30
|
+
// person who ran Clearotron reads it, so holding material back "just adds confusion for where data is
|
|
31
|
+
// lost". Six notes written for the reviewing lawyer on a delivered run reached the spreadsheet and
|
|
32
|
+
// nothing else, which is the measurement behind the ruling.
|
|
33
|
+
//
|
|
34
|
+
// So: the notes render, LABELLED, in report.css's existing `.internal` purple convention (see
|
|
35
|
+
// reviewerNotesBlock) — never merged into the client-voiced body. The workbook keeps them as well; this
|
|
36
|
+
// added a surface and moved none. The model's `registerEstimate` is NOT covered by the ruling and stays
|
|
37
|
+
// off the page.
|
|
28
38
|
import { readFileSync } from 'node:fs';
|
|
29
39
|
import { join, dirname } from 'node:path';
|
|
30
40
|
import { fileURLToPath } from 'node:url';
|
|
@@ -35,7 +45,7 @@ import {
|
|
|
35
45
|
import { SUMMARY_BLOCK_LINE, parseSummaryBlocks } from '../../shared/summary-blocks.mjs';
|
|
36
46
|
import { COUNT_BASIS, COUNT_PREDICATES, countsForMark, countLine, variantFormsLine } from '../register-count.mjs';
|
|
37
47
|
import { RECORD_BASIS, recordsForMark, recordsLine } from '../register-records.mjs';
|
|
38
|
-
import { knockoutFindingViews } from '../findings-model.mjs';
|
|
48
|
+
import { knockoutFindingViews, splitKnockoutNotes } from '../findings-model.mjs';
|
|
39
49
|
import { demoBannerHtml } from './render.mjs'; // — the SAME banner the clearance template renders, not a second wording
|
|
40
50
|
// — the two facts the register card is allowed to read off a raw record, and NEITHER is minted
|
|
41
51
|
// here. `makeClassifyStatus` and `isAllClass` are the screening lane's own, already shipped, already
|
|
@@ -118,7 +128,7 @@ function bandStop(framework, band) {
|
|
|
118
128
|
|
|
119
129
|
const DEGRADED_NOTE = 'Automated research for this name was unavailable — manual verification is recommended before relying on this rating.';
|
|
120
130
|
|
|
121
|
-
//
|
|
131
|
+
// THE QUALIFIER, IN WORDS. It rendered as a bare grey token under the band chip — `low`, no
|
|
122
132
|
// label, no border, nothing on the page saying what it qualified. A reader met one word of a private
|
|
123
133
|
// vocabulary and had to guess whether it described the risk, the confidence or the search.
|
|
124
134
|
//
|
|
@@ -176,6 +186,14 @@ const KO_CSS = `
|
|
|
176
186
|
.ko-findev{margin:0;font-size:12.5px;line-height:1.6;word-break:break-word}
|
|
177
187
|
.ko-count{font-family:var(--mono);font-size:13px;color:var(--ink);margin:0}
|
|
178
188
|
.ko-degraded{font-size:13px;color:var(--med-tx,#82550A);margin:8px 0 0;font-style:italic}
|
|
189
|
+
/* The reviewer-notes legend. NOT .ko-legend — that name is taken by the framework attribution row
|
|
190
|
+
above, and reusing it would restyle the caption. It names the purple convention report.css already
|
|
191
|
+
draws for .internal, so the colour is stated once and never re-specified. */
|
|
192
|
+
.ko-refnote{margin:0;padding:11px 24px 0;font-size:12px;color:#6a2b6e;font-style:italic}
|
|
193
|
+
/* The notes sit inside a mark's column, so the shared .internal block's bullets keep the column's
|
|
194
|
+
own list indent and do not fight the paragraph above them. */
|
|
195
|
+
.ko-row .internal .ko-bul{margin:0 0 4px}
|
|
196
|
+
.ko-row .internal .ko-bul:last-child{margin-bottom:0}
|
|
179
197
|
.ko-counts table{width:100%;border-collapse:collapse;font-size:14px}
|
|
180
198
|
.ko-counts th{text-align:left;font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint);
|
|
181
199
|
font-weight:700;padding:14px 24px 8px;border-bottom:1px solid var(--line)}
|
|
@@ -202,6 +220,28 @@ const KO_CSS = `
|
|
|
202
220
|
saved to PDF would drop the narrative this block exists to preserve. The beforeprint handler below
|
|
203
221
|
opens them; this hides the now-pointless toggle in print. */
|
|
204
222
|
@media print{.ko-full summary{display:none}}
|
|
223
|
+
/* THE LABELS THE READER ACTUALLY READS. ko-lbl above is 9.5px uppercase grey — the owner's
|
|
224
|
+
"what holds what?" was asked of a label in that style, so a new word in the same style is the
|
|
225
|
+
same defect with different letters. These are body size and body colour, and they carry the
|
|
226
|
+
band's own word ("Why High"), which is what makes them answerable without a legend. */
|
|
227
|
+
.ko-lbl2{display:block;font-size:14px;font-weight:700;color:var(--ink);margin:0 0 5px;letter-spacing:0}
|
|
228
|
+
/* The card's fold. ko-full rides with it so openAll() and the beforeprint handler reach it —
|
|
229
|
+
what folds on screen still prints, which is the rule this template already states for the
|
|
230
|
+
narrative fold. ko-why carries only the spacing a card needs inside its own body. */
|
|
231
|
+
.ko-why{margin:6px 0 5px}
|
|
232
|
+
.ko-why summary{font-size:12px;text-transform:none;letter-spacing:0;color:var(--rose,var(--faint));font-weight:600}
|
|
233
|
+
/* "About this request" — what was asked, and any flag on the asking. It sits in the hero because a
|
|
234
|
+
mis-scoped request makes every number below it answer the wrong question. */
|
|
235
|
+
.ko-req{margin:14px 0 0;padding:13px 16px;border:1px solid var(--line);border-radius:3px}
|
|
236
|
+
.ko-req .ko-lbl2{margin-bottom:6px}
|
|
237
|
+
.ko-req p{margin:0 0 6px;font-size:13.5px;color:var(--slate);line-height:1.6}
|
|
238
|
+
.ko-req p:last-child{margin-bottom:0}
|
|
239
|
+
.ko-reqflag{border-left:3px solid var(--rose,var(--line));padding-left:11px;margin-top:9px}
|
|
240
|
+
/* THE PURPLE NOTES COME OFF THE EXPORT, exactly as the clearance page removes its internal notes
|
|
241
|
+
("Internal (review-only) notes are removed on export"). The knockout's export is window.print()
|
|
242
|
+
via exportPDF(), so print is the whole export path and this rule is the whole strip. Without it
|
|
243
|
+
a knockout PDF forwarded to a client carries the reviewing lawyer's notes. */
|
|
244
|
+
@media print{.internal{display:none !important}}
|
|
205
245
|
.ko-reg{margin:11px 0 0;padding:8px 0 0;border-top:1px solid var(--line);
|
|
206
246
|
font-family:var(--mono);font-size:12px;color:var(--faint);line-height:1.5}
|
|
207
247
|
.ko-filings{padding:14px 0 2px;border-bottom:1px solid var(--line)}
|
|
@@ -248,13 +288,13 @@ function glanceSection(marks, framework, registerCounts) {
|
|
|
248
288
|
</div>
|
|
249
289
|
</div>`;
|
|
250
290
|
}).join('');
|
|
251
|
-
//
|
|
291
|
+
// THE FRAMEWORK IS NAMED BESIDE THE CHIPS IT EXPLAINS. Every `.ko-band` chip below speaks one
|
|
252
292
|
// word out of a framework's vocabulary, and that framework was named exactly once on this page: in the
|
|
253
293
|
// footer, under everything it governs. This is ATTRIBUTION AND NOTHING ELSE — the same "Rated under
|
|
254
294
|
// <name>" the footer prints, moved to where the words it licenses are actually read.
|
|
255
295
|
//
|
|
256
296
|
// NO LADDER HERE. Spelling the band scale out beside the chips would be new furniture on a client
|
|
257
|
-
// deliverable, and
|
|
297
|
+
// deliverable, and a rung buys depth, never furniture. If the knockout reader needs the
|
|
258
298
|
// scale, that is its own decision on its own merits, not a rider on this one.
|
|
259
299
|
//
|
|
260
300
|
// No framework ⇒ NOTHING. A run this render was given no manifest for gets no attribution invented for
|
|
@@ -279,8 +319,111 @@ function glanceSection(marks, framework, registerCounts) {
|
|
|
279
319
|
// all-classes figure alongside a class-scoped one would be a second count — one more provider call per
|
|
280
320
|
// mark per predicate, billable on Corsearch — and that is a spend the owner has not ruled on. Raised as
|
|
281
321
|
// a follow-up rather than assumed here (tracker issue 717).
|
|
322
|
+
// ── TERRITORIES IN WORDS, NEVER CODES (tracker issue 331 C) ─────────────────────────────────────────
|
|
323
|
+
//
|
|
324
|
+
// The line read "territories: EM, US, WO". On a worldwide run the same line printed every register code
|
|
325
|
+
// the provider offers — roughly two hundred, AD through ZZ, internal groupings among them — which the
|
|
326
|
+
// owner called a meaningless list, correctly: a reader cannot tell anything from two hundred codes and
|
|
327
|
+
// cannot tell much from three.
|
|
328
|
+
//
|
|
329
|
+
// TWO CODES ARE REGISTERS RATHER THAN COUNTRIES and neither is an ISO region, so neither can be resolved
|
|
330
|
+
// by a country table: EM is the EU Intellectual Property Office and WO is WIPO's international register.
|
|
331
|
+
// They are named here because they are the two a reader meets constantly.
|
|
332
|
+
//
|
|
333
|
+
// A CODE THIS TABLE CANNOT NAME IS DROPPED, NOT PRINTED. The provider's internal groupings (XA, XG, XS,
|
|
334
|
+
// XW, ZZ and their like) name no register a reader could look up, and printing one is the defect this
|
|
335
|
+
// change exists to remove. Dropping them is safe because the COUNT of registers is stated separately and
|
|
336
|
+
// is taken before any naming — so a reader is never told about fewer registers than were counted.
|
|
337
|
+
// TWO FORMS PER REGISTER, because English needs both: "Counted in the United States" takes the article
|
|
338
|
+
// and "United States application" refuses it. One map with one form produced "the United States
|
|
339
|
+
// application (pending)" on a card, which is why they are separate fields rather than a regex over one.
|
|
340
|
+
const REGISTER_NAMES = Object.freeze({
|
|
341
|
+
EM: { bare: 'European Union', phrase: 'the European Union' },
|
|
342
|
+
EU: { bare: 'European Union', phrase: 'the European Union' },
|
|
343
|
+
WO: { bare: 'international', phrase: 'the WIPO register' },
|
|
344
|
+
US: { bare: 'United States', phrase: 'the United States' },
|
|
345
|
+
GB: { bare: 'United Kingdom', phrase: 'the United Kingdom' },
|
|
346
|
+
UK: { bare: 'United Kingdom', phrase: 'the United Kingdom' },
|
|
347
|
+
CH: { bare: 'Swiss', phrase: 'Switzerland' },
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* A register code as a reader's words, or '' when this build cannot name it. NEVER returns a code.
|
|
352
|
+
* `bare: true` gives the attributive form for a phrase like "United States application".
|
|
353
|
+
*/
|
|
354
|
+
function territoryName(code, { bare = false } = {}) {
|
|
355
|
+
const c = String(code ?? '').trim().toUpperCase();
|
|
356
|
+
if (!c) return '';
|
|
357
|
+
if (REGISTER_NAMES[c]) return bare ? REGISTER_NAMES[c].bare : REGISTER_NAMES[c].phrase;
|
|
358
|
+
// The provider's internal groupings all sit in the X* and Z* space and name no lookup-able register.
|
|
359
|
+
if (/^[XZ]/.test(c)) return '';
|
|
360
|
+
try {
|
|
361
|
+
const name = new Intl.DisplayNames(['en'], { type: 'region' }).of(c);
|
|
362
|
+
// Intl hands the CODE back when it knows no region by that name — which would print exactly the
|
|
363
|
+
// thing this function exists to prevent, so an unresolved code is an empty string.
|
|
364
|
+
return name && name.toUpperCase() !== c ? name : '';
|
|
365
|
+
} catch { return ''; }
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/** "a, b and c" — the reader's list, not a join on commas. */
|
|
369
|
+
function listWords(items) {
|
|
370
|
+
const xs = (items ?? []).filter(Boolean);
|
|
371
|
+
if (xs.length <= 1) return xs[0] ?? '';
|
|
372
|
+
return `${xs.slice(0, -1).join(', ')} and ${xs[xs.length - 1]}`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* The counted scope, in one sentence (tracker issue 331 C). Three shapes, and the shape is chosen by
|
|
377
|
+
* how many registers were counted rather than by which they were:
|
|
378
|
+
*
|
|
379
|
+
* every register the provider offers -> "Counted worldwide, 190 registers, on Clarivate Compumark."
|
|
380
|
+
* up to six -> named in full
|
|
381
|
+
* more than six, not all -> the count, and where the list is
|
|
382
|
+
*
|
|
383
|
+
* The provider is named here and nowhere else on the page; 331 D takes the vendor's name off the cards.
|
|
384
|
+
*/
|
|
385
|
+
const TERRITORY_NAME_CAP = 6;
|
|
386
|
+
function territoriesLine(registerCounts) {
|
|
387
|
+
const provider = registerCounts?.providerLabel ?? registerCounts?.provider ?? 'the register';
|
|
388
|
+
const regions = (registerCounts?.scope?.regions ?? []).filter(Boolean);
|
|
389
|
+
const worldwide = registerCounts?.scope?.worldwide === true || regions.length === 0;
|
|
390
|
+
if (worldwide) {
|
|
391
|
+
const n = regions.length;
|
|
392
|
+
return n
|
|
393
|
+
? `Counted worldwide, ${n} registers, on ${provider}.`
|
|
394
|
+
: `Counted worldwide on ${provider}.`;
|
|
395
|
+
}
|
|
396
|
+
const named = regions.map(territoryName).filter(Boolean);
|
|
397
|
+
if (named.length && named.length <= TERRITORY_NAME_CAP) {
|
|
398
|
+
return `Counted in ${listWords(named)}, on ${provider}.`;
|
|
399
|
+
}
|
|
400
|
+
return `Counted on ${regions.length} registers, listed on the workbook's Register Counts sheet, on ${provider}.`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** What the counts do and do not say — the one line that replaces the count-basis paragraph on the page. */
|
|
404
|
+
const COUNTS_READER_LINE = 'Counts include live, pending and dead filings. '
|
|
405
|
+
+ 'A count is not a conflict; the cards above say which filings matter.';
|
|
406
|
+
|
|
282
407
|
function countsSection(marks, registerCounts) {
|
|
283
|
-
|
|
408
|
+
// ── THE DEFINITION MOVES INTO THE COLUMN HEADER (tracker issue 331 B) ────────────────────────────
|
|
409
|
+
//
|
|
410
|
+
// The 70-word count-basis paragraph existed because three one-word headers — Identical, Containing,
|
|
411
|
+
// Close variations — did not say what they counted, so the definition had to go somewhere. Put it in
|
|
412
|
+
// the header and the paragraph has nothing left to do.
|
|
413
|
+
//
|
|
414
|
+
// ONE NAME ⇒ THE HEADER NAMES IT, because "Exactly ORBIT" needs no gloss at all. Several names share
|
|
415
|
+
// one table and no header can name one of them, so they keep the general form and each row's own
|
|
416
|
+
// forms line (already rendered, unchanged) carries that row's near-spellings.
|
|
417
|
+
const single = marks.length === 1 ? String(marks[0]?.name ?? '').trim() : '';
|
|
418
|
+
const forms = single
|
|
419
|
+
? ((countsForMark(registerCounts, single)?.counts?.close?.forms ?? []).map((f) => String(f?.form ?? '').trim()).filter(Boolean))
|
|
420
|
+
: [];
|
|
421
|
+
const headLabel = (pk) => {
|
|
422
|
+
if (pk === 'identical') return single ? `Exactly ${single}` : 'Exactly the name';
|
|
423
|
+
if (pk === 'containing') return single ? `Contains ${single}` : 'Contains the name';
|
|
424
|
+
return forms.length ? `Near-spellings (${forms.join(', ')})` : 'Near-spellings';
|
|
425
|
+
};
|
|
426
|
+
const head = COUNT_PREDICATES.map((p) => `<th>${esc(headLabel(p.key))}</th>`).join('');
|
|
284
427
|
const rows = marks.map((m) => {
|
|
285
428
|
const e = countsForMark(registerCounts, m.name);
|
|
286
429
|
const cells = COUNT_PREDICATES.map((p) => {
|
|
@@ -308,11 +451,13 @@ function countsSection(marks, registerCounts) {
|
|
|
308
451
|
return `<tr><td><b>${esc(m.name)}</b><br><span class="ko-classes">${esc(scope)}</span></td>${cells}</tr>`
|
|
309
452
|
+ (forms ? `<tr class="ko-forms"><td colspan="${COUNT_PREDICATES.length + 1}">${esc(forms)}</td></tr>` : '');
|
|
310
453
|
}).join('');
|
|
311
|
-
|
|
312
|
-
|
|
454
|
+
// COUNT_BASIS IS OFF THE PAGE, NOT OUT OF THE RECORD (tracker issue 331 B). It is still written to
|
|
455
|
+
// report-data.json (knockoutReportData -> registerCountBasis) and still on the workbook, which is where
|
|
456
|
+
// 331 says it belongs; what it stops doing is printing twice on a page whose headers now say the same
|
|
457
|
+
// thing in three words each.
|
|
313
458
|
return `<div class="panel">
|
|
314
459
|
<div class="ko-counts ko-scroll"><table><thead><tr><th>Name</th>${head}</tr></thead><tbody>${rows}</tbody></table></div>
|
|
315
|
-
<p class="ko-basis">${esc(
|
|
460
|
+
<p class="ko-basis">${esc(COUNTS_READER_LINE)}<br>${esc(territoriesLine(registerCounts))}</p>
|
|
316
461
|
</div>`;
|
|
317
462
|
}
|
|
318
463
|
|
|
@@ -514,6 +659,29 @@ function tierAbsenceLine(registerCounts, probeRan) {
|
|
|
514
659
|
// A NAME is deliberately not emitted here for the control to send. `ref` is right there and reads
|
|
515
660
|
// nicely, but portal-ui/src/contract/reportFrame.ts refuses a mark from the document side on purpose,
|
|
516
661
|
// and the composite key IS a mark name. The server reads `ref` back off disk once it has resolved.
|
|
662
|
+
/**
|
|
663
|
+
* THE CARD'S DETAIL, FOLDED (tracker issue 331 A.3).
|
|
664
|
+
*
|
|
665
|
+
* Visible on a card: the reference, the name, the band chip, the source chip, the one-sentence read and
|
|
666
|
+
* the evidence links. Folded: the paragraph that argues the band, and on a register card the use-check
|
|
667
|
+
* line and the record link with it.
|
|
668
|
+
*
|
|
669
|
+
* WHY A FOLD AND NOT A CUT. The paragraph is the reasoning, and 331 rejects "shortening by dropping the
|
|
670
|
+
* reasons" in as many words. It is one click away and it still prints — `ko-full` is on the element, so
|
|
671
|
+
* openAll() and the beforeprint handler both reach it and a saved PDF carries the whole argument.
|
|
672
|
+
*
|
|
673
|
+
* EMPTY IN, EMPTY OUT. A card with no detail renders no fold rather than an empty one, which is also the
|
|
674
|
+
* archived-run path: a run whose findings carry no `basis` renders exactly the card it was delivered.
|
|
675
|
+
*/
|
|
676
|
+
function whyBandFold(inner) {
|
|
677
|
+
const body = String(inner ?? '').trim();
|
|
678
|
+
if (!body) return '';
|
|
679
|
+
return `<details class="ko-full ko-why"><summary>${esc(WHY_BAND_LABEL)}</summary>${body}</details>`;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/** The card fold's own word. Stated once so the renderer and its tests read the same string. */
|
|
683
|
+
const WHY_BAND_LABEL = 'Why this band';
|
|
684
|
+
|
|
517
685
|
function findingBlock(v, framework, markIndex) {
|
|
518
686
|
const meta = [v.type, v.owner].filter(Boolean).map((s) => esc(s)).join(' · ');
|
|
519
687
|
const ev = v.evidence.map((u) => linkOrText(u)).join(' · ');
|
|
@@ -546,7 +714,7 @@ function findingBlock(v, framework, markIndex) {
|
|
|
546
714
|
</div>
|
|
547
715
|
${meta ? `<p class="ko-findmeta">${meta}</p>` : ''}
|
|
548
716
|
${v.lead ? `<p class="ko-findnet">${inlineMd(v.lead)}</p>` : ''}
|
|
549
|
-
${v.detail ? `<p class="ko-findbasis">${inlineMd(v.detail)}</p>` : ''}
|
|
717
|
+
${whyBandFold(v.detail ? `<p class="ko-findbasis">${inlineMd(v.detail)}</p>` : '')}
|
|
550
718
|
${ev ? `<p class="ko-findev">Evidence: ${ev}</p>` : ''}
|
|
551
719
|
</div>
|
|
552
720
|
</div>
|
|
@@ -637,6 +805,28 @@ const REGISTER_ORDINAL_FLOOR = 900;
|
|
|
637
805
|
export const NOT_WEIGHED_LINE = 'Register listing — this card carries no rating of its own';
|
|
638
806
|
const NOT_WEIGHED = NOT_WEIGHED_LINE;
|
|
639
807
|
|
|
808
|
+
/**
|
|
809
|
+
* The register card's basis line, which cannot be written without knowing whether the card is rated.
|
|
810
|
+
*
|
|
811
|
+
* THE TWO RULINGS MEET HERE AND THEY ALMOST CONTRADICTED EACH OTHER ON A CLIENT PAGE. tracker issue
|
|
812
|
+
* 1935 retired a code-owned placeholder because a rating nobody performed must not appear; tracker
|
|
813
|
+
* issue 274 then ruled that the rater's OWN band for a promoted filing must appear, because a filing
|
|
814
|
+
* the rater weighed into the verdict was rendering as though it had not been. Both hold, and they hold
|
|
815
|
+
* over different cards.
|
|
816
|
+
*
|
|
817
|
+
* `band` and `read` are independent fields — the band comes from `registerReads[].band` and the read
|
|
818
|
+
* from its `text` — so a filing the rater banded WITHOUT typing a read is reachable, and the first cut
|
|
819
|
+
* of this rendered the band chip beside the sentence "this card carries no rating of its own". The
|
|
820
|
+
* report would have been contradicting itself in one card, in the client's voice.
|
|
821
|
+
*
|
|
822
|
+
* So: the retired line belongs only to a card with no band. A banded card with no read says nothing
|
|
823
|
+
* rather than something false — the chip and the source tag already say what the card is.
|
|
824
|
+
*/
|
|
825
|
+
function basisLine(band, read) {
|
|
826
|
+
if (read) return `<p class="ko-findbasis">${esc(read)}</p>`;
|
|
827
|
+
return band ? '' : `<p class="ko-findbasis">${esc(NOT_WEIGHED)}</p>`;
|
|
828
|
+
}
|
|
829
|
+
|
|
640
830
|
|
|
641
831
|
/**
|
|
642
832
|
* Which listed filings get pointed at. TWO tests, and both fail OPEN — a filing is promoted unless
|
|
@@ -654,7 +844,11 @@ const NOT_WEIGHED = NOT_WEIGHED_LINE;
|
|
|
654
844
|
* Neither test is a judgment about the filing. Whether any of it blocks anything is lawyer work this
|
|
655
845
|
* product does not do — the same line register-records.mjs rule 3 has held since the lane shipped.
|
|
656
846
|
*/
|
|
657
|
-
|
|
847
|
+
// EXPORTED so the pipeline can ask the same question the page asks (tracker issue 276). The owner
|
|
848
|
+
// use-check runs on PROMOTED filings only, and "promoted" has to mean here what it means on the report —
|
|
849
|
+
// a second predicate would let the engine search an owner whose filing the report never shows, or skip
|
|
850
|
+
// one it does.
|
|
851
|
+
export function promotableRecords(entry, mark) {
|
|
658
852
|
const scope = new Set([...(mark?.classesSearched ?? []), ...(entry?.classes ?? [])]
|
|
659
853
|
.map(Number).filter(Number.isInteger));
|
|
660
854
|
return (entry?.records ?? []).filter((r) => {
|
|
@@ -670,18 +864,52 @@ function promotableRecords(entry, mark) {
|
|
|
670
864
|
/** One sentence of what the filing IS, composed from the register's own fields. No adjective that the
|
|
671
865
|
* record did not supply, and every absent field says it is absent rather than rendering as a blank —
|
|
672
866
|
* a blank cell and an unstated field read alike to a human and only one is honest. */
|
|
867
|
+
// ── THE OFFICE, NOT THE VENDOR (tracker issue 331 D) ────────────────────────────────────────────────
|
|
868
|
+
//
|
|
869
|
+
// The sentence read "A filing of the identical name on Clarivate Compumark — held by ..., status
|
|
870
|
+
// PENDING, classes 9, 38, 45, territory us." Clarivate Compumark is the search vendor; the filing is at
|
|
871
|
+
// the United States office. Naming the vendor in the position where a reader expects the register says
|
|
872
|
+
// the filing exists somewhere it does not, and prints a raw two-letter territory code besides.
|
|
873
|
+
//
|
|
874
|
+
// The provider is still named — once, in scope, as the data source (territoriesLine), which is what it
|
|
875
|
+
// is. A card states the office, the kind of right, its status, its owner and its classes.
|
|
876
|
+
//
|
|
877
|
+
// STATUS IS THE RECORD'S OWN WORD, lower-cased for the sentence and never re-classified: "pending" here
|
|
878
|
+
// is the register's PENDING, not this renderer's reading of it. A record that states none says so.
|
|
879
|
+
const REGISTRATION_WORDS = /^(?:reg|registered|registration)/i;
|
|
880
|
+
|
|
881
|
+
/** "United States application (pending)" — the office and the kind of right, from the record's own fields. */
|
|
882
|
+
function registerRightPhrase(r) {
|
|
883
|
+
const office = territoryName(r?.territory, { bare: true });
|
|
884
|
+
const status = String(r?.status ?? '').trim();
|
|
885
|
+
// A right whose status names a registration is a registration; anything else is an application. The
|
|
886
|
+
// record's raw word rides in the bracket either way, so the reader never has to trust the reading.
|
|
887
|
+
const kind = REGISTRATION_WORDS.test(status) ? 'registration' : 'application';
|
|
888
|
+
const where = office ? `${office} ` : '';
|
|
889
|
+
// The bracket exists to show the register's OWN word where that word adds something. On a record whose
|
|
890
|
+
// status already names the kind ("REGISTERED" beside "registration") it adds nothing but noise, so it
|
|
891
|
+
// is dropped — the reader has the same fact either way, in one word instead of two.
|
|
892
|
+
// "registration (registered)" and "application (application)" say the kind twice. Both roots are
|
|
893
|
+
// tested rather than stemmed, because a stemmer that turns "registered" and "registration" into one
|
|
894
|
+
// token also turns "pending" and "pended" into one, and "(pending)" is a fact the reader wants.
|
|
895
|
+
const echoes = (kind === 'registration' && REGISTRATION_WORDS.test(status))
|
|
896
|
+
|| (kind === 'application' && /^(?:appl|filed?)/i.test(status));
|
|
897
|
+
const bracket = status && !echoes ? ` (${status.toLowerCase()})` : '';
|
|
898
|
+
return `${where}${kind}${bracket}`.trim();
|
|
899
|
+
}
|
|
900
|
+
|
|
673
901
|
function registerStatement(r, provider) {
|
|
674
|
-
const
|
|
675
|
-
? `A filing on ${provider} found under the close variation ${r.matchedForm ?? '—'}`
|
|
676
|
-
: `A filing of the identical name on ${provider}`;
|
|
902
|
+
const name = String(r?.mark ?? r?.name ?? '').trim();
|
|
677
903
|
const classes = (Array.isArray(r.classes) ? r.classes : []).filter((n) => Number.isFinite(Number(n)));
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
904
|
+
const lead = [name, registerRightPhrase(r)].filter(Boolean).join(', ');
|
|
905
|
+
const owner = r.owner ? `by ${r.owner}` : 'owner not stated on the record';
|
|
906
|
+
const cls = classes.length
|
|
907
|
+
? `class${classes.length === 1 ? '' : 'es'} ${classes.join(', ')}`
|
|
908
|
+
: 'classes not stated on the record';
|
|
909
|
+
// A close-variation card says WHICH near-form matched, because the name at the head of the sentence is
|
|
910
|
+
// then not the name the client asked about and a reader must not have to guess which it is.
|
|
911
|
+
const via = r.matchedBasis === 'close' && r.matchedForm ? ` Found under the close variation ${r.matchedForm}.` : '';
|
|
912
|
+
return `${lead} ${owner}, ${cls}.${via}`;
|
|
685
913
|
}
|
|
686
914
|
|
|
687
915
|
/**
|
|
@@ -697,6 +925,72 @@ function registerStatement(r, provider) {
|
|
|
697
925
|
* form would point a reader at a row that does not exist. Its receipt is the register record itself,
|
|
698
926
|
* which the card links.
|
|
699
927
|
*/
|
|
928
|
+
/**
|
|
929
|
+
* WHICH OF A MARK'S REGISTER CARDS THE PAGE DRAWS (tracker issue 331 A.3).
|
|
930
|
+
*
|
|
931
|
+
* THIS FILTERS THE PAGE, NEVER THE RECORD, and that separation is the whole point. 331 rejects dropping
|
|
932
|
+
* anything from report-data.json or the workbook to make the page shorter, so `registerCardViews` still
|
|
933
|
+
* builds every promoted filing and still assigns the ordinals it always did — knockoutReportData reads
|
|
934
|
+
* that, unchanged. This function decides only what is DRAWN.
|
|
935
|
+
*
|
|
936
|
+
* Keeping one projection also keeps the flag path honest: portal-service resolves a flag as
|
|
937
|
+
* `marks[i].findings.find(f => f.ordinal === ordinal)`, so a card on the page carries the ordinal its
|
|
938
|
+
* own data entry has. A card the page does not draw cannot be flagged, because there is nothing to click.
|
|
939
|
+
*
|
|
940
|
+
* ONLY AN EXPLICIT LOWEST-RUNG BAND SUPPRESSES A CARD. Absence never does, and that is the whole rule —
|
|
941
|
+
* there is no second condition and no archived-run special case, because this one covers both.
|
|
942
|
+
*
|
|
943
|
+
* The first cut read an absent band as "lowest" and needed a clause-F escape hatch beside it: if no
|
|
944
|
+
* filing on the mark carried a band, keep them all. That escape hatch is what a wrong default looks
|
|
945
|
+
* like. It handled the run with NO bands and silently mishandled the run with SOME: `band` is optional
|
|
946
|
+
* per row, so a rater who bands the filings that matter and leaves the rest alone is doing what the
|
|
947
|
+
* shape invites — and the mark whose one typed band happened to be the bottom rung lost every card it
|
|
948
|
+
* had, including the filings nobody ruled on.
|
|
949
|
+
*
|
|
950
|
+
* `atLowestBand` below already argues this, one function down: a band it cannot place on the ladder
|
|
951
|
+
* is kept, because "the rater said something, and the safe reading of something we cannot rank is that
|
|
952
|
+
* it is worth pointing at". An absent band is strictly LESS information than an unrankable one, so if
|
|
953
|
+
* unknown keeps, absent keeps. Dropping it would be this renderer deciding a filing is immaterial on
|
|
954
|
+
* the rater's behalf — the same claim tracker issue 274 removed from these cards for the same reason.
|
|
955
|
+
*
|
|
956
|
+
* A run that carries no bands at all still renders every card it was delivered with, which is what
|
|
957
|
+
* clause F asks for; it now falls out of the rule instead of being carved around it.
|
|
958
|
+
*/
|
|
959
|
+
function registerCardsOnPage(cards, mark, framework) {
|
|
960
|
+
return cards.filter((v) => !atLowestBand(framework, readBandFor(mark, v?.record?.recordId)));
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* DID THE RATER PUT THIS FILING ON THE LADDER'S LOWEST RUNG? (tracker issue 331 A.3)
|
|
965
|
+
*
|
|
966
|
+
* The ladder runs worst-first, so the lowest rung is the LAST entry. A filing the rater put there is one
|
|
967
|
+
* the rater called manageable, and 331 keeps those in the filings table rather than on a card: three
|
|
968
|
+
* cards whose own text says the filing does not bear materially on the rating cost the reader more than
|
|
969
|
+
* they told him.
|
|
970
|
+
*
|
|
971
|
+
* Stated as "is it AT the lowest rung" rather than "is it above it", because that is the only direction
|
|
972
|
+
* a caller may act on. Every other answer — a rung higher up, a word this build cannot place on the
|
|
973
|
+
* run's own ladder, no band at all — is a filing that keeps its card. An unplaceable word is not a band
|
|
974
|
+
* this function may quietly demote: the rater said something, and the safe reading of something we
|
|
975
|
+
* cannot rank is that it is worth pointing at. Absence says even less, so it keeps the card too.
|
|
976
|
+
*/
|
|
977
|
+
function atLowestBand(framework, band) {
|
|
978
|
+
const ladder = Array.isArray(framework?.bands) ? framework.bands : [];
|
|
979
|
+
const word = String(band ?? '').trim().toLowerCase();
|
|
980
|
+
if (!word || !ladder.length) return false;
|
|
981
|
+
const lowest = String(ladder[ladder.length - 1]?.label ?? '').trim().toLowerCase();
|
|
982
|
+
return Boolean(lowest) && word === lowest;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/** The rater's band for one filing, off the row that names it. `null` when the rater gave none. */
|
|
986
|
+
function readBandFor(mark, recordId) {
|
|
987
|
+
const id = String(recordId ?? '').trim();
|
|
988
|
+
if (!id) return null;
|
|
989
|
+
const row = (Array.isArray(mark?.registerReads) ? mark.registerReads : [])
|
|
990
|
+
.find((x) => String(x?.recordId ?? '').trim() === id);
|
|
991
|
+
return String(row?.band ?? '').trim() || null;
|
|
992
|
+
}
|
|
993
|
+
|
|
700
994
|
function registerCardViews(mark, framework, registerRecords) {
|
|
701
995
|
if (!registerRecords || registerRecords.unavailable) return { cards: [], entry: null, promoted: 0 };
|
|
702
996
|
const entry = recordsForMark(registerRecords, mark?.name);
|
|
@@ -728,9 +1022,13 @@ function registerCardViews(mark, framework, registerRecords) {
|
|
|
728
1022
|
* is gone; what tells the two apart on the page is where the finding came from, which is the vocabulary
|
|
729
1023
|
* the clearance reports already use for exactly this.
|
|
730
1024
|
*
|
|
731
|
-
*
|
|
732
|
-
* here
|
|
733
|
-
*
|
|
1025
|
+
* THE BAND CHIP IS DRAWN ONLY WHEN THE RATER SENT ONE, and that condition is the whole rule. The old note
|
|
1026
|
+
* here said "no band chip and no `bandStop`, ever: a rung of the run's ladder would be a rating nobody
|
|
1027
|
+
* performed" — which was true for as long as nothing could carry the rater's rating of an individual
|
|
1028
|
+
* filing. `registerReads[].band` now can (tracker issue 274), so the objection is answered where it was
|
|
1029
|
+
* raised: with a band, the rating WAS performed, by the seat, in the framework's own words, and the chip
|
|
1030
|
+
* states it. With no band the old rule stands unchanged — --faint rail, no chip, nothing claimed — and
|
|
1031
|
+
* that is still what every archived run renders.
|
|
734
1032
|
*
|
|
735
1033
|
* THE LINE UNDER THE STATEMENT DESCRIBES THE CARD, NOT THE RATING. It used to deny
|
|
736
1034
|
* that the rating turned on this filing, which this function has no way to know and which a delivered
|
|
@@ -759,28 +1057,117 @@ function sourceChips(v) {
|
|
|
759
1057
|
return `${commonLaw ? '<span class="src cl">Common law</span>' : ''}${register ? '<span class="src reg">Register</span>' : ''}`;
|
|
760
1058
|
}
|
|
761
1059
|
|
|
762
|
-
|
|
1060
|
+
// ── THE REVIEWER'S NOTES, ON THE REPORT ─────────────────────────────────────────────────
|
|
1061
|
+
//
|
|
1062
|
+
// OWNER RULING, 2026-09-07: there is one report and the person who ran Clearotron reads it — keeping
|
|
1063
|
+
// this material off the page "just adds confusion for where data is lost". This replaces the earlier
|
|
1064
|
+
// split under which the notes went to the audit workbook alone (the header of this file and
|
|
1065
|
+
// publish/knockout.mjs carried that rule; both now say what replaced it). The workbook keeps them too:
|
|
1066
|
+
// this adds a surface, it does not move one.
|
|
1067
|
+
//
|
|
1068
|
+
// LABELLED, NEVER MERGED. They render in the established `.internal` purple convention report.css
|
|
1069
|
+
// already defines — the same one the clearance report uses for this material — so a reader can see whose
|
|
1070
|
+
// voice a line is in. Merging them into the client-voiced body would make the reviewer's asides read as
|
|
1071
|
+
// findings about the mark, which is the one way this ruling could produce a worse document.
|
|
1072
|
+
const REVIEWER_NOTES_LEGEND = 'Purple notes are for the reviewing lawyer. Remove them before this goes to the client.';
|
|
1073
|
+
|
|
1074
|
+
// The clearance lane's own label, copied rather than re-worded (tracker issue 276). One spelling across
|
|
1075
|
+
// both products is the point: a reader who has seen it on a clearance report knows what it means here.
|
|
1076
|
+
const USE_CHECK_LABEL = 'Use-check source:';
|
|
1077
|
+
|
|
1078
|
+
/** The owner lookup covering a filing, joined by recordId. `null` when this run owed that filing none. */
|
|
1079
|
+
function ownerCheckFor(ownerChecks, recordId) {
|
|
1080
|
+
const id = String(recordId ?? '').trim();
|
|
1081
|
+
if (!id) return null;
|
|
1082
|
+
return (Array.isArray(ownerChecks) ? ownerChecks : [])
|
|
1083
|
+
.find((c) => (Array.isArray(c?.recordIds) ? c.recordIds : []).some((x) => String(x).trim() === id)) ?? null;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// The two-place sort lives in findings-model.mjs (splitKnockoutNotes) because the predelivery lint
|
|
1087
|
+
// needs the same answer: the page files each note, and the reviewer warns a writer whose note will file
|
|
1088
|
+
// the way they did not intend. One reader, so the two can never disagree.
|
|
1089
|
+
/**
|
|
1090
|
+
* "About this request" — what was asked, and any flag on the asking (tracker issue 331 A.1).
|
|
1091
|
+
*
|
|
1092
|
+
* WHAT WAS ASKED IS CODE-OWNED. It is read off the run's own frozen instructed scope, never off model
|
|
1093
|
+
* prose, so the line states the request the run was given rather than a paraphrase of it. An archived run
|
|
1094
|
+
* that carries no such sidecar renders the flags alone, and a run with neither renders nothing at all —
|
|
1095
|
+
* the block never appears empty and never appears with a heading over nothing.
|
|
1096
|
+
*
|
|
1097
|
+
* THE FLAGS ARE THE REVIEWER'S OWN WORDS, unedited. This surface moves them; it does not rewrite them.
|
|
1098
|
+
* They keep the purple convention here exactly as they wear it under the cards, which is also what keeps
|
|
1099
|
+
* them off the export: the strip is one rule on .internal and it reaches both places.
|
|
1100
|
+
*/
|
|
1101
|
+
function aboutRequestBlock(scope, requestNotes) {
|
|
1102
|
+
const goods = String(scope?.goods ?? '').trim();
|
|
1103
|
+
const classes = (Array.isArray(scope?.classes) ? scope.classes : []).filter((c) => c || c === 0);
|
|
1104
|
+
const jx = (Array.isArray(scope?.jurisdictions) ? scope.jurisdictions : []).map((t) => territoryName(t)).filter(Boolean);
|
|
1105
|
+
const asked = [
|
|
1106
|
+
classes.length ? `Class${classes.length === 1 ? '' : 'es'} ${classes.join(', ')}` : '',
|
|
1107
|
+
goods,
|
|
1108
|
+
].filter(Boolean).join(' — ');
|
|
1109
|
+
const where = jx.length ? `Searched in ${listWords(jx)}.` : '';
|
|
1110
|
+
const flags = (requestNotes ?? []).filter(Boolean);
|
|
1111
|
+
if (!asked && !where && !flags.length) return '';
|
|
1112
|
+
return `<div class="ko-req">
|
|
1113
|
+
<span class="ko-lbl2">About this request</span>
|
|
1114
|
+
${asked ? `<p>${esc(asked)}</p>` : ''}
|
|
1115
|
+
${where ? `<p>${esc(where)}</p>` : ''}
|
|
1116
|
+
${flags.length ? `<div class="internal ko-reqflag">${
|
|
1117
|
+
flags.map((n) => `<p class="ko-bul">${inlineMd(n)}</p>`).join('')}</div>` : ''}
|
|
1118
|
+
</div>`;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
function reviewerNotesBlock(m) {
|
|
1122
|
+
const notes = splitKnockoutNotes(m).name;
|
|
1123
|
+
if (!notes.length) return '';
|
|
1124
|
+
return `<div class="internal">
|
|
1125
|
+
<span class="tag">For the reviewing lawyer</span>
|
|
1126
|
+
${notes.map((n) => `<p class="ko-bul">${inlineMd(n)}</p>`).join('')}
|
|
1127
|
+
</div>`;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
function registerFindingBlock(v, markIndex, reads = null, framework = null, ownerChecks = []) {
|
|
763
1131
|
const r = v.record;
|
|
764
1132
|
// — THE RATER'S OWN READ OF THIS FILING, when it recorded one. `registerReads` is
|
|
765
1133
|
// joined to the record store by the validator, so a row that reaches here names a filing this run
|
|
766
1134
|
// actually holds. With no row the neutral line stands, and the neutral line is TRUE: it describes the
|
|
767
1135
|
// card. That is why the field can be optional without the page ever asserting something false.
|
|
768
|
-
const
|
|
769
|
-
.map((x) => ({ id: String(x?.recordId ?? '').trim(), text: String(x?.read ?? '').trim() }))
|
|
770
|
-
.find((x) => x.id && x.id === String(r?.recordId ?? '').trim())
|
|
1136
|
+
const row = (Array.isArray(reads) ? reads : [])
|
|
1137
|
+
.map((x) => ({ id: String(x?.recordId ?? '').trim(), text: String(x?.read ?? '').trim(), band: String(x?.band ?? '').trim() }))
|
|
1138
|
+
.find((x) => x.id && x.id === String(r?.recordId ?? '').trim());
|
|
1139
|
+
const read = row?.text;
|
|
1140
|
+
// The band rides the SAME row as the read and is independently optional: a read with no band prints
|
|
1141
|
+
// exactly as it did before this field existed. The validator has already checked the word against the
|
|
1142
|
+
// frozen ladder, so `bandStop` resolves a real stop rather than falling through to a default that would
|
|
1143
|
+
// colour an unknown word as though it were rated.
|
|
1144
|
+
const band = row?.band || null;
|
|
1145
|
+
const stop = band ? bandStop(framework, band) : null;
|
|
1146
|
+
// ── WHERE THE OWNER'S TRADE WAS LOOKED UP (tracker issue 276) ──────────────────────────────────
|
|
1147
|
+
//
|
|
1148
|
+
// The source is the DRIVER'S, joined by this filing's own recordId — never a URL the seat typed. That
|
|
1149
|
+
// is the whole reason a reader can trust it: the row exists because the driver made the call, so
|
|
1150
|
+
// "asserting a no-result without issuing a query" is not a thing this surface can express.
|
|
1151
|
+
//
|
|
1152
|
+
// ABSENT ON A RUN THAT OWED NO CHECK, and that silence is correct: no line at all says nothing, while
|
|
1153
|
+
// a line reading "no result" on a filing nobody was asked about would claim a search that never ran.
|
|
1154
|
+
const useCheck = ownerCheckFor(ownerChecks, r?.recordId);
|
|
1155
|
+
const useCheckSource = useCheck?.source ?? null;
|
|
771
1156
|
const meta = [r.owner ? esc(r.owner) : 'proprietor not stated', r.territory ? esc(r.territory) : null]
|
|
772
1157
|
.filter(Boolean).join(' · ');
|
|
773
1158
|
const receipt = isHttpUrl(r.url) ? linkOrText(r.url) : esc(r.recordId ?? 'no record address supplied');
|
|
774
1159
|
return `<div class="card ko-find" data-ko-mark="${Number(markIndex)}" data-ko-ord="${Number(v.ordinal)}">
|
|
775
1160
|
<div class="top">
|
|
776
|
-
<div class="rail" style="background:var(--faint)"></div>
|
|
1161
|
+
<div class="rail" style="background:var(${stop ?? '--faint'})"></div>
|
|
777
1162
|
<div class="body">
|
|
778
1163
|
<div class="cardhead">
|
|
779
|
-
<span class="fnum">${esc(v.ref)}</span><span class="who">${esc(r.mark ?? 'Unnamed filing')}</span
|
|
1164
|
+
<span class="fnum">${esc(v.ref)}</span><span class="who">${esc(r.mark ?? 'Unnamed filing')}</span>${
|
|
1165
|
+
band ? `<span class="ko-findband" style="background:var(${stop})">${esc(band)}</span>` : ''}<span class="src reg">Register</span>
|
|
780
1166
|
</div>
|
|
781
1167
|
<p class="ko-findmeta">${meta}</p>
|
|
782
1168
|
<p class="ko-findnet">${esc(v.statement)}</p>
|
|
783
|
-
|
|
1169
|
+
${basisLine(band, read)}
|
|
1170
|
+
${useCheck ? `<p class="ko-findev">${esc(USE_CHECK_LABEL)} ${isHttpUrl(useCheckSource) ? linkOrText(useCheckSource) : esc(useCheckSource)}</p>` : ''}
|
|
784
1171
|
<p class="ko-findev">Register record: ${receipt}</p>
|
|
785
1172
|
</div>
|
|
786
1173
|
</div>
|
|
@@ -900,34 +1287,117 @@ function coverageClause(mark, registerCounts, probeRan) {
|
|
|
900
1287
|
// NOTHING IS DISCARDED. Where a run carries both the typed fields and prose bullets the bullets survive
|
|
901
1288
|
// under a collapsed "Full narrative" — the reader who wants the long form still has it, one click away,
|
|
902
1289
|
// and no sentence the stage wrote is dropped on the floor.
|
|
903
|
-
|
|
1290
|
+
/**
|
|
1291
|
+
* THE LABELS, IN THE READER'S WORDS (tracker issue 331 A.2).
|
|
1292
|
+
*
|
|
1293
|
+
* The old pair was "What holds it there" and "What would move it", 9.5px grey capitals. The owner read
|
|
1294
|
+
* the first one and asked "what holds what?" — so the fix is not a synonym in the same style, it is a
|
|
1295
|
+
* label that carries the band's own word and answers the question by itself.
|
|
1296
|
+
*
|
|
1297
|
+
* factors → "Why High" (the mark's own band)
|
|
1298
|
+
* counterFactors → "Why not Very High" (the rung ABOVE it on the run's own ladder)
|
|
1299
|
+
* mitigation → "What would lower the risk"
|
|
1300
|
+
*
|
|
1301
|
+
* The ladder runs worst-first, so the rung above is the PREVIOUS entry. At the top rung there is no
|
|
1302
|
+
* higher band to name and the honest label is "What keeps it here" — the same question, asked where the
|
|
1303
|
+
* comparative form has no answer. A band this build cannot find on the ladder gets that label too,
|
|
1304
|
+
* rather than a comparative naming a rung that may not exist.
|
|
1305
|
+
*/
|
|
1306
|
+
function counterLabel(framework, band) {
|
|
1307
|
+
const ladder = Array.isArray(framework?.bands) ? framework.bands : [];
|
|
1308
|
+
const i = ladder.findIndex((b) => String(b?.label ?? '').trim().toLowerCase() === String(band ?? '').trim().toLowerCase());
|
|
1309
|
+
const up = i > 0 ? String(ladder[i - 1]?.label ?? '').trim() : '';
|
|
1310
|
+
return up ? `Why not ${up}` : 'What keeps it here';
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
const ASSESSMENT_FOLD_LABEL = 'Read the full assessment';
|
|
1314
|
+
|
|
1315
|
+
/** The scope block's own words, as one string, so the caveat filter reads exactly what the page prints. */
|
|
1316
|
+
const SCOPE_BLOCK_TEXT = 'What this is. A fast screen for obvious blockers to using each name, from '
|
|
1317
|
+
+ 'marketplace and web use plus a count of register filings. What it is not. A clearance search. We '
|
|
1318
|
+
+ 'drew no register conclusions and give no filing advice. A name that passes here is not clear; it '
|
|
1319
|
+
+ 'goes on to clearance. Every conflict above links to the material we found. The audit workbook holds '
|
|
1320
|
+
+ 'every search run, every empty result and the working notes. Register data.';
|
|
1321
|
+
|
|
1322
|
+
/** Words that carry no claim, so their presence or absence says nothing about what a sentence asserts. */
|
|
1323
|
+
const STOPWORDS = new Set(['a', 'an', 'and', 'are', 'as', 'at', 'be', 'been', 'but', 'by', 'can', 'do',
|
|
1324
|
+
'does', 'each', 'for', 'from', 'has', 'have', 'here', 'in', 'is', 'it', 'its', 'no', 'not', 'of', 'on',
|
|
1325
|
+
'or', 'that', 'the', 'their', 'them', 'there', 'these', 'they', 'this', 'to', 'up', 'was', 'we', 'were',
|
|
1326
|
+
'what', 'when', 'which', 'will', 'with', 'you', 'your']);
|
|
1327
|
+
|
|
1328
|
+
const contentWords = (s) => String(s ?? '').toLowerCase().replace(/[^a-z0-9\s-]/g, ' ')
|
|
1329
|
+
.split(/\s+/).filter((w) => w.length > 2 && !STOPWORDS.has(w));
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Does this line assert anything the reference text does not already assert?
|
|
1333
|
+
*
|
|
1334
|
+
* TRUE unless every content word in the line is already in the reference. An empty line has nothing to
|
|
1335
|
+
* say and returns false; a line with one unfamiliar word is kept. Singular/plural is folded so that
|
|
1336
|
+
* "conclusion" does not read as new beside "conclusions".
|
|
1337
|
+
*/
|
|
1338
|
+
function saysSomethingNew(line, reference) {
|
|
1339
|
+
// The stem must be IDEMPOTENT on the singular, or the fold does nothing: an earlier form stripped
|
|
1340
|
+
// "es" and turned "gives" into "giv" while leaving "give" alone, so the two never matched and every
|
|
1341
|
+
// caveat looked new. Strip one trailing "s" and nothing else.
|
|
1342
|
+
const stem = (w) => w.replace(/ies$/, 'y').replace(/s$/, '');
|
|
1343
|
+
const known = new Set(contentWords(reference).map(stem));
|
|
1344
|
+
const words = contentWords(line);
|
|
1345
|
+
if (!words.length) return false;
|
|
1346
|
+
return words.some((w) => !known.has(stem(w)));
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
function readBlock(m, framework) {
|
|
904
1350
|
const factors = (m.factors ?? []).filter((s) => typeof s === 'string' && s.trim());
|
|
905
1351
|
const counter = (m.counterFactors ?? []).filter((s) => typeof s === 'string' && s.trim());
|
|
906
1352
|
const structured = Boolean(m.basis || factors.length || counter.length || m.mitigation);
|
|
907
1353
|
const bullets = (m.bullets ?? []).map((b) => `<li>${inlineMd(b)}</li>`).join('');
|
|
908
1354
|
if (!structured) return bullets ? `<ul class="ko-bul">${bullets}</ul>` : '';
|
|
1355
|
+
const assessment = String(m.assessment ?? '').trim();
|
|
1356
|
+
const band = String(m.rating ?? '').trim();
|
|
909
1357
|
return [
|
|
910
1358
|
m.basis ? `<p class="ko-basisline">${inlineMd(m.basis)}</p>` : '',
|
|
911
|
-
factors.length ? `<
|
|
912
|
-
|
|
1359
|
+
factors.length ? `<div class="ko-why-band">${band ? `<span class="ko-lbl2">Why ${esc(band)}</span>` : ''}<ul class="ko-bul">${
|
|
1360
|
+
factors.map((f) => `<li>${inlineMd(f)}</li>`).join('')}</ul></div>` : '',
|
|
1361
|
+
counter.length ? `<div class="ko-counter"><span class="ko-lbl2">${esc(counterLabel(framework, band))}</span><ul class="ko-bul">${
|
|
913
1362
|
counter.map((f) => `<li>${inlineMd(f)}</li>`).join('')}</ul></div>` : '',
|
|
914
|
-
m.mitigation ? `<div class="ko-mitig"><span class="ko-
|
|
915
|
-
|
|
1363
|
+
m.mitigation ? `<div class="ko-mitig"><span class="ko-lbl2">What would lower the risk</span><p>${inlineMd(m.mitigation)}</p></div>` : '',
|
|
1364
|
+
// ── THE ASSESSMENT REPLACES THE "FULL NARRATIVE" FOLD (tracker issue 331 A.2) ────────────────────
|
|
1365
|
+
//
|
|
1366
|
+
// The model writes both. `bullets` (five) say in other words what `factors` (four) already say
|
|
1367
|
+
// visible above; `assessment` is the long-form read under its own four headings, and until now the
|
|
1368
|
+
// page rendered it NOWHERE — validated, carried in report-data.json and the workbook, never shown.
|
|
1369
|
+
// The owner found the bullets fold by accident and called it the most useful block on the page; the
|
|
1370
|
+
// assessment is the better version of the same thing.
|
|
1371
|
+
//
|
|
1372
|
+
// `bullets` is NOT dropped from the record — knockoutReportData still carries it and the workbook
|
|
1373
|
+
// still writes it. What retires is one fold on one page, replaced by a longer answer to the same
|
|
1374
|
+
// question. 331 rejects dropping the field itself, and this does not.
|
|
1375
|
+
//
|
|
1376
|
+
// CLAUSE F. An archived run carries bullets and no assessment: it keeps the fold it was delivered
|
|
1377
|
+
// with, under its own old label. The fallback is the old block, never an empty new one.
|
|
1378
|
+
assessment
|
|
1379
|
+
? `<details class="ko-full"><summary>${esc(ASSESSMENT_FOLD_LABEL)}</summary><div class="ko-assess">${mdParagraphs(assessment)}</div></details>`
|
|
1380
|
+
: (bullets ? `<details class="ko-full"><summary>Full narrative</summary><ul class="ko-bul">${bullets}</ul></details>` : ''),
|
|
916
1381
|
].filter(Boolean).join('');
|
|
917
1382
|
}
|
|
918
1383
|
|
|
919
|
-
function analysisSection(marks, framework, { registerCounts = null, probeRan = false, registerRecords = null } = {}) {
|
|
1384
|
+
function analysisSection(marks, framework, { registerCounts = null, probeRan = false, registerRecords = null, ownerChecks = [] } = {}) {
|
|
920
1385
|
const cards = marks.map((m, markIndex) => {
|
|
921
1386
|
const stop = bandStop(framework, m.rating);
|
|
922
|
-
const bullets = readBlock(m);
|
|
1387
|
+
const bullets = readBlock(m, framework);
|
|
923
1388
|
// — the promoted register filings, in the SAME list as the common-law conflicts. They render
|
|
924
1389
|
// after the typed findings and that position is not a rank: a card with no band already sorts last
|
|
925
1390
|
// under compareKnockoutBlockingPower, so appending them is the ladder's own rule applied to a row
|
|
926
1391
|
// that has no rung, not a new one invented for the register.
|
|
927
1392
|
const reg = registerCardViews(m, framework, registerRecords);
|
|
928
|
-
const
|
|
929
|
-
const
|
|
930
|
-
|
|
1393
|
+
const drawn = registerCardsOnPage(reg.cards, m, framework);
|
|
1394
|
+
const regBlocks = drawn.map((v) => registerFindingBlock(v, markIndex, m?.registerReads, framework, ownerChecks)).join('');
|
|
1395
|
+
// The overflow counts what is NOT on the page against what met the promotion test — cards held back
|
|
1396
|
+
// by the cap and cards the rater put on the lowest rung alike, because from the reader's side they
|
|
1397
|
+
// are the same fact: further filings for this name, all of them listed below.
|
|
1398
|
+
const held = reg.promoted - drawn.length;
|
|
1399
|
+
const overflow = held > 0
|
|
1400
|
+
? `<p class="ko-bul">${esc(`${held} further filing${held === 1 ? '' : 's'} for this name met the same test — every one of them is in the filings section below.`)}</p>`
|
|
931
1401
|
: '';
|
|
932
1402
|
// THE DEFECT THIS CLOSES. This line was `(m.findings ??).filter((f) => f?.url)`, and a
|
|
933
1403
|
// typed finding has no `url` — so every conflict was dropped from the page and a mark whose findings
|
|
@@ -950,11 +1420,17 @@ function analysisSection(marks, framework, { registerCounts = null, probeRan = f
|
|
|
950
1420
|
<div>
|
|
951
1421
|
${body || '<p class="ko-bul">No adverse signals recorded for this name on this screen.</p>'}
|
|
952
1422
|
${m.degraded ? `<p class="ko-degraded">${esc(DEGRADED_NOTE)}</p>` : ''}
|
|
1423
|
+
${reviewerNotesBlock(m)}
|
|
953
1424
|
<p class="ko-reg">${esc(registerLine(m, registerCounts, probeRan, registerRecords, reg.cards))}</p>
|
|
954
1425
|
</div>
|
|
955
1426
|
</div>`;
|
|
956
1427
|
}).join('');
|
|
957
|
-
|
|
1428
|
+
// The legend rides the panel and only when a note is actually on it — a standing sentence explaining a
|
|
1429
|
+
// colour no reader can see would be the report describing a convention it did not use.
|
|
1430
|
+
const anyNotes = marks.some((m) => (Array.isArray(m?.purpleNotes) ? m.purpleNotes : [])
|
|
1431
|
+
.some((n) => String(n ?? '').trim()));
|
|
1432
|
+
const legend = anyNotes ? `<p class="ko-refnote">${esc(REVIEWER_NOTES_LEGEND)}</p>` : '';
|
|
1433
|
+
return `<div class="panel ko-glance">${legend}${cards}</div>`;
|
|
958
1434
|
}
|
|
959
1435
|
|
|
960
1436
|
// The method line names EXACTLY what ran, and its wording is doctrine — with counts on the page, "register
|
|
@@ -1012,87 +1488,6 @@ function depthStrip(note) {
|
|
|
1012
1488
|
// says what the lines under it are. It is not a filter and it rewrites no caveat.
|
|
1013
1489
|
const CAVEAT_LEAD = 'This screen also carries the following limits:';
|
|
1014
1490
|
|
|
1015
|
-
/**
|
|
1016
|
-
* WHAT THIS RUN SEARCHED AND DID NOT, FROM THE RUN'S OWN POLICY.
|
|
1017
|
-
*
|
|
1018
|
-
* The line this replaces was composed from `registerCounts` — an ARTIFACT — and said "Common-law/
|
|
1019
|
-
* marketplace screen only, register searches are addressed separately" whenever no counts were present.
|
|
1020
|
-
* That reads the absence of a result as a statement of scope, which is the class this repo keeps paying
|
|
1021
|
-
* for: a run INSTRUCTED to take register counts whose provider refused printed the same sentence as a
|
|
1022
|
-
* run never instructed to take them at all. One of those is a scope statement and the other is a gap in
|
|
1023
|
-
* the record, and a client cannot tell them apart.
|
|
1024
|
-
*
|
|
1025
|
-
* The clearance report composes its scope from the run's frozen components (`productCoverageNote`,
|
|
1026
|
-
* search-policy.mjs) and this now does the same, from the same object, so the two lanes cannot describe
|
|
1027
|
-
* the same component in different words.
|
|
1028
|
-
*
|
|
1029
|
-
* THE ARTIFACT IS STILL REPORTED — separately, and as what it is. Where the policy says a component ran
|
|
1030
|
-
* and its output is missing, that is disclosed as a gap rather than folded into "we did not do it".
|
|
1031
|
-
*
|
|
1032
|
-
* @returns {string[]} lines, most load-bearing first. Empty when there is no policy to read, and the
|
|
1033
|
-
* caller falls back to the artifact-derived sentence rather than printing nothing.
|
|
1034
|
-
*/
|
|
1035
|
-
export function knockoutScopeLines(policy, { registerCounts = null, probeRan = false } = {}) {
|
|
1036
|
-
const c = policy?.components;
|
|
1037
|
-
if (!c) return [];
|
|
1038
|
-
const lines = [];
|
|
1039
|
-
lines.push('This is a screen, not a clearance search: it triages names against use we can see, '
|
|
1040
|
-
+ 'and makes no filing recommendation.');
|
|
1041
|
-
if (c.registerProbe) {
|
|
1042
|
-
const who = registerCounts?.providerLabel ?? registerCounts?.provider ?? null;
|
|
1043
|
-
// THE BASIS RIDES WITH THE COMPONENT THAT NEEDS IT, in methodLine's own words rather than new ones.
|
|
1044
|
-
// Composing this section from the policy moved methodLine off the page for every run that HAS a
|
|
1045
|
-
// policy — which is every live run — and took COUNT_BASIS and "Counting is not searching" with it.
|
|
1046
|
-
// That is the sentence saying a count weighs nothing and decides nothing, on the page that prints
|
|
1047
|
-
// the counts. `runner.knockout-e2e.test.mjs` caught it and this branch called it pre-existing;
|
|
1048
|
-
// it is not — origin/main's renderer passes that arm 3/3 in the same worktree.
|
|
1049
|
-
lines.push(registerCounts
|
|
1050
|
-
? `Registers were searched for a hit-count per name${who ? ` on ${who}` : ''}, and the filings behind `
|
|
1051
|
-
+ `the narrow counts are listed below. ${COUNT_BASIS} Counting is not searching: no register `
|
|
1052
|
-
+ `conclusions, no filing advice, and a full register clearance is a separate piece of work.`
|
|
1053
|
-
: 'Registers were searched for a hit-count per name, and no counts reached this report — '
|
|
1054
|
-
+ 'that is a gap in the record for this run, not a statement that registers were left out.');
|
|
1055
|
-
} else if (c.registerProbe === false) {
|
|
1056
|
-
lines.push(probeRan
|
|
1057
|
-
? 'Registers were not part of this search. A register count screen ran separately; full register analysis is its own piece of work.'
|
|
1058
|
-
: 'Registers were not searched in this search.');
|
|
1059
|
-
}
|
|
1060
|
-
// A COMPONENT THE POLICY DOES NOT MENTION IS NOT A COMPONENT THAT WAS OFF. Same rule as the missing
|
|
1061
|
-
// policy above, one level down: `undefined` is silence, and silence is not `false`. Reached only when
|
|
1062
|
-
// `components` arrives without this key — every row in search-policy.mjs states all three, so the
|
|
1063
|
-
// product table cannot produce it; `{ ...policyFor(product)?.components, ...r.components }` can, when
|
|
1064
|
-
// the product resolves to nothing. Driven before this line existed: an empty `components` printed
|
|
1065
|
-
// "Registers were not searched in this search" on a report that was carrying a register hit-count
|
|
1066
|
-
// table, which is the document contradicting itself in the section that exists to state scope. Saying
|
|
1067
|
-
// nothing is the honest answer, and it needs no new sentence in front of a client.
|
|
1068
|
-
//
|
|
1069
|
-
// THE TWO BELOW STAY `!== true`, and the difference is the population rather than the principle.
|
|
1070
|
-
// `registerProbe` is true on two knockout rows (knockout-search, knockout-register), so silence about
|
|
1071
|
-
// it is genuinely ambiguous. `commonLawGrid` and `jxLanes` are false on EVERY row this template
|
|
1072
|
-
// renders — they are what the clearance search is — so silence there states a thing that is true of
|
|
1073
|
-
// the whole population, and making them conditional would drop a disclosure the clearance report
|
|
1074
|
-
// makes about itself. Symmetry here would cost a client the sentence naming the lane they did not buy.
|
|
1075
|
-
// Stated because the clearance report states its own absence of them, in these words. A reader
|
|
1076
|
-
// comparing two documents must not have to infer that a lane is missing from its silence.
|
|
1077
|
-
if (c.commonLawGrid !== true) {
|
|
1078
|
-
lines.push('The systematic common-law grid sweep is not part of this search — that is the clearance search.');
|
|
1079
|
-
}
|
|
1080
|
-
if (c.jxLanes !== true) {
|
|
1081
|
-
lines.push('The per-jurisdiction native-script deep dive is not part of this search.');
|
|
1082
|
-
}
|
|
1083
|
-
return lines;
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
function methodLine(registerCounts, probeRan, { citedFindings = 0, uncitedFindings = 0 } = {}) {
|
|
1087
|
-
const receipts = (citedFindings && !uncitedFindings)
|
|
1088
|
-
? ` Every conflict named above cites material held in this run's own research payload for that name.`
|
|
1089
|
-
: '';
|
|
1090
|
-
return (registerCounts
|
|
1091
|
-
? `Common-law/marketplace screen, plus a register HIT-COUNT per name on ${registerCounts.providerLabel ?? registerCounts.provider ?? 'the register'}. ${COUNT_BASIS} `
|
|
1092
|
-
+ `Counting is not searching: no register conclusions, no filing advice, and a full register clearance is a separate piece of work.`
|
|
1093
|
-
: `Common-law/marketplace screen only — register searches are addressed separately${probeRan ? ' (a register count screen ran; full register analysis follows separately)' : ''}. `
|
|
1094
|
-
+ `A knockout screen is triage, not a clearance search: no register conclusions, no filing advice.`) + receipts;
|
|
1095
|
-
}
|
|
1096
1491
|
|
|
1097
1492
|
/**
|
|
1098
1493
|
* Render the knockout report.
|
|
@@ -1114,11 +1509,20 @@ function methodLine(registerCounts, probeRan, { citedFindings = 0, uncitedFindin
|
|
|
1114
1509
|
export function renderKnockoutHtml(findings, framework, {
|
|
1115
1510
|
runId, overall, issued = null, auditFile = null, probeRan = false, registerCounts = null,
|
|
1116
1511
|
registerRecords = null,
|
|
1512
|
+
// The driver's own record of the owner lookups it ran (tracker issue 276). Defaults to [] so an
|
|
1513
|
+
// archived run that predates the lane renders exactly as it was delivered.
|
|
1514
|
+
ownerChecks = [],
|
|
1117
1515
|
identity = null, matter = null, homeHref = null, chromeHref = null, depthNote = null,
|
|
1118
1516
|
// — the run's FROZEN policy, so the scope section states what this run was
|
|
1119
1517
|
// instructed to do rather than what its artifacts happen to show. Defaults to null, and an archived
|
|
1120
1518
|
// run that carries none keeps the artifact-derived sentence it was delivered with.
|
|
1121
1519
|
searchPolicy = null,
|
|
1520
|
+
// — the run's own frozen instructed scope (tracker issue 331 A.1): the goods, classes and
|
|
1521
|
+
// territories the requester asked for, in the requester's words. Defaults to null, and an archived run
|
|
1522
|
+
// that carries no such sidecar renders "About this request" from its request-level notes alone, or not
|
|
1523
|
+
// at all when it has none. Never derived from model prose — this is what was ASKED, not what was said
|
|
1524
|
+
// about it.
|
|
1525
|
+
instructedScope = null,
|
|
1122
1526
|
// — the run's frozen delivery overlay. It defaults to null, which is the NO-OPINION state and
|
|
1123
1527
|
// renders the same plain "Privileged & Confidential" this template always printed — so the ~15 unit
|
|
1124
1528
|
// fixtures and both render-check scripts, none of which pass one, are unchanged by its arrival.
|
|
@@ -1145,7 +1549,12 @@ export function renderKnockoutHtml(findings, framework, {
|
|
|
1145
1549
|
const allViews = marks.flatMap((m) => knockoutFindingViews(m, { manifest: framework }));
|
|
1146
1550
|
const citedFindings = allViews.filter((v) => v.evidence.length).length;
|
|
1147
1551
|
const uncitedFindings = allViews.length - citedFindings;
|
|
1148
|
-
|
|
1552
|
+
// ── A ONE-NAME PAGE HAS NO INDEX (tracker issue 331 A.6) ────────────────────────────────────────
|
|
1553
|
+
//
|
|
1554
|
+
// The glance row exists to let a reader of a BATCH find the name they care about. With one name there
|
|
1555
|
+
// is nothing to index, and the row printed that name, its band and its classes for the first of three
|
|
1556
|
+
// times before the reader reached a single sentence of reading. On a batch it stays exactly as it was.
|
|
1557
|
+
const glance = marks.length > 1 ? glanceSection(marks, framework, registerCounts) : '';
|
|
1149
1558
|
const hasCounts = Boolean(registerCounts?.marks?.length);
|
|
1150
1559
|
// The register block is a table when counts were taken and a SENTENCE when they were not — never
|
|
1151
1560
|
// nothing. It renders in the place the numbers would have occupied, at the top of the section that
|
|
@@ -1154,7 +1563,24 @@ export function renderKnockoutHtml(findings, framework, {
|
|
|
1154
1563
|
const counts = hasCounts
|
|
1155
1564
|
? countsSection(marks, registerCounts)
|
|
1156
1565
|
: `<div class="panel"><p class="ko-tier">${esc(tierLine)}</p></div>`;
|
|
1157
|
-
|
|
1566
|
+
// ── A CAVEAT THAT SAYS NOTHING THE SCOPE BLOCK HAS NOT SAID IS NOT RENDERED (tracker issue 331 E) ──
|
|
1567
|
+
//
|
|
1568
|
+
// The four model-written caveats on the measured run overlap the fixed text completely — 331 item 9,
|
|
1569
|
+
// and 333 rule 4 ("say it once") fixes it at the source for runs written under that doctrine. This is
|
|
1570
|
+
// the reader for the ones already written.
|
|
1571
|
+
//
|
|
1572
|
+
// THE TEST IS SUBSET, NOT SIMILARITY, and the difference is the whole safety argument. A caveat is
|
|
1573
|
+
// dropped only when EVERY content word in it already appears in the scope block. A caveat making any
|
|
1574
|
+
// new claim brings at least one new content word with it and is kept — so this cannot silently delete
|
|
1575
|
+
// a disclosure, which is the one failure that would matter on a client-facing page. A similarity score
|
|
1576
|
+
// could; that is why there isn't one.
|
|
1577
|
+
const newCaveats = caveats.filter((c) => saysSomethingNew(c, SCOPE_BLOCK_TEXT));
|
|
1578
|
+
const analysis = analysisSection(marks, framework, { registerCounts, probeRan, registerRecords, ownerChecks });
|
|
1579
|
+
// The request-level notes, gathered across every mark on the document and rendered ONCE at the top.
|
|
1580
|
+
// They are about the asking, not about a name, so a batch repeating them per mark would be the same
|
|
1581
|
+
// sentence three times. reviewerNotesBlock renders the rest, under that mark's own cards.
|
|
1582
|
+
const requestNotes = marks.flatMap((m) => splitKnockoutNotes(m).request);
|
|
1583
|
+
const aboutRequest = aboutRequestBlock(instructedScope, requestNotes);
|
|
1158
1584
|
const provider = hasCounts ? (registerCounts.providerLabel ?? registerCounts.provider ?? 'the register') : null;
|
|
1159
1585
|
// The filings appendix renders only when the run produced a listing artifact — never on its absence,
|
|
1160
1586
|
// and never as an empty table. A knockout with no sidecar publishes exactly the counts-only document.
|
|
@@ -1165,7 +1591,10 @@ export function renderKnockoutHtml(findings, framework, {
|
|
|
1165
1591
|
// promoted filing that sentence sent a reader to a row that does not exist. A false pointer on the
|
|
1166
1592
|
// audit trail is worse than no pointer, and the honest fix is to narrow the claim rather than mint a
|
|
1167
1593
|
// second drill-through key for a card whose receipt is the register record itself.
|
|
1168
|
-
|
|
1594
|
+
// Counted over what the page DRAWS: the sentence explains a REG reference a reader can see, so a run
|
|
1595
|
+
// whose register cards are all held back needs no sentence about them.
|
|
1596
|
+
const registerCardCount = marks.reduce((n, m) =>
|
|
1597
|
+
n + registerCardsOnPage(registerCardViews(m, framework, registerRecords).cards, m, framework).length, 0);
|
|
1169
1598
|
const hasRecords = Boolean(registerRecords && (registerRecords.marks?.length || registerRecords.unavailable));
|
|
1170
1599
|
const filings = hasRecords ? filingsSection(marks, registerRecords) : '';
|
|
1171
1600
|
const onFieldSec = `<div class="sec"><span class="num">${num()}</span><h2>On-field conflicts</h2><span class="note">${hasCounts ? `register hit-counts (${esc(provider)}) and the read, per name` : 'what we found, per name'}</span></div>
|
|
@@ -1226,6 +1655,7 @@ window.addEventListener('beforeprint',o);})();</script>
|
|
|
1226
1655
|
${depthStrip(depthNote)}
|
|
1227
1656
|
<h1 class="mark">${esc(title)}</h1>
|
|
1228
1657
|
${productContext ? `<p class="ko-classes" style="font-size:13.5px;margin:0 0 16px">${inlineMd(productContext)}</p>` : ''}
|
|
1658
|
+
${aboutRequest}
|
|
1229
1659
|
${summary ? `<div class="sub">${mdParagraphs(summary)}</div>` : ''}
|
|
1230
1660
|
</header>
|
|
1231
1661
|
|
|
@@ -1247,14 +1677,31 @@ window.addEventListener('beforeprint',o);})();</script>
|
|
|
1247
1677
|
// FROM THE POLICY WHERE THERE IS ONE (tracker issue 1935). The fallback is not a tidy default: an
|
|
1248
1678
|
// archived run froze no policy, and re-rendering it must not invent a scope claim about a run
|
|
1249
1679
|
// nobody can now ask. It keeps the sentence it was delivered with.
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1680
|
+
// ── THE SCOPE BLOCK, WHOLE (tracker issue 331 E) ──────────────────────────────────────────────
|
|
1681
|
+
//
|
|
1682
|
+
// The composed lines said one thing five times in 362 words: "not a clearance" three times,
|
|
1683
|
+
// "proceeds to clearance" twice, and the count-basis sentence a second time after the counts table
|
|
1684
|
+
// had already carried it. This is the owner's replacement text, and its two halves are the two
|
|
1685
|
+
// questions a reader of a screen actually has.
|
|
1686
|
+
//
|
|
1687
|
+
// "Every conflict above links to the material we found" STAYS CONDITIONAL and that is not a
|
|
1688
|
+
// stylistic carry-over: said unconditionally it is an absence claim wider than what was examined,
|
|
1689
|
+
// which this file refuses elsewhere in the same words. It prints only when every rendered conflict
|
|
1690
|
+
// cites something.
|
|
1691
|
+
const linked = citedFindings && !uncitedFindings
|
|
1692
|
+
? ' Every conflict above links to the material we found.'
|
|
1693
|
+
: '';
|
|
1694
|
+
const source = registerCounts
|
|
1695
|
+
? ` Register data: ${registerCounts.providerLabel ?? registerCounts.provider ?? 'the register'}.`
|
|
1254
1696
|
: '';
|
|
1255
|
-
return
|
|
1697
|
+
return `<p class="ko-scope"><b>What this is.</b> A fast screen for obvious blockers to using each `
|
|
1698
|
+
+ `name, from marketplace and web use plus a count of register filings.</p>`
|
|
1699
|
+
+ `<p class="ko-scope"><b>What it is not.</b> A clearance search. We drew no register conclusions `
|
|
1700
|
+
+ `and give no filing advice. A name that passes here is not clear; it goes on to clearance.</p>`
|
|
1701
|
+
+ `<p class="ko-scope">${linked.trim()}${linked ? ' ' : ''}The audit workbook holds every search run, `
|
|
1702
|
+
+ `every empty result and the working notes.${source}</p>`;
|
|
1256
1703
|
})()}
|
|
1257
|
-
${
|
|
1704
|
+
${newCaveats.length ? `<p class="ko-scope" style="border-top:1px solid var(--line)">${CAVEAT_LEAD}<br>${newCaveats.map((c) => inlineMd(c)).join('<br>')}</p>` : ''}
|
|
1258
1705
|
${auditFile ? `<p class="ko-scope" style="border-top:1px solid var(--line)"><a href="${escAttr(auditFile)}">Download the audit workbook (Excel)</a> — every search run, every negative result, and the working notes behind these ratings.${
|
|
1259
1706
|
citedFindings ? ` The reference beside each common-law conflict above (for example <span class="mono">${esc(firstRef(marks, framework))}</span>) is its row on the workbook's Findings sheet.${
|
|
1260
1707
|
registerCardCount ? ` A <span class="mono">REG</span> reference is a register filing rather than a common-law conflict — it has no Findings row, and its receipt is the register record the card links.` : ''}` : ''}</p>` : ''}
|
|
@@ -1282,7 +1729,7 @@ window.addEventListener('beforeprint',o);})();</script>
|
|
|
1282
1729
|
* where the working notes live, and a data file that quietly re-admitted them would reopen exactly the
|
|
1283
1730
|
* leak this series closed.
|
|
1284
1731
|
*/
|
|
1285
|
-
export function knockoutReportData(findings, framework, { runId, codename, overall, issued, identity, registerCounts, registerRecords = null, url, auditFile, customerKey, matter }) {
|
|
1732
|
+
export function knockoutReportData(findings, framework, { runId, codename, overall, issued, identity, registerCounts, registerRecords = null, ownerChecks = [], url, auditFile, customerKey, matter }) {
|
|
1286
1733
|
const marks = findings?.marks ?? [];
|
|
1287
1734
|
return {
|
|
1288
1735
|
schema: 'report-data/1',
|
|
@@ -1324,6 +1771,39 @@ export function knockoutReportData(findings, framework, { runId, codename, overa
|
|
|
1324
1771
|
classesDriving: m.classesDriving ?? [],
|
|
1325
1772
|
degraded: Boolean(m.degraded),
|
|
1326
1773
|
points: m.bullets ?? [],
|
|
1774
|
+
// ── THE ASSESSMENT THE RUN ALREADY WROTE (tracker issue 274) ──────────────────────────────
|
|
1775
|
+
//
|
|
1776
|
+
// Seven keys the assess stage writes into knockout-findings.json reached this file as nothing.
|
|
1777
|
+
// They were not withheld by a rule — no code decided against them; this projection is an explicit
|
|
1778
|
+
// whitelist and nobody had added them, so an assistant drafting from this file could not see the
|
|
1779
|
+
// reasoning behind a rating it was drafting about.
|
|
1780
|
+
//
|
|
1781
|
+
// `assessment` is the sharpest case: publish substitutes it into `batch.executiveSummary` ONLY on
|
|
1782
|
+
// a multi-mark batch, so on a single-mark run — the common knockout — the mark's own opening read
|
|
1783
|
+
// was written, validated, and then dropped by both surfaces at once.
|
|
1784
|
+
//
|
|
1785
|
+
// `purpleNotes` is the reviewer's notes, and it is here by the owner's ruling of 2026-09-07: one
|
|
1786
|
+
// report, read by the person who ran Clearotron, because keeping material off it "just adds
|
|
1787
|
+
// confusion for where data is lost". They are LABELLED on the page rather than merged into the
|
|
1788
|
+
// client-voiced body — see reviewerNotesBlock — so a reader can tell whose voice they are in.
|
|
1789
|
+
assessment: (() => { const t = String(m.assessment ?? '').trim(); return t || null; })(),
|
|
1790
|
+
counterFactors: m.counterFactors ?? [],
|
|
1791
|
+
mitigation: (() => { const t = String(m.mitigation ?? '').trim(); return t || null; })(),
|
|
1792
|
+
// `null`, not `false`, when the rater said nothing: a crowded field is a mitigant the reasoning
|
|
1793
|
+
// turns on, and an unstated one must not read as a stated "no".
|
|
1794
|
+
crowdedField: typeof m.crowdedField === 'boolean' ? m.crowdedField : null,
|
|
1795
|
+
reviewerNotes: m.purpleNotes ?? [],
|
|
1796
|
+
// The proof-of-search rows — the same defensibility record list_searches answers from.
|
|
1797
|
+
negatives: (m.negatives ?? []).map((n) => ({
|
|
1798
|
+
term: n?.term ?? null, source: n?.source ?? null, note: n?.note ?? null,
|
|
1799
|
+
})),
|
|
1800
|
+
// The rater's read of a filing it weighed, keyed by the record id the card prints, so a consumer
|
|
1801
|
+
// can join a read to its filing without matching on prose.
|
|
1802
|
+
registerReads: (m.registerReads ?? []).map((x) => ({
|
|
1803
|
+
recordId: x?.recordId ?? null,
|
|
1804
|
+
read: x?.read ?? null,
|
|
1805
|
+
band: String(x?.band ?? '').trim() || null,
|
|
1806
|
+
})),
|
|
1327
1807
|
// — the typed finding, ranked, with the reference the report prints. The old key was
|
|
1328
1808
|
// `evidence[]` and it was `(m.findings ?? []).filter((f) => f?.url)`: a typed finding has no
|
|
1329
1809
|
// `url`, so this file — the one the assistant drafts client mail from — silently carried zero
|
|
@@ -1345,14 +1825,36 @@ export function knockoutReportData(findings, framework, { runId, codename, overa
|
|
|
1345
1825
|
// A promoted filing the brief omitted would be the report and the brief disagreeing about
|
|
1346
1826
|
// what the run found.
|
|
1347
1827
|
//
|
|
1348
|
-
// `
|
|
1349
|
-
//
|
|
1350
|
-
//
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1828
|
+
// `shape: 'register'` is the load-bearing field: a consumer can tell a weighed conflict from a
|
|
1829
|
+
// pointed-at filing without parsing prose.
|
|
1830
|
+
//
|
|
1831
|
+
// `band` AND `basis` NOW CARRY THE RATER'S READ WHEN IT SENT ONE (tracker issue 274). Before
|
|
1832
|
+
// this, both were constants — `band: null` and the not-weighed sentence — on every filing of
|
|
1833
|
+
// every run, including runs where the seat had written a full read of that exact filing and the
|
|
1834
|
+
// HTML card was already printing it. The page and this file disagreed, and this file is the one
|
|
1835
|
+
// the MCP brief answers from, so the surface a reader asks "what did you make of that
|
|
1836
|
+
// registration?" was the surface that had dropped the answer.
|
|
1837
|
+
//
|
|
1838
|
+
// The unmatched case is unchanged and must stay that way: no row for this recordId ⇒ `band:
|
|
1839
|
+
// null` and the not-weighed line, which describes the card and claims nothing.
|
|
1840
|
+
...registerCardViews(m, framework, registerRecords).cards.map((v) => {
|
|
1841
|
+
const row = (Array.isArray(m?.registerReads) ? m.registerReads : [])
|
|
1842
|
+
.find((x) => String(x?.recordId ?? '').trim() && String(x?.recordId ?? '').trim() === String(v.record?.recordId ?? '').trim());
|
|
1843
|
+
const read = String(row?.read ?? '').trim() || null;
|
|
1844
|
+
const band = String(row?.band ?? '').trim() || null;
|
|
1845
|
+
// The driver's own record of where this filing's proprietor was looked up (tracker issue
|
|
1846
|
+
// 276), joined by recordId. `null` where the run owed no check — the same three states the
|
|
1847
|
+
// card has, so a consumer can tell "searched and found nothing" from "never searched".
|
|
1848
|
+
const oc = ownerCheckFor(ownerChecks, v.record?.recordId);
|
|
1849
|
+
return {
|
|
1850
|
+
ref: v.ref, ordinal: v.ordinal, name: v.record.mark, owner: v.record.owner, band,
|
|
1851
|
+
type: 'Register filing',
|
|
1852
|
+
net: read ? v.statement : `${v.statement} It was ${NOT_WEIGHED}.`,
|
|
1853
|
+
basis: read ?? NOT_WEIGHED,
|
|
1854
|
+
useCheckSource: oc?.source ?? null,
|
|
1855
|
+
evidence: v.evidence, shape: 'register',
|
|
1856
|
+
};
|
|
1857
|
+
}),
|
|
1356
1858
|
],
|
|
1357
1859
|
registerCounts: counted?.counts
|
|
1358
1860
|
? {
|