harnery 0.38.0 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +32 -8
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +97 -6
- package/dist/commands/backup.d.ts +16 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +239 -33
- package/dist/commands/browse.d.ts +8 -0
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +466 -231
- package/dist/commands/diagnostics.d.ts.map +1 -1
- package/dist/commands/diagnostics.js +6 -3
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +20 -4
- package/dist/commands/qa-run.d.ts.map +1 -1
- package/dist/commands/qa-run.js +26 -3
- package/dist/commands/qa-status.d.ts.map +1 -1
- package/dist/commands/qa-status.js +7 -2
- package/dist/commands/resources.d.ts.map +1 -1
- package/dist/commands/resources.js +23 -3
- package/dist/commands/review-pack.d.ts.map +1 -1
- package/dist/commands/review-pack.js +98 -23
- package/dist/commands/tunnel.d.ts.map +1 -1
- package/dist/commands/tunnel.js +2 -2
- package/dist/core/adapters/profiles.d.ts +1 -1
- package/dist/core/agents/canonical-emit.d.ts +3 -2
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +2 -0
- package/dist/core/agents/cli.js +13 -6
- package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
- package/dist/core/agents/live-authority-v3.js +5 -3
- package/dist/core/agents/live-lifecycle-v3.d.ts +2 -2
- package/dist/core/agents/live-lifecycle-v3.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.d.ts +7 -5
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +63 -8
- package/dist/core/agents/session-finalizer-v3.d.ts +2 -2
- package/dist/core/agents/session-finalizer-v3.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.d.ts +3 -3
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +2 -1
- package/dist/core/agents/state/names.d.ts +35 -2
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +80 -5
- package/dist/core/agents/state/stale-sweep.d.ts +2 -1
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +23 -6
- package/dist/core/agents/turn-elapsed.d.ts +51 -0
- package/dist/core/agents/turn-elapsed.d.ts.map +1 -0
- package/dist/core/agents/turn-elapsed.js +91 -0
- package/dist/core/artifacts/activity.d.ts +14 -0
- package/dist/core/artifacts/activity.d.ts.map +1 -0
- package/dist/core/artifacts/activity.js +52 -0
- package/dist/core/artifacts/delivery-card.d.ts +39 -0
- package/dist/core/artifacts/delivery-card.d.ts.map +1 -0
- package/dist/core/artifacts/delivery-card.js +282 -0
- package/dist/core/artifacts/index.d.ts +42 -7
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +288 -76
- package/dist/core/artifacts/mutation-lock.d.ts +2 -0
- package/dist/core/artifacts/mutation-lock.d.ts.map +1 -0
- package/dist/core/artifacts/mutation-lock.js +91 -0
- package/dist/core/backup/host-snapshot.d.ts +18 -0
- package/dist/core/backup/host-snapshot.d.ts.map +1 -0
- package/dist/core/backup/host-snapshot.js +64 -0
- package/dist/core/config.d.ts +20 -5
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +44 -10
- package/dist/core/diagnostics/advice.d.ts +38 -3
- package/dist/core/diagnostics/advice.d.ts.map +1 -1
- package/dist/core/diagnostics/advice.js +103 -99
- package/dist/core/diagnostics/bundle.d.ts.map +1 -1
- package/dist/core/diagnostics/bundle.js +111 -47
- package/dist/core/diagnostics/comparison.d.ts.map +1 -1
- package/dist/core/diagnostics/comparison.js +3 -2
- package/dist/core/diagnostics/contract.d.ts +15 -31
- package/dist/core/diagnostics/contract.d.ts.map +1 -1
- package/dist/core/diagnostics/contract.js +2 -5
- package/dist/core/diagnostics/index.d.ts +2 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -1
- package/dist/core/diagnostics/index.js +2 -0
- package/dist/core/diagnostics/pressure-contract.d.ts +260 -0
- package/dist/core/diagnostics/pressure-contract.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure-contract.js +70 -0
- package/dist/core/diagnostics/pressure.d.ts +25 -0
- package/dist/core/diagnostics/pressure.d.ts.map +1 -0
- package/dist/core/diagnostics/pressure.js +1138 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -1
- package/dist/core/diagnostics/replay.js +90 -10
- package/dist/core/events/v3/adapter-id.d.ts +6 -0
- package/dist/core/events/v3/adapter-id.d.ts.map +1 -0
- package/dist/core/events/v3/adapter-id.js +7 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -1
- package/dist/core/events/v3/archive-retention.js +3 -2
- package/dist/core/events/v3/bootstrap.d.ts +41 -4
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +120 -17
- package/dist/core/events/v3/capabilities.d.ts +16 -9
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +37 -2
- package/dist/core/events/v3/capability-drift.d.ts +2 -2
- package/dist/core/events/v3/capability-drift.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.d.ts +48 -5
- package/dist/core/events/v3/control-witness.d.ts.map +1 -1
- package/dist/core/events/v3/control-witness.js +91 -36
- package/dist/core/events/v3/control.d.ts.map +1 -1
- package/dist/core/events/v3/control.js +22 -2
- package/dist/core/events/v3/index.d.ts +2 -1
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +2 -1
- package/dist/core/events/v3/live-feed.d.ts +7 -1
- package/dist/core/events/v3/live-feed.d.ts.map +1 -1
- package/dist/core/events/v3/live-feed.js +21 -3
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +10 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/command-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/command-recorder.js +2 -1
- package/dist/core/events/v3/producers/coordination-recorder.d.ts +2 -2
- package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/coordination-recorder.js +2 -1
- package/dist/core/events/v3/producers/hook-base.d.ts +2 -2
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +15 -5
- package/dist/core/events/v3/producers/hook.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook.js +17 -4
- package/dist/core/events/v3/producers/intake.d.ts +4 -4
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +3 -2
- package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -1
- package/dist/core/events/v3/producers/producer-state-observer.js +2 -1
- package/dist/core/events/v3/producers/recorder.d.ts +16 -5
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +31 -9
- package/dist/core/events/v3/reader.d.ts.map +1 -1
- package/dist/core/events/v3/reader.js +10 -13
- package/dist/core/events/v3/runtime-build.d.ts.map +1 -1
- package/dist/core/events/v3/runtime-build.js +3 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +2 -2
- package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/turn-telemetry.d.ts +2 -2
- package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.d.ts +16 -14
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +36 -38
- package/dist/core/hooks/backup-schedule.d.ts +34 -0
- package/dist/core/hooks/backup-schedule.d.ts.map +1 -0
- package/dist/core/hooks/backup-schedule.js +114 -0
- package/dist/core/hooks/cli.js +61 -18
- package/dist/core/hooks/codex-wsl-bridge.d.ts +2 -0
- package/dist/core/hooks/codex-wsl-bridge.d.ts.map +1 -1
- package/dist/core/hooks/codex-wsl-bridge.js +18 -4
- package/dist/core/hooks/index.d.ts +1 -0
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/hooks/prompt-context/contract.d.ts +61 -0
- package/dist/core/hooks/prompt-context/contract.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/contract.js +102 -0
- package/dist/core/hooks/prompt-context/index.d.ts +5 -0
- package/dist/core/hooks/prompt-context/index.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/index.js +2 -0
- package/dist/core/hooks/prompt-context/runner.d.ts +24 -0
- package/dist/core/hooks/prompt-context/runner.d.ts.map +1 -0
- package/dist/core/hooks/prompt-context/runner.js +249 -0
- package/dist/core/qa-artifacts.d.ts +3 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -1
- package/dist/core/qa-artifacts.js +25 -3
- package/dist/core/resources/contract.d.ts +69 -3
- package/dist/core/resources/contract.d.ts.map +1 -1
- package/dist/core/resources/contract.js +1 -1
- package/dist/core/resources/index.d.ts +1 -0
- package/dist/core/resources/index.d.ts.map +1 -1
- package/dist/core/resources/index.js +1 -0
- package/dist/core/resources/native.d.ts +36 -0
- package/dist/core/resources/native.d.ts.map +1 -0
- package/dist/core/resources/native.js +418 -0
- package/dist/core/resources/sampler.d.ts +2 -0
- package/dist/core/resources/sampler.d.ts.map +1 -1
- package/dist/core/resources/sampler.js +31 -1
- package/dist/core/resources/status.d.ts +61 -0
- package/dist/core/resources/status.d.ts.map +1 -0
- package/dist/core/resources/status.js +536 -0
- package/dist/core/resources/system.d.ts +27 -0
- package/dist/core/resources/system.d.ts.map +1 -0
- package/dist/core/resources/system.js +439 -0
- package/dist/core/semantic/contract.d.ts +13 -13
- package/dist/core/semantic/service.d.ts +2 -0
- package/dist/core/semantic/service.d.ts.map +1 -1
- package/dist/core/semantic/service.js +27 -4
- package/dist/core/storage/builtins.js +41 -0
- package/dist/core/supervisor/contract.d.ts +41 -3
- package/dist/core/supervisor/contract.d.ts.map +1 -1
- package/dist/core/supervisor/contract.js +3 -2
- package/dist/core/supervisor/findings.d.ts +3 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -1
- package/dist/core/supervisor/findings.js +88 -0
- package/dist/core/supervisor/history.d.ts.map +1 -1
- package/dist/core/supervisor/history.js +14 -0
- package/dist/core/supervisor/ledger-state.d.ts +55 -0
- package/dist/core/supervisor/ledger-state.d.ts.map +1 -0
- package/dist/core/supervisor/ledger-state.js +0 -0
- package/dist/core/supervisor/service.d.ts.map +1 -1
- package/dist/core/supervisor/service.js +120 -7
- package/dist/core/supervisor/storage.d.ts +3 -1
- package/dist/core/supervisor/storage.d.ts.map +1 -1
- package/dist/core/supervisor/storage.js +4 -0
- package/dist/core/workflow/admission.d.ts +3 -0
- package/dist/core/workflow/admission.d.ts.map +1 -1
- package/dist/core/workflow/admission.js +28 -16
- package/dist/core/workflow/engine.js +2 -2
- package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
- package/dist/core/workflow/live-session-v3.js +6 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +4 -3
- package/dist/lib/browser/capture-fidelity.d.ts +7 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -1
- package/dist/lib/browser/capture-fidelity.js +17 -0
- package/dist/lib/browser/client.d.ts +9 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +85 -37
- package/dist/lib/browser/index.d.ts +3 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +2 -1
- package/dist/lib/browser/page-review-budget.d.ts +13 -0
- package/dist/lib/browser/page-review-budget.d.ts.map +1 -0
- package/dist/lib/browser/page-review-budget.js +251 -0
- package/dist/lib/browser/page-review-contracts.d.ts +127 -0
- package/dist/lib/browser/page-review-contracts.d.ts.map +1 -0
- package/dist/lib/browser/page-review-contracts.js +5 -0
- package/dist/lib/browser/page-review-evidence.d.ts +48 -0
- package/dist/lib/browser/page-review-evidence.d.ts.map +1 -0
- package/dist/lib/browser/page-review-evidence.js +340 -0
- package/dist/lib/browser/page-review-judge.d.ts +1 -1
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -1
- package/dist/lib/browser/page-review-judge.js +46 -38
- package/dist/lib/browser/page-review-pack.d.ts +44 -22
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -1
- package/dist/lib/browser/page-review-pack.js +116 -36
- package/dist/lib/browser/page-review-source.d.ts +12 -0
- package/dist/lib/browser/page-review-source.d.ts.map +1 -0
- package/dist/lib/browser/page-review-source.js +22 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +35 -9
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -1
- package/dist/lib/browser/qa-run-contracts.js +48 -14
- package/dist/lib/browser/qa-run.d.ts.map +1 -1
- package/dist/lib/browser/qa-run.js +215 -68
- package/dist/lib/browser/qa-snapshot.d.ts +6 -0
- package/dist/lib/browser/qa-snapshot.d.ts.map +1 -1
- package/dist/lib/browser/qa-snapshot.js +259 -48
- package/dist/lib/browser/review-capture-transaction.d.ts +13 -0
- package/dist/lib/browser/review-capture-transaction.d.ts.map +1 -0
- package/dist/lib/browser/review-capture-transaction.js +79 -0
- package/dist/lib/browser/standalone-html.d.ts.map +1 -1
- package/dist/lib/browser/standalone-html.js +4 -2
- package/dist/lib/browser/thumbnail-association.d.ts +34 -0
- package/dist/lib/browser/thumbnail-association.d.ts.map +1 -0
- package/dist/lib/browser/thumbnail-association.js +158 -0
- package/dist/lib/browser/tiling.d.ts +30 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +38 -0
- package/dist/lib/docs-metadata-managed.d.ts.map +1 -1
- package/dist/lib/docs-metadata-managed.js +4 -1
- package/dist/lib/identities/assume.d.ts.map +1 -1
- package/dist/lib/identities/assume.js +7 -1
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +1 -0
- package/dist/lib/local-file-url.d.ts +12 -0
- package/dist/lib/local-file-url.d.ts.map +1 -1
- package/dist/lib/local-file-url.js +16 -2
- package/dist/lib/tunnel/state.d.ts +19 -4
- package/dist/lib/tunnel/state.d.ts.map +1 -1
- package/dist/lib/tunnel/state.js +53 -13
- package/package.json +7 -4
- package/schemas/config.schema.json +69 -2
- package/src/commands/agents.ts +42 -9
- package/src/commands/artifacts.ts +130 -6
- package/src/commands/backup.ts +287 -34
- package/src/commands/browse.ts +564 -267
- package/src/commands/diagnostics.ts +6 -3
- package/src/commands/ledger-v3.ts +20 -3
- package/src/commands/qa-run.ts +37 -3
- package/src/commands/qa-status.ts +11 -2
- package/src/commands/resources.ts +23 -3
- package/src/commands/review-pack.ts +165 -62
- package/src/commands/tunnel.ts +2 -1
- package/src/core/agents/canonical-emit.ts +4 -2
- package/src/core/agents/cli.ts +14 -6
- package/src/core/agents/live-authority-v3.ts +7 -3
- package/src/core/agents/live-lifecycle-v3.ts +2 -2
- package/src/core/agents/render/prompt-context.ts +68 -14
- package/src/core/agents/session-finalizer-v3.ts +2 -2
- package/src/core/agents/state/live-coordination-view.ts +4 -4
- package/src/core/agents/state/names.ts +92 -7
- package/src/core/agents/state/stale-sweep.ts +22 -8
- package/src/core/agents/turn-elapsed.ts +135 -0
- package/src/core/artifacts/activity.ts +71 -0
- package/src/core/artifacts/delivery-card.ts +375 -0
- package/src/core/artifacts/index.ts +385 -91
- package/src/core/artifacts/mutation-lock.ts +106 -0
- package/src/core/backup/host-snapshot.ts +76 -0
- package/src/core/config.ts +66 -13
- package/src/core/diagnostics/advice.ts +148 -120
- package/src/core/diagnostics/bundle.ts +138 -52
- package/src/core/diagnostics/comparison.ts +6 -2
- package/src/core/diagnostics/contract.ts +39 -42
- package/src/core/diagnostics/index.ts +2 -0
- package/src/core/diagnostics/pressure-contract.ts +294 -0
- package/src/core/diagnostics/pressure.ts +1361 -0
- package/src/core/diagnostics/replay.ts +116 -11
- package/src/core/events/v3/adapter-id.ts +12 -0
- package/src/core/events/v3/archive-retention.ts +3 -6
- package/src/core/events/v3/bootstrap.ts +163 -16
- package/src/core/events/v3/capabilities.ts +75 -25
- package/src/core/events/v3/capability-drift.ts +2 -2
- package/src/core/events/v3/control-witness.ts +172 -41
- package/src/core/events/v3/control.ts +34 -2
- package/src/core/events/v3/index.ts +3 -0
- package/src/core/events/v3/live-feed.ts +23 -5
- package/src/core/events/v3/live-routing.ts +14 -2
- package/src/core/events/v3/producers/command-recorder.ts +4 -4
- package/src/core/events/v3/producers/coordination-recorder.ts +4 -4
- package/src/core/events/v3/producers/hook-base.ts +21 -16
- package/src/core/events/v3/producers/hook.ts +21 -4
- package/src/core/events/v3/producers/intake.ts +6 -6
- package/src/core/events/v3/producers/producer-state-observer.ts +2 -1
- package/src/core/events/v3/producers/recorder.ts +50 -21
- package/src/core/events/v3/reader.ts +14 -13
- package/src/core/events/v3/runtime-build.ts +3 -2
- package/src/core/events/v3/runtime-telemetry-capabilities.ts +3 -3
- package/src/core/events/v3/turn-telemetry.ts +4 -4
- package/src/core/hooks/adapter/output.ts +50 -36
- package/src/core/hooks/backup-schedule.ts +147 -0
- package/src/core/hooks/cli.ts +65 -14
- package/src/core/hooks/codex-wsl-bridge.ts +21 -5
- package/src/core/hooks/index.ts +1 -0
- package/src/core/hooks/prompt-context/contract.ts +177 -0
- package/src/core/hooks/prompt-context/index.ts +22 -0
- package/src/core/hooks/prompt-context/runner.ts +303 -0
- package/src/core/qa-artifacts.ts +29 -3
- package/src/core/resources/contract.ts +76 -3
- package/src/core/resources/index.ts +1 -0
- package/src/core/resources/native.ts +481 -0
- package/src/core/resources/sampler.ts +46 -1
- package/src/core/resources/status.ts +717 -0
- package/src/core/resources/system.ts +530 -0
- package/src/core/semantic/service.ts +37 -3
- package/src/core/storage/builtins.ts +41 -0
- package/src/core/supervisor/contract.ts +45 -3
- package/src/core/supervisor/findings.ts +159 -0
- package/src/core/supervisor/history.ts +15 -0
- package/src/core/supervisor/ledger-state.ts +0 -0
- package/src/core/supervisor/service.ts +133 -5
- package/src/core/supervisor/storage.ts +7 -0
- package/src/core/workflow/admission.ts +33 -17
- package/src/core/workflow/engine.ts +2 -2
- package/src/core/workflow/live-session-v3.ts +6 -8
- package/src/core/workflow/proof.ts +4 -3
- package/src/lib/browser/capture-fidelity.ts +23 -0
- package/src/lib/browser/client.ts +96 -44
- package/src/lib/browser/index.ts +15 -1
- package/src/lib/browser/page-review-budget.ts +309 -0
- package/src/lib/browser/page-review-contracts.ts +129 -0
- package/src/lib/browser/page-review-evidence.ts +465 -0
- package/src/lib/browser/page-review-judge.ts +56 -40
- package/src/lib/browser/page-review-pack.ts +181 -43
- package/src/lib/browser/page-review-source.ts +30 -0
- package/src/lib/browser/qa-run-contracts.ts +62 -18
- package/src/lib/browser/qa-run.ts +259 -71
- package/src/lib/browser/qa-snapshot.ts +289 -48
- package/src/lib/browser/review-capture-transaction.ts +106 -0
- package/src/lib/browser/standalone-html.ts +4 -2
- package/src/lib/browser/thumbnail-association.ts +190 -0
- package/src/lib/browser/tiling.ts +63 -0
- package/src/lib/docs-metadata-managed.ts +4 -1
- package/src/lib/identities/assume.ts +12 -4
- package/src/lib/instructions/templates.ts +1 -0
- package/src/lib/local-file-url.ts +17 -2
- package/src/lib/tunnel/state.ts +70 -13
|
@@ -366,6 +366,29 @@ export class Browser {
|
|
|
366
366
|
async fullPageScreenshotBuffer() {
|
|
367
367
|
return await this.currentPage.screenshot({ type: "png", fullPage: true });
|
|
368
368
|
}
|
|
369
|
+
/** Wait for font-driven DOM/layout initialization, with a bounded convergence check. */
|
|
370
|
+
async waitForReviewReady(timeoutMs = 15_000) {
|
|
371
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000)
|
|
372
|
+
throw new RangeError("waitForReviewReady timeoutMs must be an integer from 1 to 60000");
|
|
373
|
+
const settled = await this.currentPage.evaluate(async (timeoutMs) => {
|
|
374
|
+
await document.fonts.ready;
|
|
375
|
+
const deadline = performance.now() + timeoutMs;
|
|
376
|
+
let previous = "";
|
|
377
|
+
let consecutive = 0;
|
|
378
|
+
while (performance.now() < deadline) {
|
|
379
|
+
await new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
380
|
+
const geometry = `${document.documentElement.scrollWidth},${document.documentElement.scrollHeight},${document.body?.scrollWidth},${document.body?.scrollHeight}`;
|
|
381
|
+
const current = geometry + document.documentElement.outerHTML;
|
|
382
|
+
consecutive = current === previous ? consecutive + 1 : 0;
|
|
383
|
+
if (consecutive >= 8)
|
|
384
|
+
return true;
|
|
385
|
+
previous = current;
|
|
386
|
+
}
|
|
387
|
+
return false;
|
|
388
|
+
}, timeoutMs);
|
|
389
|
+
if (!settled)
|
|
390
|
+
throw new Error("Page review source or layout did not settle; rerun when page initialization completes.");
|
|
391
|
+
}
|
|
369
392
|
/** Base64 PNG of a document-space clip rect. Used to capture one critique tile. */
|
|
370
393
|
async screenshotClipBase64(rect) {
|
|
371
394
|
const buf = await this.currentPage.screenshot({ type: "png", clip: rect });
|
|
@@ -400,10 +423,18 @@ export class Browser {
|
|
|
400
423
|
* full-page screenshot would show it, without the full-page raster.
|
|
401
424
|
*/
|
|
402
425
|
async captureRegionByScroll(rect) {
|
|
426
|
+
const [image] = await this.captureRegionsByScroll([rect]);
|
|
427
|
+
return image;
|
|
428
|
+
}
|
|
429
|
+
/** Capture a document-ordered group with one pinned-element inventory and restore. */
|
|
430
|
+
async captureRegionsByScroll(rects) {
|
|
431
|
+
if (!rects.length)
|
|
432
|
+
return [];
|
|
403
433
|
const page = this.currentPage;
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
434
|
+
for (const rect of rects)
|
|
435
|
+
if (!(rect.width > 0) || !(rect.height > 0)) {
|
|
436
|
+
throw new Error(`captureRegionByScroll: rect must have a positive size (got ${rect.width}×${rect.height})`);
|
|
437
|
+
}
|
|
407
438
|
const settle = (top) => page.evaluate(async (target) => {
|
|
408
439
|
window.scrollTo({ left: window.scrollX, top: target, behavior: "instant" });
|
|
409
440
|
const frame = () => new Promise((r) => requestAnimationFrame(() => r()));
|
|
@@ -423,7 +454,7 @@ export class Browser {
|
|
|
423
454
|
};
|
|
424
455
|
}, top);
|
|
425
456
|
const original = await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY }));
|
|
426
|
-
const
|
|
457
|
+
const captures = [];
|
|
427
458
|
// Viewport-pinned candidates, measured at scroll 0 so each later capture
|
|
428
459
|
// can tell "still where the full page shows it" from "riding along".
|
|
429
460
|
await settle(0);
|
|
@@ -434,10 +465,19 @@ export class Browser {
|
|
|
434
465
|
// switched off inline so the capture never lands mid-fade.
|
|
435
466
|
const pinned = await page.evaluateHandle(() => {
|
|
436
467
|
const out = [];
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
468
|
+
// Fixed controls can live inside a static shadow host. Walk open roots
|
|
469
|
+
// without hiding their ordinary content or exceeding the total node cap.
|
|
470
|
+
const walkers = [document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT)];
|
|
471
|
+
let visited = 0;
|
|
472
|
+
while (walkers.length && visited < 20_000) {
|
|
473
|
+
const el = walkers[walkers.length - 1].nextNode();
|
|
474
|
+
if (!el) {
|
|
475
|
+
walkers.pop();
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
478
|
+
visited++;
|
|
479
|
+
if (el.shadowRoot)
|
|
480
|
+
walkers.push(document.createTreeWalker(el.shadowRoot, NodeFilter.SHOW_ELEMENT));
|
|
441
481
|
const position = getComputedStyle(el).position;
|
|
442
482
|
if (position !== "fixed" && position !== "sticky")
|
|
443
483
|
continue;
|
|
@@ -455,7 +495,11 @@ export class Browser {
|
|
|
455
495
|
const syncPinned = (mode) => page.evaluate(async ([entries, action]) => {
|
|
456
496
|
for (const entry of entries) {
|
|
457
497
|
const restore = () => {
|
|
498
|
+
// Restore opacity while transitions are still disabled. Restoring both
|
|
499
|
+
// declarations in one style flush starts a new fade from zero.
|
|
500
|
+
entry.el.style.setProperty("transition", "none", "important");
|
|
458
501
|
entry.el.style.setProperty("opacity", entry.priorOpacity, entry.priorOpacityPriority);
|
|
502
|
+
void getComputedStyle(entry.el).opacity;
|
|
459
503
|
entry.el.style.setProperty("transition", entry.priorTransition, entry.priorTransitionPriority);
|
|
460
504
|
};
|
|
461
505
|
if (action === "restore") {
|
|
@@ -475,35 +519,39 @@ export class Browser {
|
|
|
475
519
|
await new Promise((r) => requestAnimationFrame(() => r()));
|
|
476
520
|
}, [pinned, mode]);
|
|
477
521
|
try {
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
view = await settle(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
522
|
+
for (const rect of rects) {
|
|
523
|
+
const pieces = [];
|
|
524
|
+
const bottom = rect.y + rect.height;
|
|
525
|
+
let cursor = rect.y;
|
|
526
|
+
let first = true;
|
|
527
|
+
while (cursor < bottom) {
|
|
528
|
+
const remaining = bottom - cursor;
|
|
529
|
+
// Top-align the piece; a final partial piece is then re-anchored to
|
|
530
|
+
// the viewport bottom once the viewport height is known.
|
|
531
|
+
let view = await settle(cursor);
|
|
532
|
+
if (!first && remaining < view.innerHeight) {
|
|
533
|
+
view = await settle(Math.max(0, bottom - view.innerHeight));
|
|
534
|
+
}
|
|
535
|
+
await syncPinned("hide-moved");
|
|
536
|
+
const offset = cursor - view.scrollY;
|
|
537
|
+
if (offset < 0 || offset >= view.innerHeight) {
|
|
538
|
+
throw new Error(`captureRegionByScroll: document y ${cursor} is not reachable in the viewport ` +
|
|
539
|
+
`(scrollY ${view.scrollY}, innerHeight ${view.innerHeight})`);
|
|
540
|
+
}
|
|
541
|
+
const pieceHeight = Math.min(remaining, view.innerHeight - offset);
|
|
542
|
+
const clipX = Math.max(0, rect.x - view.scrollX);
|
|
543
|
+
const clipWidth = Math.min(rect.width, view.innerWidth - clipX);
|
|
544
|
+
if (!(clipWidth > 0)) {
|
|
545
|
+
throw new Error(`captureRegionByScroll: document x ${rect.x} is outside the viewport (innerWidth ${view.innerWidth})`);
|
|
546
|
+
}
|
|
547
|
+
pieces.push(await page.screenshot({
|
|
548
|
+
type: "png",
|
|
549
|
+
clip: { x: clipX, y: offset, width: clipWidth, height: pieceHeight },
|
|
550
|
+
}));
|
|
551
|
+
cursor += pieceHeight;
|
|
552
|
+
first = false;
|
|
500
553
|
}
|
|
501
|
-
|
|
502
|
-
type: "png",
|
|
503
|
-
clip: { x: clipX, y: offset, width: clipWidth, height: pieceHeight },
|
|
504
|
-
}));
|
|
505
|
-
cursor += pieceHeight;
|
|
506
|
-
first = false;
|
|
554
|
+
captures.push(stitchPngRows(pieces));
|
|
507
555
|
}
|
|
508
556
|
}
|
|
509
557
|
finally {
|
|
@@ -515,7 +563,7 @@ export class Browser {
|
|
|
515
563
|
await page.evaluate(({ x, y }) => window.scrollTo({ left: x, top: y, behavior: "instant" }), original);
|
|
516
564
|
}
|
|
517
565
|
}
|
|
518
|
-
return
|
|
566
|
+
return captures;
|
|
519
567
|
}
|
|
520
568
|
/** Document-space rects + labels for each element matching `selector` (semantic tiling). */
|
|
521
569
|
async elementTiles(selector) {
|
|
@@ -8,8 +8,10 @@ export { buildLayoutLintCheck } from "./geometry.js";
|
|
|
8
8
|
export { isWSL, wslHeadedLaunchArgs } from "./launch-args.js";
|
|
9
9
|
export type { OverflowElement, OverflowResult, WidthResult, } from "./layout.js";
|
|
10
10
|
export { serializeNetscapeCookies, writeNetscapeCookieFile, } from "./netscape-cookies.js";
|
|
11
|
+
export type { PageReviewBudgetCoverage, PageReviewCandidate, PageReviewCapturePlan, PageReviewContextAllocation, PageReviewDecisionSlot, PageReviewDurableDecision, PageReviewEvidenceContext, PageReviewNativeEvidence, PageReviewNativeTile, PageReviewRect, PageReviewTileBudgetAllocation, } from "./page-review-contracts.js";
|
|
12
|
+
export { nativePixelDigest } from "./page-review-evidence.js";
|
|
11
13
|
export { type JudgedContext, type JudgePageReviewPackOptions, type JudgePageReviewPackResult, judgePageReviewPack, toCritiqueRecords, } from "./page-review-judge.js";
|
|
12
|
-
export { buildInspectionPlan, type FinalizePageReviewPackInput, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, type PageReviewContextCapture, type PageReviewContextRecord, type PageReviewCritiqueRecord, type PageReviewGateRecord, type PageReviewInspectionPlan, type PageReviewPackManifest, type PageReviewTileRecord, packPaths, readPackContext, readPackDom,
|
|
14
|
+
export { buildInspectionPlan, type FinalizePageReviewPackInput, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, type PageReviewContextCapture, type PageReviewContextRecord, type PageReviewCritiqueRecord, type PageReviewGateRecord, type PageReviewInspectionPlan, type PageReviewPackManifest, type PageReviewTileRecord, packPaths, readPackContext, readPackDom, readPackManifest, readPackOverview, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
|
|
13
15
|
export { type BrowserProxy, type BrowserProxyGate, browserProxyFromEnv, browserProxyGateFromEnv, extractObservedIp, WEBRTC_PROXY_ONLY_ARG, } from "./proxy.js";
|
|
14
16
|
export { buildQaManifest, type ChangeClass, type ClassifyOptions, classifySignatures, fnv1a32, type ManifestOptions, type QaClassification, type QaContext, type QaManifest, type QaNodeSignature, type QaScope, type QaSignature, type QaStylesheetSignature, } from "./qa-plan.js";
|
|
15
17
|
export { defaultQaRunExec, QA_RUN_HEADLESS_ONLY_ENV, QA_RUN_RESULT_FILENAME, type QaRunExec, type QaRunExecOptions, type QaRunExecResult, type QaRunMatrixOptions, runQaMatrix, } from "./qa-run.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,gBAAgB,EAChB,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EACP,KAAK,cAAc,EACnB,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,4BAA4B,EACjC,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,UAAU,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,OAAO,EACP,SAAS,EACT,UAAU,EACV,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,UAAU,EACV,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EACV,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,mBAAmB,EACnB,KAAK,2BAA2B,EAChC,sBAAsB,EACtB,sBAAsB,EACtB,gBAAgB,EAChB,2BAA2B,EAC3B,wBAAwB,EACxB,uBAAuB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,SAAS,EACT,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,kBAAkB,EAClB,OAAO,EACP,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,qBAAqB,GAC3B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,sBAAsB,EACtB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,yBAAyB,EACzB,4BAA4B,EAC5B,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,KAAK,sBAAsB,EAC3B,aAAa,EACb,KAAK,kBAAkB,EACvB,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,OAAO,EACP,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,8BAA8B,EAC9B,+BAA+B,EAC/B,yCAAyC,EACzC,gCAAgC,EAChC,KAAK,wBAAwB,EAC7B,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,OAAO,EACP,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,gBAAgB,EAChB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,9 @@ export { captureDevOverlay, } from "./dev-overlay.js";
|
|
|
5
5
|
export { buildLayoutLintCheck } from "./geometry.js";
|
|
6
6
|
export { isWSL, wslHeadedLaunchArgs } from "./launch-args.js";
|
|
7
7
|
export { serializeNetscapeCookies, writeNetscapeCookieFile, } from "./netscape-cookies.js";
|
|
8
|
+
export { nativePixelDigest } from "./page-review-evidence.js";
|
|
8
9
|
export { judgePageReviewPack, toCritiqueRecords, } from "./page-review-judge.js";
|
|
9
|
-
export { buildInspectionPlan, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, packPaths, readPackContext, readPackDom,
|
|
10
|
+
export { buildInspectionPlan, finalizePageReviewPack, findingsSchemaDocument, listPackContexts, PAGE_REVIEW_FINDINGS_SCHEMA, PAGE_REVIEW_PACK_DIRNAME, PAGE_REVIEW_PACK_SCHEMA, packPaths, readPackContext, readPackDom, readPackManifest, readPackOverview, readPackSignature, readPackTiles, renderReviewMarkdown, writePackContext, } from "./page-review-pack.js";
|
|
10
11
|
export { browserProxyFromEnv, browserProxyGateFromEnv, extractObservedIp, WEBRTC_PROXY_ONLY_ARG, } from "./proxy.js";
|
|
11
12
|
export { buildQaManifest, classifySignatures, fnv1a32, } from "./qa-plan.js";
|
|
12
13
|
export { defaultQaRunExec, QA_RUN_HEADLESS_ONLY_ENV, QA_RUN_RESULT_FILENAME, runQaMatrix, } from "./qa-run.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type PageReviewBudgetCoverage, type PageReviewCapturePlan, type PageReviewContextAllocation, type PageReviewRect, type PageReviewTileBudgetAllocation } from "./page-review-contracts.js";
|
|
2
|
+
export declare function validatePageReviewCapturePlan(value: unknown): PageReviewCapturePlan;
|
|
3
|
+
export declare function intervalUnion(rects: readonly PageReviewRect[]): Array<{
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function allocationCoverage(plan: PageReviewCapturePlan, selectedIds: readonly string[]): PageReviewBudgetCoverage;
|
|
8
|
+
/** Reserve edges, prioritize gate hits, then distribute by remaining height. */
|
|
9
|
+
export declare function allocateTileBudget(plans: PageReviewCapturePlan[], budget?: number, ceilings?: Record<string, number>): PageReviewTileBudgetAllocation;
|
|
10
|
+
/** Gate-hit annotations are planning results; geometry and page state are authoritative at capture. */
|
|
11
|
+
export declare function capturePlanDigest(plan: PageReviewCapturePlan): string;
|
|
12
|
+
export declare function validatePageReviewAllocation(value: unknown, current: PageReviewCapturePlan): PageReviewContextAllocation;
|
|
13
|
+
//# sourceMappingURL=page-review-budget.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-review-budget.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/page-review-budget.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,wBAAwB,EAE7B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,cAAc,EACnB,KAAK,8BAA8B,EACpC,MAAM,4BAA4B,CAAC;AAMpC,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,CAiEnF;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,cAAc,EAAE,GAC/B,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAQvC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,qBAAqB,EAC3B,WAAW,EAAE,SAAS,MAAM,EAAE,GAC7B,wBAAwB,CAsC1B;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,qBAAqB,EAAE,EAC9B,MAAM,SAAkC,EACxC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,8BAA8B,CAqHhC;AAED,uGAAuG;AACvG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAKrE;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,qBAAqB,GAC7B,2BAA2B,CAkC7B"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { PAGE_REVIEW_CAPTURE_PLAN_SCHEMA, PAGE_REVIEW_DEFAULT_TILE_BUDGET, PAGE_REVIEW_MAX_TILE_BUDGET, } from "./page-review-contracts.js";
|
|
3
|
+
const severityRank = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
4
|
+
const position = (a, b) => a.rect.y - b.rect.y || a.rect.x - b.rect.x || a.index - b.index || a.id.localeCompare(b.id);
|
|
5
|
+
export function validatePageReviewCapturePlan(value) {
|
|
6
|
+
const fail = (detail) => {
|
|
7
|
+
throw new Error(`Invalid page review capture plan: ${detail}; rerun planning.`);
|
|
8
|
+
};
|
|
9
|
+
if (!value || typeof value !== "object")
|
|
10
|
+
fail("expected an object");
|
|
11
|
+
const p = value;
|
|
12
|
+
if (p.schema !== PAGE_REVIEW_CAPTURE_PLAN_SCHEMA)
|
|
13
|
+
fail("unsupported schema");
|
|
14
|
+
for (const key of [
|
|
15
|
+
"context_id",
|
|
16
|
+
"viewport",
|
|
17
|
+
"state",
|
|
18
|
+
"source_digest",
|
|
19
|
+
"recipe_version",
|
|
20
|
+
]) {
|
|
21
|
+
if (typeof p[key] !== "string" || !p[key].trim())
|
|
22
|
+
fail(`missing ${key}`);
|
|
23
|
+
}
|
|
24
|
+
if (p.theme !== "light" && p.theme !== "dark")
|
|
25
|
+
fail("invalid theme");
|
|
26
|
+
if (!Number.isFinite(p.dpr) || p.dpr <= 0)
|
|
27
|
+
fail("invalid DPR");
|
|
28
|
+
for (const key of ["viewport_width", "viewport_height", "page_width", "page_height"]) {
|
|
29
|
+
if (!Number.isSafeInteger(p[key]) || p[key] <= 0)
|
|
30
|
+
fail(`invalid ${key}`);
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(p.candidates) || !p.candidates.length)
|
|
33
|
+
fail("no candidates");
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
for (const c of p.candidates) {
|
|
36
|
+
if (!c || typeof c.id !== "string" || !c.id || seen.has(c.id))
|
|
37
|
+
fail("missing or duplicate candidate ID");
|
|
38
|
+
seen.add(c.id);
|
|
39
|
+
if (!Number.isSafeInteger(c.index) || c.index < 0 || typeof c.label !== "string")
|
|
40
|
+
fail(`invalid candidate ${c.id}`);
|
|
41
|
+
const r = c.rect;
|
|
42
|
+
if (!r ||
|
|
43
|
+
![r.x, r.y, r.width, r.height].every(Number.isSafeInteger) ||
|
|
44
|
+
r.x < 0 ||
|
|
45
|
+
r.y < 0 ||
|
|
46
|
+
r.width <= 0 ||
|
|
47
|
+
r.height <= 0 ||
|
|
48
|
+
r.x + r.width > p.page_width ||
|
|
49
|
+
r.y + r.height > p.page_height)
|
|
50
|
+
fail(`invalid rectangle ${c.id}`);
|
|
51
|
+
if (c.scope !== undefined && (typeof c.scope !== "string" || !c.scope))
|
|
52
|
+
fail(`invalid scope ${c.id}`);
|
|
53
|
+
if (!Array.isArray(c.gate_hits) ||
|
|
54
|
+
c.gate_hits.some((h) => !h || typeof h.check_id !== "string" || !h.check_id || !(h.severity in severityRank)))
|
|
55
|
+
fail(`invalid gate hits ${c.id}`);
|
|
56
|
+
}
|
|
57
|
+
if (p.required_scopes !== undefined &&
|
|
58
|
+
(!Array.isArray(p.required_scopes) ||
|
|
59
|
+
p.required_scopes.some((s) => typeof s !== "string" || !s)))
|
|
60
|
+
fail("invalid required scopes");
|
|
61
|
+
const bands = p.candidates.filter((c) => c.scope === undefined).sort(position);
|
|
62
|
+
if (!bands.length ||
|
|
63
|
+
bands[0].rect.y !== 0 ||
|
|
64
|
+
bands.at(-1).rect.y + bands.at(-1).rect.height !== p.page_height)
|
|
65
|
+
fail("top and bottom page bands are required");
|
|
66
|
+
return p;
|
|
67
|
+
}
|
|
68
|
+
export function intervalUnion(rects) {
|
|
69
|
+
const out = [];
|
|
70
|
+
for (const r of [...rects].sort((a, b) => a.y - b.y || a.height - b.height)) {
|
|
71
|
+
const last = out.at(-1);
|
|
72
|
+
if (last && r.y <= last.end)
|
|
73
|
+
last.end = Math.max(last.end, r.y + r.height);
|
|
74
|
+
else
|
|
75
|
+
out.push({ start: r.y, end: r.y + r.height });
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
export function allocationCoverage(plan, selectedIds) {
|
|
80
|
+
const selected = new Set(selectedIds);
|
|
81
|
+
const kept = plan.candidates.filter((c) => selected.has(c.id));
|
|
82
|
+
// A narrow scope cannot stand in for a full-width document band.
|
|
83
|
+
const reviewed = intervalUnion(kept
|
|
84
|
+
.filter((c) => !c.scope && c.rect.x === 0 && c.rect.width === plan.page_width)
|
|
85
|
+
.map((c) => c.rect));
|
|
86
|
+
const uncovered = [];
|
|
87
|
+
let cursor = 0;
|
|
88
|
+
for (const r of reviewed) {
|
|
89
|
+
if (r.start > cursor)
|
|
90
|
+
uncovered.push({ start: cursor, end: r.start });
|
|
91
|
+
cursor = r.end;
|
|
92
|
+
}
|
|
93
|
+
if (cursor < plan.page_height)
|
|
94
|
+
uncovered.push({ start: cursor, end: plan.page_height });
|
|
95
|
+
const missed = plan.candidates.filter((c) => !selected.has(c.id));
|
|
96
|
+
const scopes = new Set([
|
|
97
|
+
...(plan.required_scopes ?? []),
|
|
98
|
+
...plan.candidates.flatMap((c) => (c.scope ? [c.scope] : [])),
|
|
99
|
+
]);
|
|
100
|
+
const omittedScopes = [...scopes]
|
|
101
|
+
.filter((s) => !plan.candidates.some((c) => c.scope === s) || missed.some((c) => c.scope === s))
|
|
102
|
+
.sort();
|
|
103
|
+
return {
|
|
104
|
+
page_height_px: plan.page_height,
|
|
105
|
+
reviewed_height_px: reviewed.reduce((sum, r) => sum + r.end - r.start, 0),
|
|
106
|
+
bands_total: plan.candidates.filter((c) => !c.scope).length,
|
|
107
|
+
bands_reviewed: kept.filter((c) => !c.scope).length,
|
|
108
|
+
capped: uncovered.length > 0 || omittedScopes.length > 0 || missed.some((c) => !c.scope),
|
|
109
|
+
selected_rectangles: kept.map((c) => ({ ...c.rect })),
|
|
110
|
+
reviewed_intervals: reviewed,
|
|
111
|
+
uncovered_intervals: uncovered,
|
|
112
|
+
omitted_gate_hits: [
|
|
113
|
+
...new Set(missed.flatMap((c) => c.gate_hits.map((h) => h.check_id))),
|
|
114
|
+
].sort(),
|
|
115
|
+
omitted_scopes: omittedScopes,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Reserve edges, prioritize gate hits, then distribute by remaining height. */
|
|
119
|
+
export function allocateTileBudget(plans, budget = PAGE_REVIEW_DEFAULT_TILE_BUDGET, ceilings) {
|
|
120
|
+
if (!Number.isSafeInteger(budget) || budget < 1 || budget > PAGE_REVIEW_MAX_TILE_BUDGET)
|
|
121
|
+
throw new Error(`Tile budget must be an integer from 1 to ${PAGE_REVIEW_MAX_TILE_BUDGET}.`);
|
|
122
|
+
const rows = [...plans]
|
|
123
|
+
.map(validatePageReviewCapturePlan)
|
|
124
|
+
.sort((a, b) => a.context_id.localeCompare(b.context_id))
|
|
125
|
+
.map((plan) => {
|
|
126
|
+
const bands = plan.candidates.filter((c) => !c.scope).sort(position);
|
|
127
|
+
const edges = [bands[0], bands.at(-1)].filter((c, i, a) => a.findIndex((x) => x.id === c.id) === i);
|
|
128
|
+
const ceiling = ceilings?.[plan.context_id] ?? budget;
|
|
129
|
+
if (!Number.isSafeInteger(ceiling) || ceiling < edges.length)
|
|
130
|
+
throw new Error(`Context ${plan.context_id} requires a tile ceiling of at least ${edges.length} for its top and bottom bands (got ${ceiling}).`);
|
|
131
|
+
return { plan, ceiling, selected: new Set(edges.map((c) => c.id)) };
|
|
132
|
+
});
|
|
133
|
+
if (new Set(rows.map((r) => r.plan.context_id)).size !== rows.length)
|
|
134
|
+
throw new Error("Duplicate page review context ID.");
|
|
135
|
+
let used = rows.reduce((s, r) => s + r.selected.size, 0);
|
|
136
|
+
if (used > budget)
|
|
137
|
+
throw new Error(`Tile budget requires at least ${used} to reserve every context's top and bottom bands (got ${budget}).`);
|
|
138
|
+
const hits = rows.flatMap((row) => row.plan.candidates
|
|
139
|
+
.filter((c) => c.gate_hits.length && !row.selected.has(c.id))
|
|
140
|
+
.map((c) => ({
|
|
141
|
+
row,
|
|
142
|
+
c,
|
|
143
|
+
rank: Math.min(...c.gate_hits.map((h) => severityRank[h.severity])),
|
|
144
|
+
})));
|
|
145
|
+
hits.sort((a, b) => a.rank - b.rank ||
|
|
146
|
+
a.row.plan.context_id.localeCompare(b.row.plan.context_id) ||
|
|
147
|
+
position(a.c, b.c));
|
|
148
|
+
for (const { row, c } of hits) {
|
|
149
|
+
if (used >= budget)
|
|
150
|
+
break;
|
|
151
|
+
if (row.selected.size >= row.ceiling)
|
|
152
|
+
continue;
|
|
153
|
+
row.selected.add(c.id);
|
|
154
|
+
used++;
|
|
155
|
+
}
|
|
156
|
+
const remaining = (row) => row.plan.candidates.filter((c) => !row.selected.has(c.id)).sort(position);
|
|
157
|
+
while (used < budget) {
|
|
158
|
+
const eligible = rows
|
|
159
|
+
.map((row) => {
|
|
160
|
+
const candidates = remaining(row);
|
|
161
|
+
return {
|
|
162
|
+
row,
|
|
163
|
+
candidates,
|
|
164
|
+
capacity: Math.min(candidates.length, row.ceiling - row.selected.size),
|
|
165
|
+
height: intervalUnion(candidates.map((c) => c.rect)).reduce((s, r) => s + r.end - r.start, 0),
|
|
166
|
+
quota: 0,
|
|
167
|
+
fraction: 0,
|
|
168
|
+
};
|
|
169
|
+
})
|
|
170
|
+
.filter((r) => r.capacity > 0);
|
|
171
|
+
if (!eligible.length)
|
|
172
|
+
break;
|
|
173
|
+
const slots = budget - used, totalHeight = eligible.reduce((s, r) => s + r.height, 0);
|
|
174
|
+
for (const r of eligible) {
|
|
175
|
+
const exact = (slots * r.height) / totalHeight;
|
|
176
|
+
r.quota = Math.min(r.capacity, Math.floor(exact));
|
|
177
|
+
r.fraction = exact - Math.floor(exact);
|
|
178
|
+
}
|
|
179
|
+
let spare = slots - eligible.reduce((s, r) => s + r.quota, 0);
|
|
180
|
+
for (const r of [...eligible].sort((a, b) => b.fraction - a.fraction || a.row.plan.context_id.localeCompare(b.row.plan.context_id))) {
|
|
181
|
+
if (spare > 0 && r.quota < r.capacity) {
|
|
182
|
+
r.quota++;
|
|
183
|
+
spare--;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const r of eligible) {
|
|
187
|
+
for (let i = 0; i < r.quota; i++) {
|
|
188
|
+
const index = Math.floor(((i + 0.5) * r.candidates.length) / r.quota);
|
|
189
|
+
r.row.selected.add(r.candidates[index].id);
|
|
190
|
+
used++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
budget,
|
|
196
|
+
used,
|
|
197
|
+
contexts: rows.map(({ plan, ceiling, selected }) => {
|
|
198
|
+
const selected_ids = plan.candidates
|
|
199
|
+
.filter((c) => selected.has(c.id))
|
|
200
|
+
.sort(position)
|
|
201
|
+
.map((c) => c.id);
|
|
202
|
+
return {
|
|
203
|
+
context_id: plan.context_id,
|
|
204
|
+
plan,
|
|
205
|
+
selected_ids,
|
|
206
|
+
ceiling,
|
|
207
|
+
omitted_candidates: plan.candidates
|
|
208
|
+
.filter((c) => !selected.has(c.id))
|
|
209
|
+
.map((c) => ({
|
|
210
|
+
id: c.id,
|
|
211
|
+
reason: ceilings?.[plan.context_id] !== undefined && selected.size >= ceiling
|
|
212
|
+
? "ceiling"
|
|
213
|
+
: "budget",
|
|
214
|
+
})),
|
|
215
|
+
coverage: allocationCoverage(plan, selected_ids),
|
|
216
|
+
};
|
|
217
|
+
}),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/** Gate-hit annotations are planning results; geometry and page state are authoritative at capture. */
|
|
221
|
+
export function capturePlanDigest(plan) {
|
|
222
|
+
const { candidates, ...rest } = plan;
|
|
223
|
+
return createHash("sha256")
|
|
224
|
+
.update(JSON.stringify({ ...rest, candidates: candidates.map(({ gate_hits, ...c }) => c) }))
|
|
225
|
+
.digest("hex");
|
|
226
|
+
}
|
|
227
|
+
export function validatePageReviewAllocation(value, current) {
|
|
228
|
+
const allocation = value;
|
|
229
|
+
if (!allocation || typeof allocation !== "object")
|
|
230
|
+
throw new Error("Missing page review allocation; rerun planning.");
|
|
231
|
+
validatePageReviewCapturePlan(allocation.plan);
|
|
232
|
+
if (allocation.context_id !== current.context_id ||
|
|
233
|
+
capturePlanDigest(allocation.plan) !== capturePlanDigest(current))
|
|
234
|
+
throw new Error("Page review capture geometry or source changed since planning; rerun the review.");
|
|
235
|
+
if (!Array.isArray(allocation.selected_ids) ||
|
|
236
|
+
!allocation.selected_ids.length ||
|
|
237
|
+
new Set(allocation.selected_ids).size !== allocation.selected_ids.length ||
|
|
238
|
+
allocation.selected_ids.some((id) => !current.candidates.some((c) => c.id === id)))
|
|
239
|
+
throw new Error("Invalid selected tile IDs in page review allocation.");
|
|
240
|
+
if (!Number.isSafeInteger(allocation.ceiling) ||
|
|
241
|
+
allocation.selected_ids.length > allocation.ceiling)
|
|
242
|
+
throw new Error("Page review allocation exceeds its context ceiling.");
|
|
243
|
+
const bands = current.candidates.filter((c) => !c.scope).sort(position);
|
|
244
|
+
if (!allocation.selected_ids.includes(bands[0].id) ||
|
|
245
|
+
!allocation.selected_ids.includes(bands.at(-1).id))
|
|
246
|
+
throw new Error("Page review allocation must include top and bottom bands.");
|
|
247
|
+
const coverage = allocationCoverage(allocation.plan, allocation.selected_ids);
|
|
248
|
+
if (JSON.stringify(coverage) !== JSON.stringify(allocation.coverage))
|
|
249
|
+
throw new Error("Page review allocation coverage is inconsistent with selected tiles.");
|
|
250
|
+
return { ...allocation, coverage };
|
|
251
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { CritiqueCoverage, CritiqueFinding } from "./critique.js";
|
|
2
|
+
export declare const PAGE_REVIEW_CAPTURE_PLAN_SCHEMA = "harnery-page-review-capture-plan/v1";
|
|
3
|
+
export declare const PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA = "harnery-page-review-native-evidence/v2";
|
|
4
|
+
export declare const PAGE_REVIEW_DECISIONS_SCHEMA = "harnery-page-review-decisions/v1";
|
|
5
|
+
export declare const PAGE_REVIEW_DEFAULT_TILE_BUDGET = 96;
|
|
6
|
+
export declare const PAGE_REVIEW_MAX_TILE_BUDGET = 400;
|
|
7
|
+
/** Rectangles are native image pixels, never CSS pixels or overview pixels. */
|
|
8
|
+
export interface PageReviewRect {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}
|
|
14
|
+
export interface PageReviewCandidate {
|
|
15
|
+
id: string;
|
|
16
|
+
index: number;
|
|
17
|
+
label: string;
|
|
18
|
+
rect: PageReviewRect;
|
|
19
|
+
scope?: string;
|
|
20
|
+
gate_hits: Array<{
|
|
21
|
+
check_id: string;
|
|
22
|
+
severity: "critical" | "high" | "medium" | "low" | "info";
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
/** Private diagnostic receipt, not an additional acceptance condition. Hash
|
|
26
|
+
* the referenced file bytes directly to reproduce source_digest. */
|
|
27
|
+
export interface PageReviewSourceEvidence {
|
|
28
|
+
path: string;
|
|
29
|
+
sha256: string;
|
|
30
|
+
bytes: number;
|
|
31
|
+
encoding: "utf8";
|
|
32
|
+
}
|
|
33
|
+
export interface PageReviewCapturePlan {
|
|
34
|
+
schema: typeof PAGE_REVIEW_CAPTURE_PLAN_SCHEMA;
|
|
35
|
+
context_id: string;
|
|
36
|
+
viewport: string;
|
|
37
|
+
viewport_width: number;
|
|
38
|
+
viewport_height: number;
|
|
39
|
+
theme: "light" | "dark";
|
|
40
|
+
state: string;
|
|
41
|
+
dpr: number;
|
|
42
|
+
page_width: number;
|
|
43
|
+
page_height: number;
|
|
44
|
+
/** Stable content/geometry signature; excludes capture timestamps. */
|
|
45
|
+
source_digest: string;
|
|
46
|
+
recipe_version: string;
|
|
47
|
+
required_scopes: string[];
|
|
48
|
+
candidates: PageReviewCandidate[];
|
|
49
|
+
}
|
|
50
|
+
export interface PageReviewBudgetCoverage extends CritiqueCoverage {
|
|
51
|
+
selected_rectangles: PageReviewRect[];
|
|
52
|
+
reviewed_intervals: Array<{
|
|
53
|
+
start: number;
|
|
54
|
+
end: number;
|
|
55
|
+
}>;
|
|
56
|
+
uncovered_intervals: Array<{
|
|
57
|
+
start: number;
|
|
58
|
+
end: number;
|
|
59
|
+
}>;
|
|
60
|
+
omitted_gate_hits: string[];
|
|
61
|
+
omitted_scopes: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface PageReviewContextAllocation {
|
|
64
|
+
context_id: string;
|
|
65
|
+
plan: PageReviewCapturePlan;
|
|
66
|
+
selected_ids: string[];
|
|
67
|
+
ceiling: number;
|
|
68
|
+
omitted_candidates: Array<{
|
|
69
|
+
id: string;
|
|
70
|
+
reason: "budget" | "ceiling";
|
|
71
|
+
}>;
|
|
72
|
+
coverage: PageReviewBudgetCoverage;
|
|
73
|
+
}
|
|
74
|
+
export interface PageReviewTileBudgetAllocation {
|
|
75
|
+
budget: number;
|
|
76
|
+
used: number;
|
|
77
|
+
contexts: PageReviewContextAllocation[];
|
|
78
|
+
}
|
|
79
|
+
/** Pixel identity is meaningful only within an identical rendering contract. */
|
|
80
|
+
export interface PageReviewEvidenceContext {
|
|
81
|
+
viewport: string;
|
|
82
|
+
viewport_width: number;
|
|
83
|
+
viewport_height: number;
|
|
84
|
+
theme: "light" | "dark";
|
|
85
|
+
state: string;
|
|
86
|
+
dpr: number;
|
|
87
|
+
recipe_version: string;
|
|
88
|
+
rubric_digest: string;
|
|
89
|
+
critique_contract_version: number;
|
|
90
|
+
}
|
|
91
|
+
/** In-memory form. The snapshot store writes PNGs separately from metadata. */
|
|
92
|
+
export interface PageReviewNativeTile {
|
|
93
|
+
tile_id: string;
|
|
94
|
+
index: number;
|
|
95
|
+
label: string;
|
|
96
|
+
rect: PageReviewRect;
|
|
97
|
+
pixel_digest: string;
|
|
98
|
+
png: Buffer;
|
|
99
|
+
}
|
|
100
|
+
export interface PageReviewNativeEvidence {
|
|
101
|
+
schema: typeof PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA;
|
|
102
|
+
context: PageReviewEvidenceContext;
|
|
103
|
+
tiles: PageReviewNativeTile[];
|
|
104
|
+
}
|
|
105
|
+
export interface PageReviewDurableDecision {
|
|
106
|
+
finding_key: string;
|
|
107
|
+
tile_pixel_digest: string;
|
|
108
|
+
rect: PageReviewRect;
|
|
109
|
+
finding: Pick<CritiqueFinding, "severity" | "category" | "description">;
|
|
110
|
+
disposition: "artifact" | "not-a-defect" | "confirmed" | "duplicate-of-gate";
|
|
111
|
+
reviewer: string;
|
|
112
|
+
at: string;
|
|
113
|
+
note?: string;
|
|
114
|
+
}
|
|
115
|
+
/** Stored independently of baseline replacement and expiring pack directories. */
|
|
116
|
+
export interface PageReviewDecisionSlot {
|
|
117
|
+
schema: typeof PAGE_REVIEW_DECISIONS_SCHEMA;
|
|
118
|
+
target: string;
|
|
119
|
+
context: PageReviewEvidenceContext;
|
|
120
|
+
source_run: string;
|
|
121
|
+
source_revision: string | null;
|
|
122
|
+
reviewer: string;
|
|
123
|
+
reviewed_at: string;
|
|
124
|
+
complete: true;
|
|
125
|
+
decisions: PageReviewDurableDecision[];
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=page-review-contracts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-review-contracts.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/page-review-contracts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const PAGE_REVIEW_CAPTURE_PLAN_SCHEMA = "harnery-page-review-capture-plan/v1";
|
|
2
|
+
export const PAGE_REVIEW_NATIVE_EVIDENCE_SCHEMA = "harnery-page-review-native-evidence/v2";
|
|
3
|
+
export const PAGE_REVIEW_DECISIONS_SCHEMA = "harnery-page-review-decisions/v1";
|
|
4
|
+
export const PAGE_REVIEW_DEFAULT_TILE_BUDGET = 96;
|
|
5
|
+
export const PAGE_REVIEW_MAX_TILE_BUDGET = 400;
|