@reticlehq/server 3.8.2 → 3.10.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/LICENSE +201 -104
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/SKILL.md +13 -12
- package/bin/launch.js +13 -0
- package/bin/package.json +3 -0
- package/bin/reticle.js +66 -8
- package/dist/chromium-launch-options.d.ts +25 -0
- package/dist/chromium-launch-options.js +21 -1
- package/dist/command/cli/adhoc-suite.js +2 -0
- package/dist/command/cli/adhoc-verdict.d.ts +2 -43
- package/dist/command/cli/adhoc-verdict.js +50 -160
- package/dist/command/cli/answers/gate-exit.d.ts +6 -2
- package/dist/command/cli/answers/gate-exit.js +12 -2
- package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
- package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
- package/dist/command/cli/ci-hint.d.ts +44 -0
- package/dist/command/cli/ci-hint.js +72 -0
- package/dist/command/cli/cli-doctor.d.ts +6 -1
- package/dist/command/cli/cli-doctor.js +46 -5
- package/dist/command/cli/cli-flow-commands.d.ts +7 -1
- package/dist/command/cli/cli-flow-commands.js +39 -24
- package/dist/command/cli/cli-kill.d.ts +21 -0
- package/dist/command/cli/cli-kill.js +47 -4
- package/dist/command/cli/cli-parse-compare.d.ts +22 -0
- package/dist/command/cli/cli-parse-compare.js +75 -0
- package/dist/command/cli/cli-parse-grade.d.ts +36 -0
- package/dist/command/cli/cli-parse-grade.js +75 -0
- package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
- package/dist/command/cli/cli-parse-grammar.js +18 -20
- package/dist/command/cli/cli-parse-verify.d.ts +10 -0
- package/dist/command/cli/cli-parse-verify.js +63 -14
- package/dist/command/cli/cli-parse.d.ts +22 -17
- package/dist/command/cli/cli-parse.js +54 -32
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +29 -20
- package/dist/command/cli/cli-usage.js +61 -31
- package/dist/command/cli/cli-verify.d.ts +17 -3
- package/dist/command/cli/cli-verify.js +59 -21
- package/dist/command/cli/cloud-cli.js +2 -119
- package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
- package/dist/command/cli/daemon-link/daemon-client.js +205 -0
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
- package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
- package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
- package/dist/command/cli/doctor/doctor-fix.js +89 -0
- package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/doctor-repairs.d.ts +64 -0
- package/dist/command/cli/doctor-repairs.js +214 -0
- package/dist/command/cli/drive/drive-command.js +3 -7
- package/dist/command/cli/ensure-daemon.d.ts +26 -0
- package/dist/command/cli/ensure-daemon.js +57 -0
- package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
- package/dist/command/cli/finished-run/grade-command.js +180 -0
- package/dist/command/cli/first-use-checks.d.ts +41 -0
- package/dist/command/cli/first-use-checks.js +127 -0
- package/dist/command/cli/first-verdict-node.d.ts +3 -0
- package/dist/command/cli/first-verdict-node.js +189 -0
- package/dist/command/cli/first-verdict.d.ts +126 -0
- package/dist/command/cli/first-verdict.js +267 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
- package/dist/command/cli/launch/sdk-version-match.js +3 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
- package/dist/command/cli/mcp-command.js +13 -4
- package/dist/command/cli/ports/port-holder.d.ts +11 -0
- package/dist/command/cli/ports/port-holder.js +36 -4
- package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
- package/dist/command/cli/setup-mcp-cli.js +98 -23
- package/dist/command/cli/status/status-lines.d.ts +2 -0
- package/dist/command/cli/status/status-lines.js +72 -17
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +24 -6
- package/dist/command/cli/try-command.d.ts +7 -0
- package/dist/command/cli/try-command.js +11 -3
- package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
- package/dist/command/cli/two-builds/compare-command.js +314 -0
- package/dist/command/cli/verify-against.d.ts +61 -0
- package/dist/command/cli/verify-against.js +187 -0
- package/dist/command/cli/verify-no-session.d.ts +2 -0
- package/dist/command/cli/verify-no-session.js +13 -0
- package/dist/command/cli/verify-results.d.ts +35 -2
- package/dist/command/cli/verify-results.js +76 -10
- package/dist/command/cli.js +112 -70
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
- package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
- package/dist/command/daemon/daemon-argv.d.ts +9 -0
- package/dist/command/daemon/daemon-argv.js +11 -0
- package/dist/command/daemon/daemon-resolve.d.ts +8 -1
- package/dist/command/daemon/daemon-resolve.js +27 -1
- package/dist/command/daemon/daemon.d.ts +22 -4
- package/dist/command/daemon/daemon.js +52 -10
- package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
- package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
- package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
- package/dist/command/daemon/lifetime/death-cause.js +149 -0
- package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
- package/dist/command/daemon/lifetime/heartbeat.js +11 -15
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- package/dist/command/daemon/port-state.d.ts +14 -0
- package/dist/command/daemon/port-state.js +31 -0
- package/dist/command/setup/agent-configs.d.ts +2 -0
- package/dist/command/setup/agent-configs.js +42 -15
- package/dist/command/setup/agent-next-steps.d.ts +77 -0
- package/dist/command/setup/agent-next-steps.js +284 -0
- package/dist/command/setup/agent-writer.js +11 -6
- package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
- package/dist/command/setup/bringup/dev-server-files.js +17 -0
- package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
- package/dist/command/setup/bringup/static-page-server.js +43 -9
- package/dist/command/setup/init/init-host.js +2 -0
- package/dist/command/setup/init/init-runtime.d.ts +6 -1
- package/dist/command/setup/init/init-runtime.js +63 -21
- package/dist/command/setup/mcp-launcher.d.ts +3 -0
- package/dist/command/setup/mcp-launcher.js +11 -0
- package/dist/command/setup/node-effects.d.ts +3 -2
- package/dist/command/setup/node-effects.js +9 -3
- package/dist/command/setup/remaining-steps.d.ts +8 -0
- package/dist/command/setup/remaining-steps.js +10 -0
- package/dist/command/setup/run-setup.d.ts +2 -0
- package/dist/command/setup/run-setup.js +9 -1
- package/dist/command/setup/setup-command.js +36 -15
- package/dist/command/setup/setup-mcp.d.ts +8 -0
- package/dist/command/setup/setup-mcp.js +47 -20
- package/dist/command/setup/start-dev-server.d.ts +8 -0
- package/dist/command/setup/start-dev-server.js +43 -0
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/identity/server-version.d.ts +2 -0
- package/dist/command/version/identity/server-version.js +2 -0
- package/dist/command/version/version-skew.d.ts +7 -0
- package/dist/command/version/version-skew.js +14 -3
- package/dist/features/compare/action-plan.d.ts +260 -0
- package/dist/features/compare/action-plan.js +543 -0
- package/dist/features/compare/behaviour-compare.d.ts +24 -0
- package/dist/features/compare/behaviour-compare.js +85 -0
- package/dist/features/compare/behaviour-diff.d.ts +97 -0
- package/dist/features/compare/behaviour-diff.js +202 -0
- package/dist/features/compare/behaviour-report.d.ts +40 -0
- package/dist/features/compare/behaviour-report.js +128 -0
- package/dist/features/compare/build-readings.d.ts +106 -0
- package/dist/features/compare/build-readings.js +250 -0
- package/dist/features/compare/compare-diff.d.ts +62 -0
- package/dist/features/compare/compare-diff.js +177 -0
- package/dist/features/compare/compare-report-html.d.ts +6 -0
- package/dist/features/compare/compare-report-html.js +102 -0
- package/dist/features/compare/compare-report.d.ts +15 -0
- package/dist/features/compare/compare-report.js +73 -0
- package/dist/features/compare/compare-run.d.ts +60 -0
- package/dist/features/compare/compare-run.js +123 -0
- package/dist/features/compare/outside/effect-lines.d.ts +26 -0
- package/dist/features/compare/outside/effect-lines.js +103 -0
- package/dist/features/compare/outside/state-sources.d.ts +76 -0
- package/dist/features/compare/outside/state-sources.js +164 -0
- package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
- package/dist/features/compare/outside/value-dictionary.js +227 -0
- package/dist/features/compare/visible-content.d.ts +20 -0
- package/dist/features/compare/visible-content.js +125 -0
- package/dist/features/crawl/crawl-empty.js +2 -1
- package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
- package/dist/features/crawl/crawl-exhaustive.js +138 -0
- package/dist/features/crawl/crawl-tools.d.ts +9 -2
- package/dist/features/crawl/crawl-tools.js +28 -12
- package/dist/features/crawl/crawl.d.ts +8 -9
- package/dist/features/crawl/crawl.js +61 -65
- package/dist/features/exhaust/app-coverage.d.ts +5 -1
- package/dist/features/exhaust/app-coverage.js +3 -1
- package/dist/features/exhaust/code-coverage.js +8 -4
- package/dist/features/exhaust/edge-cases.d.ts +133 -0
- package/dist/features/exhaust/edge-cases.js +310 -0
- package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
- package/dist/features/exhaust/edges/edge-drive.js +364 -0
- package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
- package/dist/features/exhaust/edges/edge-run.js +169 -0
- package/dist/features/exhaust/explorer.d.ts +87 -14
- package/dist/features/exhaust/explorer.js +159 -25
- package/dist/features/exhaust/failure-branches.d.ts +5 -0
- package/dist/features/exhaust/failure-branches.js +29 -11
- package/dist/features/exhaust/invariants.d.ts +112 -0
- package/dist/features/exhaust/invariants.js +188 -0
- package/dist/features/exhaust/ledger.d.ts +68 -0
- package/dist/features/exhaust/ledger.js +121 -13
- package/dist/features/exhaust/session-fold.d.ts +10 -0
- package/dist/features/exhaust/session-fold.js +46 -3
- package/dist/features/exhaust/session-port.d.ts +3 -1
- package/dist/features/exhaust/session-port.js +97 -28
- package/dist/features/grade/grade-answer.d.ts +99 -0
- package/dist/features/grade/grade-answer.js +112 -0
- package/dist/features/grade/grade-noise.d.ts +27 -0
- package/dist/features/grade/grade-noise.js +55 -0
- package/dist/features/grade/grade-renumber.d.ts +12 -0
- package/dist/features/grade/grade-renumber.js +86 -0
- package/dist/features/grade/grade-state.d.ts +50 -0
- package/dist/features/grade/grade-state.js +93 -0
- package/dist/features/grade/grade-suggest.d.ts +33 -0
- package/dist/features/grade/grade-suggest.js +98 -0
- package/dist/features/license/license.d.ts +11 -71
- package/dist/features/license/license.js +43 -136
- package/dist/features/visual/desktop-capture.d.ts +33 -0
- package/dist/features/visual/desktop-capture.js +94 -0
- package/dist/features/visual/step-shots.js +139 -35
- package/dist/features/visual/visual-tools.d.ts +0 -18
- package/dist/features/visual/visual-tools.js +67 -99
- package/dist/import-graph.js +5 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +19 -7
- package/dist/judgement/capsule/causal-summary.js +9 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +16 -2
- package/dist/judgement/runs/run-ledger.d.ts +7 -5
- package/dist/judgement/runs/run-ledger.js +98 -69
- package/dist/judgement/runs/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- package/dist/judgement/runs/verification-sync.d.ts +6 -3
- package/dist/judgement/runs/verification-sync.js +21 -10
- package/dist/language/flows/affected-tools.d.ts +1 -1
- package/dist/language/flows/affected-tools.js +49 -30
- package/dist/language/flows/change/git-changed.d.ts +2 -1
- package/dist/language/flows/change/git-changed.js +19 -2
- package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
- package/dist/language/flows/fields/flow-secret-field.js +77 -21
- package/dist/language/flows/flow-anchor.d.ts +60 -2
- package/dist/language/flows/flow-anchor.js +125 -20
- package/dist/language/flows/flow-classify.d.ts +20 -0
- package/dist/language/flows/flow-classify.js +90 -12
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +25 -1
- package/dist/language/flows/flow-journey.d.ts +38 -4
- package/dist/language/flows/flow-journey.js +138 -8
- package/dist/language/flows/flow-replay-run.d.ts +0 -16
- package/dist/language/flows/flow-replay-run.js +76 -14
- package/dist/language/flows/flow-replay-types.d.ts +4 -2
- package/dist/language/flows/flow-replay.d.ts +19 -1
- package/dist/language/flows/flow-replay.js +169 -52
- package/dist/language/flows/flow-replayable.js +7 -1
- package/dist/language/flows/flow-start-path.d.ts +34 -5
- package/dist/language/flows/flow-start-path.js +202 -15
- package/dist/language/flows/flow-step-runners.d.ts +14 -13
- package/dist/language/flows/flow-step-runners.js +184 -109
- package/dist/language/flows/flow-store-for-session.d.ts +26 -25
- package/dist/language/flows/flow-store-for-session.js +51 -5
- package/dist/language/flows/flow-tools.js +46 -33
- package/dist/language/flows/flows.js +176 -76
- package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
- package/dist/language/flows/recording/tape/recordings.js +112 -49
- package/dist/language/flows/replay.d.ts +36 -12
- package/dist/language/flows/replay.js +193 -50
- package/dist/language/flows/steps/page-steps.d.ts +68 -0
- package/dist/language/flows/steps/page-steps.js +198 -0
- package/dist/language/flows/suite/sequential-run.d.ts +68 -0
- package/dist/language/flows/suite/sequential-run.js +96 -0
- package/dist/language/flows/verify-change-tools.js +26 -15
- package/dist/launch-chromium.d.ts +1 -0
- package/dist/launch-chromium.js +49 -12
- package/dist/memory/cloud/background-sync.d.ts +13 -0
- package/dist/memory/cloud/background-sync.js +24 -3
- package/dist/memory/cloud/sync-daemon.js +26 -27
- package/dist/memory/cloud/sync-screenshots.js +6 -1
- package/dist/memory/journal/attach-journal.js +2 -1
- package/dist/memory/journal/drive-flow.d.ts +7 -0
- package/dist/memory/journal/drive-flow.js +44 -13
- package/dist/memory/journal/journal-recorder.d.ts +4 -2
- package/dist/memory/journal/session-journal.d.ts +7 -0
- package/dist/memory/journal/session-journal.js +58 -10
- package/dist/memory/project/root-claims.d.ts +9 -0
- package/dist/memory/project/root-claims.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +13 -4
- package/dist/portal/bridge/bridge.js +10 -9
- package/dist/portal/input/download-capture.d.ts +7 -0
- package/dist/portal/input/download-capture.js +92 -0
- package/dist/portal/input/network-detail.d.ts +6 -0
- package/dist/portal/input/network-detail.js +12 -1
- package/dist/portal/input/network-mock-tools.js +49 -13
- package/dist/portal/input/network-mock.d.ts +8 -0
- package/dist/portal/input/network-mock.js +30 -10
- package/dist/portal/input/page-capture.d.ts +24 -0
- package/dist/portal/input/page-capture.js +33 -0
- package/dist/portal/input/real-input.d.ts +35 -18
- package/dist/portal/input/real-input.js +99 -33
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +81 -21
- package/dist/portal/pool/browser-pool.d.ts +16 -30
- package/dist/portal/pool/browser-pool.js +64 -52
- package/dist/portal/pool/context-permissions.d.ts +34 -17
- package/dist/portal/pool/context-permissions.js +94 -1
- package/dist/portal/pool/csp-widen.d.ts +62 -0
- package/dist/portal/pool/csp-widen.js +132 -0
- package/dist/portal/pool/determinism.d.ts +52 -0
- package/dist/portal/pool/determinism.js +259 -0
- package/dist/portal/pool/lease-emulation.d.ts +34 -1
- package/dist/portal/pool/lease-emulation.js +18 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
- package/dist/portal/pool/lease-marker-stamp.js +15 -1
- package/dist/portal/pool/lease-page-error.d.ts +56 -0
- package/dist/portal/pool/lease-page-error.js +160 -0
- package/dist/portal/pool/page-error-journal.d.ts +63 -0
- package/dist/portal/pool/page-error-journal.js +208 -0
- package/dist/portal/pool/playwright-launcher.js +71 -15
- package/dist/portal/pool/pool-contract.d.ts +49 -1
- package/dist/portal/pool/pool-lease.d.ts +70 -2
- package/dist/portal/pool/pool-lease.js +23 -0
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +91 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
- package/dist/portal/session/dev-server/dev-command.js +110 -16
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
- package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
- package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
- package/dist/portal/session/dev-server/project-ports.js +62 -0
- package/dist/portal/session/facts/departed-network.d.ts +66 -0
- package/dist/portal/session/facts/departed-network.js +142 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
- package/dist/portal/session/no-session-diagnosis.js +76 -27
- package/dist/portal/session/no-session-next-action.d.ts +14 -0
- package/dist/portal/session/no-session-next-action.js +56 -7
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +41 -4
- package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
- package/dist/portal/session/page-commands/undeclared-command.js +16 -7
- package/dist/portal/session/recorded-gaps.d.ts +1 -1
- package/dist/portal/session/recorded-gaps.js +5 -2
- package/dist/portal/session/serving-directory.d.ts +10 -0
- package/dist/portal/session/serving-directory.js +39 -8
- package/dist/portal/session/session-manager.d.ts +10 -0
- package/dist/portal/session/session-manager.js +211 -81
- package/dist/portal/session/session.js +4 -3
- package/dist/portal/session/zero-install-first-call.d.ts +20 -1
- package/dist/portal/session/zero-install-first-call.js +34 -2
- package/dist/start-wiring.d.ts +30 -2
- package/dist/start-wiring.js +74 -9
- package/dist/surface/mcp/mcp-proxy.js +10 -2
- package/dist/surface/mcp/mcp.js +8 -5
- package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
- package/dist/surface/mcp/peer/agents-connected.js +58 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
- package/dist/surface/mcp/shared-params.d.ts +2 -0
- package/dist/surface/mcp/shared-params.js +31 -0
- package/dist/surface/tools/act/act-observation.d.ts +40 -2
- package/dist/surface/tools/act/act-observation.js +118 -12
- package/dist/surface/tools/act/act-preflight.js +38 -18
- package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
- package/dist/surface/tools/act/act-sequence-retry.js +61 -5
- package/dist/surface/tools/act/act-target.js +3 -1
- package/dist/surface/tools/act/after-match.d.ts +10 -0
- package/dist/surface/tools/act/after-match.js +40 -0
- package/dist/surface/tools/act/already-true.js +1 -1
- package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
- package/dist/surface/tools/act/navigation/reload-result.js +25 -2
- package/dist/surface/tools/act/resolve-target.d.ts +17 -1
- package/dist/surface/tools/act/resolve-target.js +59 -9
- package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
- package/dist/surface/tools/act/sequence-grade.js +45 -27
- package/dist/surface/tools/act/settle-in-flight.js +27 -15
- package/dist/surface/tools/act-command.d.ts +23 -0
- package/dist/surface/tools/act-command.js +50 -0
- package/dist/surface/tools/act-sequence-tool.js +81 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +83 -95
- package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
- package/dist/surface/tools/agent/build-staleness.js +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +18 -12
- package/dist/surface/tools/browser-tools.js +87 -13
- package/dist/surface/tools/compare-tools.d.ts +11 -0
- package/dist/surface/tools/compare-tools.js +94 -0
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.js +11 -3
- package/dist/surface/tools/empty-session-list.d.ts +2 -0
- package/dist/surface/tools/empty-session-list.js +4 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +131 -40
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +29 -21
- package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
- package/dist/surface/tools/lease-coverage-tools.js +128 -0
- package/dist/surface/tools/lease-hint.d.ts +42 -1
- package/dist/surface/tools/lease-hint.js +52 -3
- package/dist/surface/tools/lease-readiness.d.ts +47 -0
- package/dist/surface/tools/lease-readiness.js +126 -0
- package/dist/surface/tools/lease-seed.d.ts +16 -1
- package/dist/surface/tools/lease-seed.js +37 -4
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +104 -124
- package/dist/surface/tools/lease-url-identity.d.ts +46 -0
- package/dist/surface/tools/lease-url-identity.js +97 -0
- package/dist/surface/tools/merge-tools.js +99 -2
- package/dist/surface/tools/merged-name-redirect.js +5 -1
- package/dist/surface/tools/observe-tools.js +15 -9
- package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
- package/dist/surface/tools/read/console-pre-attach.js +23 -0
- package/dist/surface/tools/read-tools.js +33 -30
- package/dist/surface/tools/real-input-attempt.d.ts +0 -8
- package/dist/surface/tools/real-input-attempt.js +143 -28
- package/dist/surface/tools/repeat-hint.d.ts +40 -0
- package/dist/surface/tools/repeat-hint.js +171 -0
- package/dist/surface/tools/run-report.d.ts +2 -2
- package/dist/surface/tools/run-report.js +27 -15
- package/dist/surface/tools/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +18 -0
- package/dist/surface/tools/tool-kit.js +9 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +54 -18
- package/dist/surface/tools/type-spelling.d.ts +13 -0
- package/dist/surface/tools/type-spelling.js +36 -0
- package/dist/telemetry/agent-client.d.ts +6 -0
- package/dist/telemetry/agent-client.js +10 -0
- package/dist/telemetry/argument-shape.js +17 -7
- package/dist/telemetry/cli-telemetry.d.ts +10 -1
- package/dist/telemetry/cli-telemetry.js +15 -0
- package/dist/telemetry/init-telemetry.d.ts +2 -1
- package/dist/telemetry/init-telemetry.js +47 -2
- package/dist/telemetry/install-trace.js +23 -4
- package/dist/telemetry/onboarding-funnel.d.ts +19 -2
- package/dist/telemetry/onboarding-funnel.js +25 -3
- package/dist/telemetry/proxy-telemetry.d.ts +2 -1
- package/dist/telemetry/proxy-telemetry.js +2 -2
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +67 -27
- package/dist/telemetry/telemetry.d.ts +3 -1
- package/dist/telemetry/telemetry.js +60 -28
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +15 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/architecture.md +3 -6
- package/docs/capabilities.mdx +61 -1
- package/docs/cli/affected.mdx +9 -7
- package/docs/cli/cloud.mdx +3 -3
- package/docs/cli/compare.mdx +94 -0
- package/docs/cli/doctor.mdx +41 -2
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/help.mdx +4 -2
- package/docs/cli/license.mdx +13 -12
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- package/docs/cli/setup.mdx +13 -2
- package/docs/cli/status.mdx +4 -0
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/update.mdx +2 -2
- package/docs/cli/verify.mdx +23 -1
- package/docs/cli.mdx +34 -24
- package/docs/deploy-checks.md +25 -0
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +17 -22
- package/docs/environment.mdx +1 -0
- package/docs/first-drive.md +1 -1
- package/docs/flows.md +11 -1
- package/docs/frameworks.mdx +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/install-manual.mdx +16 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/server.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/test.mdx +1 -1
- package/docs/packages.mdx +1 -1
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +1 -1
- package/docs/quickstart.mdx +68 -49
- package/docs/skill-setup.md +1 -1
- package/docs/skill.md +14 -13
- package/docs/telemetry.md +6 -4
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +1 -1
- package/docs/usage.md +17 -14
- package/package.json +18 -14
- package/LICENSE-ENTERPRISE +0 -37
- package/dist/features/ee/audit-log.d.ts +0 -14
- package/dist/features/ee/audit-log.js +0 -11
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -13,7 +13,7 @@ import { aliasParam } from './args/alias-args.js';
|
|
|
13
13
|
import { resolveSessionWithin } from '../../portal/session/timing/resolve-within.js';
|
|
14
14
|
import { WALL_CLOCK } from '../../portal/session/timing/wall-clock.js';
|
|
15
15
|
import { timeoutMsSchema } from './args/numeric-bounds.js';
|
|
16
|
-
import { captureAct, captureVerdictedAct,
|
|
16
|
+
import { captureAct, captureVerdictedAct, pageOf, wroteSince } from '../../language/flows/replay.js';
|
|
17
17
|
import { durableArg, durableOutput, reloadAndRecheck, withDurability } from './act/durable.js';
|
|
18
18
|
import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, checkIntent, } from '@reticlehq/core';
|
|
19
19
|
import { leanActResult, mutatedWithin } from './act/act-view.js';
|
|
@@ -34,19 +34,19 @@ import { declaresState } from '@reticlehq/engine/question/predicate/predicate-as
|
|
|
34
34
|
import { isStateUnwatched } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
35
35
|
import { hiddenMatchNote } from '@reticlehq/engine/evidence/already-true.js';
|
|
36
36
|
import { inFlightRequestLabels, repeatedRequestLabels } from './act/settle-in-flight.js';
|
|
37
|
-
import { finishAfterMatch } from './act/after-match.js';
|
|
37
|
+
import { awaitShownMatch, evaluateAfterAct, finishAfterMatch } from './act/after-match.js';
|
|
38
38
|
import { noteProved } from './act/proved-controls.js';
|
|
39
|
-
import { decideVerified } from '@reticlehq/engine/evidence/verified.js';
|
|
39
|
+
import { decideVerified, withDeclinedDialog } from '@reticlehq/engine/evidence/verified.js';
|
|
40
40
|
import { buildHonestyBlock, honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
|
|
41
|
-
import { declaredExpectations, declaresBodyIndependentChannel, } from '@reticlehq/engine/question/declared.js';
|
|
41
|
+
import { declaredExpectations, declaresBodyIndependentChannel, namedReactions, provedConsequences, } from '@reticlehq/engine/question/declared.js';
|
|
42
42
|
import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/evidence/unsettled.js';
|
|
43
43
|
import { saveFailedAssertCapsule } from './act-capsule.js';
|
|
44
44
|
import { blastRadius, buildDivergenceCapsule, wireCapsule } from '../../judgement/capsule/capsule.js';
|
|
45
45
|
import { predicateToExpectedLinks } from '@reticlehq/engine/question/predicate/predicate-to-links.js';
|
|
46
|
-
import { absenceBlindSpotNote, buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
46
|
+
import { absenceBlindSpotNote, buildCoverageStatement, canvasPaintSpots, blindSpotsFromState, failingClauseReadsLostChannel, restsOnCompleteWindow, transportGapNote, Coverage, impeachesCapture, } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
47
47
|
import { acceptedWriteLabels } from '@reticlehq/engine/evidence/accepted-write.js';
|
|
48
48
|
import { unreadWriteLabels, unreadWriteReason } from '@reticlehq/engine/evidence/unread-outcome.js';
|
|
49
|
-
import {
|
|
49
|
+
import { waitForPredicate, provenExpectedLinks, PredicateSchema, } from '@reticlehq/engine/question/predicate/predicate.js';
|
|
50
50
|
import { sessionVerdictFacts } from '../../portal/session/session-verdict-facts.js';
|
|
51
51
|
import { currentOf, healthEnvelope, refuseIfThrottled } from '../../portal/session/session-health.js';
|
|
52
52
|
import { pausedShortCircuit, pausedOutputShape, withControl, PAUSED_NO_VERDICT, } from '../../portal/session/control-envelope.js';
|
|
@@ -54,14 +54,15 @@ import { asNumber, asRecord, asString } from '@reticlehq/core';
|
|
|
54
54
|
import { sourceOf } from './tools-helpers.js';
|
|
55
55
|
import { confirmedByDeclaration } from './act/act-danger.js';
|
|
56
56
|
import { dispatchAct, preflightAct } from './act/act-preflight.js';
|
|
57
|
-
import {
|
|
57
|
+
import { actInconclusive, checkNet, followLostObservation, NAVIGATION_FOLLOW_GRACE_MS, } from './act/act-observation.js';
|
|
58
58
|
import { intentArg, sessionIdShape } from './tool-kit.js';
|
|
59
|
+
import { actCommand } from './act-command.js';
|
|
60
|
+
import { tryRealInput } from './real-input-attempt.js';
|
|
59
61
|
import { verdictIntentGap } from '@reticlehq/engine/evidence/verdict-intent-gap.js';
|
|
60
62
|
import { asActionType, gradeOf } from './act/act-helpers.js';
|
|
61
63
|
import { resolveActTarget } from './act/act-target.js';
|
|
64
|
+
import { hiddenTargetField } from './act/resolve-target.js';
|
|
62
65
|
import { screenRequestFindings, withAdvisories } from './act/screen-request.js';
|
|
63
|
-
import { tryRealInput, rewriteUploadArgs, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
|
|
64
|
-
import { sessionRoot } from '../../memory/project/session-root.js';
|
|
65
66
|
import { gradeOfPredicate } from './assert/assert-grade.js';
|
|
66
67
|
import { readAlreadyTrue } from './act/already-true.js';
|
|
67
68
|
import { engineBlindSpotsField, noteSourceSeen } from '../../portal/session/recorded-gaps.js';
|
|
@@ -71,45 +72,11 @@ import { engineBlindSpotsField, noteSourceSeen } from '../../portal/session/reco
|
|
|
71
72
|
*/
|
|
72
73
|
const ACTION_TYPE_VALUES = Object.values(ActionType);
|
|
73
74
|
const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
|
|
74
|
-
/**
|
|
75
|
-
* Single dispatch point for every ACT and ACT_SEQUENCE command.
|
|
76
|
-
*
|
|
77
|
-
* reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
|
|
78
|
-
* the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
|
|
79
|
-
*
|
|
80
|
-
* captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
|
|
81
|
-
* the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
|
|
82
|
-
* base64 to the browser as if it were an inline content call.
|
|
83
|
-
*/
|
|
84
|
-
export async function actCommand(deps, session, actArgs, timeoutMs) {
|
|
85
|
-
const rewritten = await rewriteUploadArgs({ fs: deps.fs, reticleRoot: sessionRoot(deps, session.id) }, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
|
|
86
|
-
// Sequence and act_and_wait dispatch through here without the ACT handler's tryRealInput.
|
|
87
|
-
// A synthetic hover reports dispatched/settled while CSS :hover never applies — drive a real
|
|
88
|
-
// pointer when one is available, otherwise refuse rather than lie. A press on a lease takes its
|
|
89
|
-
// real keyboard, as reticle_act does: a synthetic Tab moves no focus.
|
|
90
|
-
const hover = ActionType.HOVER === actArgs['action'];
|
|
91
|
-
if (hover || (ActionType.PRESS === actArgs['action'] && deps.realInput === undefined)) {
|
|
92
|
-
const ref = asString(actArgs['ref']);
|
|
93
|
-
if (hover && ref === undefined)
|
|
94
|
-
throw new Error(HOVER_NEEDS_POINTER_MSG);
|
|
95
|
-
const action = hover ? ActionType.HOVER : ActionType.PRESS;
|
|
96
|
-
const real = await tryRealInput(deps, session, ref ?? '', action, actArgs);
|
|
97
|
-
if (hover && real.result === undefined)
|
|
98
|
-
throw new Error(HOVER_NEEDS_POINTER_MSG);
|
|
99
|
-
if (real.result !== undefined) {
|
|
100
|
-
const result = { dispatched: true, settled: real.settled, ...asRecord(real.result) };
|
|
101
|
-
return { kind: 'command_result', id: action, ok: true, result };
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
const bridgeArgs = { ...actArgs, args: rewritten };
|
|
105
|
-
// What the acted element shows (test id, source) is noted in `Session.command`, Harness acts too.
|
|
106
|
-
return session.command(ReticleCommand.ACT, bridgeArgs, timeoutMs);
|
|
107
|
-
}
|
|
108
75
|
export const ACT_TOOLS = [
|
|
109
76
|
{
|
|
110
77
|
name: ReticleTool.ACT,
|
|
111
78
|
example: { ref: 'e42', action: 'fill', args: { value: 'hello' } },
|
|
112
|
-
description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. On a leased tab a press uses the real keyboard: Tab moves focus, and a press with a ref focuses that element first, so Enter or Space presses it as a person would. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
|
|
79
|
+
description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView|insertText. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. For insertText, defaultPrevented=true with valueChanged=true is the success path on an editor that owns its input: it cancelled beforeinput and applied the text, so it is NOT a refusal. insertText refuses with an error when the surface is not contenteditable — an EditContext editor (Monaco, CodeMirror 6) is refused too, because a scripted update fires no textupdate for its model — or when the native command exists and fails. On a leased tab a press uses the real keyboard: Tab moves focus, and a press with a ref focuses that element first, so Enter or Space presses it as a person would. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
|
|
113
80
|
inputSchema: {
|
|
114
81
|
ref: z
|
|
115
82
|
.string()
|
|
@@ -123,7 +90,7 @@ export const ACT_TOOLS = [
|
|
|
123
90
|
args: z
|
|
124
91
|
.record(z.string(), z.unknown())
|
|
125
92
|
.optional()
|
|
126
|
-
.describe('Action-specific arguments: { value } for fill/select (select also drives an ARIA combobox: it opens it and clicks the option by its label), { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt — a Cmd+K) or a click/dblclick (Shift+click range select), { button: "right" | "middle" } for a click (right sends contextmenu), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { native: true } to force a trusted native click, { holdMs: N } to keep the pointer or the key DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration. For press: { keys: ["Control","k"] } holds several keys down TOGETHER (pressed in order, released in reverse) and { code } names the physical key — both stay on the in-page dispatcher, the only path that can express them. For upload: { path } is a path on disk (absolute or relative to the project root; the daemon reads the file and delivers real bytes to the file picker — this is the way to verify document-ingestion flows); or { name, content?, type? } to supply inline bytes directly.'),
|
|
93
|
+
.describe('Action-specific arguments: { value } for fill/select (select also drives an ARIA combobox: it opens it and clicks the option by its label), { text } for type/press/insertText (the key NAME, e.g. Escape or Tab, for press/type — or the text to insert for insertText), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt — a Cmd+K) or a click/dblclick (Shift+click range select), { button: "right" | "middle" } for a click (right sends contextmenu), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { at: { x, y } } for click/dblclick/hover/tap/drag to act at a point of the element as fractions 0..1 of its box (a canvas has no child elements), { to: { x, y } } for drag to end at a point of the drop target (or of the source), { native: true } to force a trusted native click, { holdMs: N } to keep the pointer or the key DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration. For press: { keys: ["Control","k"] } holds several keys down TOGETHER (pressed in order, released in reverse) and { code } names the physical key — both stay on the in-page dispatcher, the only path that can express them. For upload: { path } is a path on disk (absolute or relative to the project root; the daemon reads the file and delivers real bytes to the file picker — this is the way to verify document-ingestion flows); or { name, content?, type? } to supply inline bytes directly.'),
|
|
127
94
|
refuseWhenThrottled: z
|
|
128
95
|
.boolean()
|
|
129
96
|
.optional()
|
|
@@ -160,8 +127,9 @@ export const ACT_TOOLS = [
|
|
|
160
127
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
161
128
|
// Live-control: refuse to drive the page while the human has paused us (before any work).
|
|
162
129
|
const paused = pausedShortCircuit(session);
|
|
163
|
-
if (paused !== undefined)
|
|
130
|
+
if (paused !== undefined) {
|
|
164
131
|
return paused;
|
|
132
|
+
}
|
|
165
133
|
refuseIfThrottled(session, args['refuseWhenThrottled']);
|
|
166
134
|
// Where this step RUNS, read before the action — not after.
|
|
167
135
|
//
|
|
@@ -169,12 +137,13 @@ export const ACT_TOOLS = [
|
|
|
169
137
|
// ambient tape cuts journeys on this value, and stamping the destination put the sign-in click
|
|
170
138
|
// at the head of the page it navigated TO: 4 of 11 auto-captured flows began with
|
|
171
139
|
// `login-submit` on `/deployments`, which is the exact flow the segmentation exists to prevent.
|
|
172
|
-
const routeBefore =
|
|
140
|
+
const routeBefore = pageOf(session.url);
|
|
173
141
|
// Resolve `target` to a ref BEFORE the action window opens, so the lookup is not attributed to
|
|
174
142
|
// the act and cannot be mistaken for something the action caused.
|
|
175
143
|
const targetRef = await resolveActTarget(session, args);
|
|
176
|
-
if ('error' === targetRef.kind)
|
|
144
|
+
if ('error' === targetRef.kind) {
|
|
177
145
|
throw new Error(targetRef.message);
|
|
146
|
+
}
|
|
178
147
|
const since = session.elapsed();
|
|
179
148
|
// The act cursor + effect are marked only once the action has actually DISPATCHED (below, on
|
|
180
149
|
// each success path) — a refused act must leave nothing behind for the next observe to judge.
|
|
@@ -204,23 +173,23 @@ export const ACT_TOOLS = [
|
|
|
204
173
|
settled: real.settled,
|
|
205
174
|
settleReason: null,
|
|
206
175
|
result: leanActResult(real.result),
|
|
176
|
+
...hiddenTargetField(targetRef),
|
|
207
177
|
...healthEnvelope(session),
|
|
208
178
|
});
|
|
209
179
|
}
|
|
210
180
|
// actCommand is the single interception point: it rewrites upload+path args to real bytes
|
|
211
181
|
// before any ACT command crosses the bridge, covering this call site and all others.
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
args: args['args'] ?? {},
|
|
216
|
-
});
|
|
217
|
-
if (!result.ok)
|
|
182
|
+
const plain = { ref: targetRef.ref, action: args['action'], args: args['args'] ?? {} };
|
|
183
|
+
const result = await actCommand(deps, session, ReticleCommand.ACT, plain, undefined, true);
|
|
184
|
+
if (!result.ok) {
|
|
218
185
|
throw new Error(result.error ?? 'act failed');
|
|
186
|
+
}
|
|
219
187
|
captureAct(deps.recordings, args, result.result, routeBefore, session.id);
|
|
220
188
|
// lift dispatch/settle status to the envelope (a settle timeout is NOT a failure).
|
|
221
189
|
const r = asRecord(result.result);
|
|
222
|
-
if ('boolean' === typeof r['settled'])
|
|
190
|
+
if ('boolean' === typeof r['settled']) {
|
|
223
191
|
settledOutcome = r['settled'];
|
|
192
|
+
}
|
|
224
193
|
// Keep what only this call measured, so the observe that judges this window can ask whether
|
|
225
194
|
// anything happened INSIDE the target — the one fact that separates a dead control from a
|
|
226
195
|
// page that was merely busy with something else.
|
|
@@ -234,12 +203,13 @@ export const ACT_TOOLS = [
|
|
|
234
203
|
settled: r['settled'] ?? null,
|
|
235
204
|
settleReason: r['settleReason'] ?? null,
|
|
236
205
|
result: leanActResult(result.result),
|
|
206
|
+
...hiddenTargetField(targetRef),
|
|
237
207
|
...(true === real.fellBack ? { warning: ActionWarning.REAL_INPUT_FELL_BACK } : {}),
|
|
238
208
|
...healthEnvelope(session),
|
|
239
209
|
});
|
|
240
210
|
}
|
|
241
211
|
finally {
|
|
242
|
-
deps.recordings.markEnded(
|
|
212
|
+
deps.recordings.markEnded(pageOf(session.url), session.id);
|
|
243
213
|
// Close the window on every exit (settle or throw), recording the action + settle outcome.
|
|
244
214
|
session.finishAction(undefined, settledOutcome, true === settledOutcome ? session.elapsed() - since : undefined);
|
|
245
215
|
}
|
|
@@ -271,7 +241,7 @@ export const ACT_TOOLS = [
|
|
|
271
241
|
args: z
|
|
272
242
|
.record(z.string(), z.unknown())
|
|
273
243
|
.optional()
|
|
274
|
-
.describe('Action-specific arguments: { value } for fill/select (select also drives an ARIA combobox: it opens it and clicks the option by its label), { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut or a click (Meta/Control/Shift/Alt), { button: "right" | "middle" } for a click, { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { confirmDangerous: true } for a potentially destructive control. For upload: { path } is a path on disk (absolute or relative to project root; daemon reads real bytes) or { name, content?, type? } for inline bytes.'),
|
|
244
|
+
.describe('Action-specific arguments: { value } for fill/select (select also drives an ARIA combobox: it opens it and clicks the option by its label), { text } for type/press/insertText (the key NAME, e.g. Escape or Tab, for press/type — or the text to insert for insertText), { modifiers: ["Meta","Shift"] } for a press shortcut or a click (Meta/Control/Shift/Alt), { button: "right" | "middle" } for a click, { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { at: { x, y } } for click/dblclick/hover/tap/drag to act at a point of the element as fractions 0..1 of its box (a canvas has no child elements), { to: { x, y } } for drag to end at a point of the drop target (or of the source), { confirmDangerous: true } for a potentially destructive control. For upload: { path } is a path on disk (absolute or relative to project root; daemon reads real bytes) or { name, content?, type? } for inline bytes.'),
|
|
275
245
|
predicate: PredicateSchema.optional().describe('Alias for `until`.'),
|
|
276
246
|
until: PredicateSchema.optional().describe('Predicate to wait for after the action completes (same shape as reticle_assert). OMIT to wait for the page to SETTLE — network + DOM idle — the deterministic default instead of a sleep. To assert a consequence AND settle, allOf them: { kind: "allOf", predicates: [<your predicate>, { kind: "settled" }] }.'),
|
|
277
247
|
timeout_ms: timeoutMsSchema
|
|
@@ -287,6 +257,10 @@ export const ACT_TOOLS = [
|
|
|
287
257
|
},
|
|
288
258
|
outputSchema: {
|
|
289
259
|
durable: durableOutput,
|
|
260
|
+
budgetExtendedMs: z
|
|
261
|
+
.number()
|
|
262
|
+
.optional()
|
|
263
|
+
.describe("The re-ask on the successor ran on the caller's grace: a budget extension ON PURPOSE, taken only when the departure evidence showed the page navigating. Absent for every verdict that needed no follow."),
|
|
290
264
|
effect: z
|
|
291
265
|
.unknown()
|
|
292
266
|
.optional()
|
|
@@ -401,8 +375,9 @@ export const ACT_TOOLS = [
|
|
|
401
375
|
// BEFORE the action. A body clause this session cannot answer would fail whatever the app
|
|
402
376
|
// did, and on a drive that mutates state the action is not always repeatable. See #801(C).
|
|
403
377
|
const bodyRefusal = bodyClauseRefusal(until, session);
|
|
404
|
-
if (bodyRefusal !== undefined)
|
|
378
|
+
if (bodyRefusal !== undefined) {
|
|
405
379
|
throw new Error(bodyRefusal);
|
|
380
|
+
}
|
|
406
381
|
const timeout = asNumber(args['timeout_ms']) ?? DEFAULT_ASSERT_TIMEOUT_MS;
|
|
407
382
|
// An intent declared here lands in the ledger BEFORE the verdict is drawn, which is what makes
|
|
408
383
|
// the undeclared-change gap silent on THIS verdict rather than the next one: it reads the
|
|
@@ -415,8 +390,9 @@ export const ACT_TOOLS = [
|
|
|
415
390
|
// Resolve `target` to a ref BEFORE the action window opens, so the lookup is not attributed to
|
|
416
391
|
// the act and cannot be mistaken for something the action caused.
|
|
417
392
|
const resolved = await resolveActTarget(session, args);
|
|
418
|
-
if ('error' === resolved.kind)
|
|
393
|
+
if ('error' === resolved.kind) {
|
|
419
394
|
throw new Error(resolved.message);
|
|
395
|
+
}
|
|
420
396
|
let since = session.elapsed();
|
|
421
397
|
const actedSince = since;
|
|
422
398
|
// The cursor + effect are marked after the act dispatches (below) — a refused act leaves none.
|
|
@@ -431,10 +407,11 @@ export const ACT_TOOLS = [
|
|
|
431
407
|
// Was the consequence ALREADY TRUE, and what did that reading say? See act/already-true.ts.
|
|
432
408
|
const { alreadyTrue, alreadyTrueHiddenMatch, alreadyTrueEvidence, baselines } = await readAlreadyTrue(session, until, since);
|
|
433
409
|
// Same as the ACT handler: the route this step RAN on, before the action can move the app.
|
|
434
|
-
const routeBeforeWait =
|
|
435
|
-
// Recorded in `finally`, once the verdict is known — see captureVerdictedAct.
|
|
410
|
+
const routeBeforeWait = pageOf(session.url);
|
|
411
|
+
// Recorded in `finally`, once the verdict is known — see captureVerdictedAct. `held`: the
|
|
412
|
+
// action made the declared claim hold.
|
|
436
413
|
let dispatched;
|
|
437
|
-
let
|
|
414
|
+
let held = false;
|
|
438
415
|
try {
|
|
439
416
|
// actCommand is the single interception point for upload+path rewrite.
|
|
440
417
|
//
|
|
@@ -444,14 +421,15 @@ export const ACT_TOOLS = [
|
|
|
444
421
|
// returns null instead (see act-preflight.ts for why a write is never re-sent), and the
|
|
445
422
|
// successor block below then asks whether the consequence held on the NEW document — a
|
|
446
423
|
// green if it did, an honest observation_lost if it did not.
|
|
447
|
-
const actResult = await dispatchAct(() => actCommand(deps, session, {
|
|
424
|
+
const actResult = await dispatchAct(() => actCommand(deps, session, ReticleCommand.ACT, {
|
|
448
425
|
ref: resolved.ref,
|
|
449
426
|
action: args['action'],
|
|
450
427
|
args: confirmedByDeclaration(asRecord(args['args']), args['target'], untilNamed),
|
|
451
428
|
}));
|
|
452
429
|
if (actResult !== null) {
|
|
453
|
-
if (!actResult.ok)
|
|
430
|
+
if (!actResult.ok) {
|
|
454
431
|
throw new Error(actResult.error ?? 'act failed');
|
|
432
|
+
}
|
|
455
433
|
dispatched = { result: actResult.result };
|
|
456
434
|
// Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement
|
|
457
435
|
// also stops the spread below from inheriting an earlier reticle_act's action and
|
|
@@ -462,9 +440,7 @@ export const ACT_TOOLS = [
|
|
|
462
440
|
const predicateStarted = session.elapsed();
|
|
463
441
|
let verdict = null === actResult
|
|
464
442
|
? { pass: false, observationLost: true }
|
|
465
|
-
: timeout
|
|
466
|
-
? await waitForPredicate(session, until, timeout, since, baselines)
|
|
467
|
-
: await evaluatePredicate(session, until, since, true, baselines);
|
|
443
|
+
: await evaluateAfterAct(session, until, timeout, since, baselines);
|
|
468
444
|
// The SDK may have gone away mid-act — see act-observation.ts.
|
|
469
445
|
const followed = await followLostObservation({
|
|
470
446
|
sessions: deps.sessions,
|
|
@@ -472,22 +448,28 @@ export const ACT_TOOLS = [
|
|
|
472
448
|
verdict,
|
|
473
449
|
timeout,
|
|
474
450
|
predicateStarted,
|
|
451
|
+
since,
|
|
452
|
+
failedFollowGraceMs: NAVIGATION_FOLLOW_GRACE_MS,
|
|
475
453
|
reevaluate: (next, budget) => waitForPredicate(next, until, budget, 0, baselines),
|
|
476
454
|
});
|
|
477
|
-
if (followed.followed)
|
|
455
|
+
if (followed.followed) {
|
|
478
456
|
since = 0;
|
|
457
|
+
}
|
|
479
458
|
session = followed.session;
|
|
480
459
|
verdict = followed.verdict;
|
|
481
460
|
// After a match, let the app finish before the window closes — see act/after-match.ts.
|
|
482
461
|
if (verdict.pass && timeout > 0) {
|
|
483
462
|
const left = () => timeout - (session.elapsed() - predicateStarted);
|
|
484
463
|
const reverted = await finishAfterMatch(session, until, since, baselines, left);
|
|
485
|
-
if (reverted !== undefined)
|
|
464
|
+
if (reverted !== undefined) {
|
|
486
465
|
verdict = { pass: false, failureReason: reverted, observed: reverted };
|
|
466
|
+
}
|
|
467
|
+
verdict = await awaitShownMatch(session, until, since, baselines, verdict, left);
|
|
487
468
|
}
|
|
488
469
|
const r = asRecord(actResult?.result);
|
|
489
|
-
if ('boolean' === typeof r['settled'])
|
|
470
|
+
if ('boolean' === typeof r['settled']) {
|
|
490
471
|
settledOutcome = r['settled'];
|
|
472
|
+
}
|
|
491
473
|
// Where the acted element is written, captured at act time even if the action unmounted it.
|
|
492
474
|
const actedSource = sourceOf(r['source']);
|
|
493
475
|
// Remembered so a LATER assertion can name a file with no element to point at, and so the
|
|
@@ -505,6 +487,9 @@ export const ACT_TOOLS = [
|
|
|
505
487
|
// Read before the capsule, which needs it: a window the buffer trimmed cannot state an
|
|
506
488
|
// absolute about what did NOT happen. See CausalSummary.truncated.
|
|
507
489
|
const bufferLost = session.lostSince(since);
|
|
490
|
+
const impeachForLoss = bufferLost &&
|
|
491
|
+
(restsOnCompleteWindow(until) ||
|
|
492
|
+
(false === verdict.pass && failingClauseReadsLostChannel(until, windowEvents)));
|
|
508
493
|
const capsule = verdict.pass
|
|
509
494
|
? undefined
|
|
510
495
|
: buildDivergenceCapsule(links, windowEvents, bufferLost);
|
|
@@ -526,11 +511,13 @@ export const ACT_TOOLS = [
|
|
|
526
511
|
// stronger than this block. Grade from the strongest asserted consequence; integrity from evictions.
|
|
527
512
|
// Coverage: cross-origin frames / other blind spots the SDK reported during this window mean the
|
|
528
513
|
// verdict didn't see everything — say so, never imply full coverage.
|
|
529
|
-
const
|
|
514
|
+
const prior = since > 0 ? (await session.queryEvents({ since: 0 })).filter((e) => e.t < since) : [];
|
|
515
|
+
const canvas = canvasPaintSpots(windowEvents, { actionSince: since, prior });
|
|
516
|
+
const spots = [...blindSpotsFromState(session.blindSpots(), session.runtime), ...canvas];
|
|
530
517
|
// The window's own counts, so sampling before it is not described as this window's (#1414).
|
|
531
518
|
const windowSpots = blindSpotsFromState(session.blindSpots(since), session.runtime);
|
|
532
519
|
const coverage = buildCoverageStatement(spots, windowSpots);
|
|
533
|
-
const absenceBlindSpot = absenceBlindSpotNote(until, spots);
|
|
520
|
+
const absenceBlindSpot = absenceBlindSpotNote(until, spots, windowEvents);
|
|
534
521
|
// A green resting on hidden matches says the node exists, not that it shows (#1408).
|
|
535
522
|
const hiddenMatch = hiddenMatchNote(until, verdict.evidence);
|
|
536
523
|
// Nothing subscribed ⇒ the state channel is dark, and the summary must say so rather than
|
|
@@ -565,13 +552,7 @@ export const ACT_TOOLS = [
|
|
|
565
552
|
const honesty = buildHonestyBlock({
|
|
566
553
|
grade,
|
|
567
554
|
attribution: 'window',
|
|
568
|
-
|
|
569
|
-
// the action ran", which was the previous rule and which is true on essentially every live
|
|
570
|
-
// page. Age eviction retires everything past 60s on every push, and the churn floor is
|
|
571
|
-
// sacrificed on purpose; neither costs this verdict a single event it needed. In the
|
|
572
|
-
// field this made `unclean_capture` the dominant cause of `unknown`, reported for
|
|
573
|
-
// evictions that happened outside the window they impeached.
|
|
574
|
-
truncated: bufferLost,
|
|
555
|
+
truncated: impeachForLoss,
|
|
575
556
|
coveragePartial: Coverage.PARTIAL === coverage.coverage,
|
|
576
557
|
...(coverage.note === undefined ? {} : { coverageNote: coverage.note }),
|
|
577
558
|
// Settlement no longer vetoes a declared consequence that held, so the fact is carried
|
|
@@ -580,10 +561,9 @@ export const ACT_TOOLS = [
|
|
|
580
561
|
...(0 === impeachingNotes.length ? {} : { blindSpots: impeachingNotes }),
|
|
581
562
|
losses,
|
|
582
563
|
});
|
|
583
|
-
// A refuted
|
|
584
|
-
//
|
|
585
|
-
|
|
586
|
-
deps.recordings.unassertLast();
|
|
564
|
+
// A refuted or already-true claim stays off the ambient tape (the capsule below keeps a
|
|
565
|
+
// refuted one). See captureVerdictedAct.
|
|
566
|
+
held = verdict.pass && !alreadyTrue;
|
|
587
567
|
const capsuleSaved = await saveFailedAssertCapsule({
|
|
588
568
|
deps,
|
|
589
569
|
verdict,
|
|
@@ -608,8 +588,8 @@ export const ACT_TOOLS = [
|
|
|
608
588
|
// flagship path, and nothing said so: the finding was simply never produced.
|
|
609
589
|
//
|
|
610
590
|
// Learning material only. Attribution is unchanged — findings still come exclusively from
|
|
611
|
-
// `windowEvents`, exactly as on the assert path.
|
|
612
|
-
|
|
591
|
+
// `windowEvents`, exactly as on the assert path. It is read above, before coverage, because the
|
|
592
|
+
// canvas-paint spot (#1525) learns the last canvas digest from it too.
|
|
613
593
|
//
|
|
614
594
|
// `actionSince` is the window's own floor here, which is the tightest attribution there is —
|
|
615
595
|
// and it is what lets `duplicate-request` claim "one user action was performed" and mean it.
|
|
@@ -624,9 +604,10 @@ export const ACT_TOOLS = [
|
|
|
624
604
|
namedNetUrls: declared.netUrls,
|
|
625
605
|
repeatableNetUrls: declared.repeatableNetUrls,
|
|
626
606
|
// A consequence that was already true before the action proves nothing about it, so it is
|
|
627
|
-
// not evidence the destination rendered
|
|
628
|
-
|
|
607
|
+
// not evidence the destination rendered or the route moved — `alreadyTrue` decides that, once.
|
|
608
|
+
...provedConsequences(declared, verdict.pass && !alreadyTrue),
|
|
629
609
|
...session.lastAct.effect(),
|
|
610
|
+
...namedReactions(declared),
|
|
630
611
|
currentDocumentId: session.currentDocumentId,
|
|
631
612
|
currentEditEpoch: session.currentEditEpoch,
|
|
632
613
|
appOrigin: session.url,
|
|
@@ -644,8 +625,8 @@ export const ACT_TOOLS = [
|
|
|
644
625
|
});
|
|
645
626
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
646
627
|
const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
|
|
647
|
-
// A
|
|
648
|
-
const inconclusive =
|
|
628
|
+
// A timed-out read says why; a disabled or unreachable target cannot cause anything.
|
|
629
|
+
const inconclusive = actInconclusive(verdict, actResult?.result, session);
|
|
649
630
|
const { decision, durable } = await withDurability(args['durable'], until, decideVerified({
|
|
650
631
|
pass: verdict.pass,
|
|
651
632
|
// Threaded rather than looked up: decideVerified is pure and has no session.
|
|
@@ -685,13 +666,13 @@ export const ACT_TOOLS = [
|
|
|
685
666
|
unsettled: {
|
|
686
667
|
waitedFor: describeWaitTarget(until),
|
|
687
668
|
stillInFlight,
|
|
688
|
-
// The retry loop that leaves nothing outstanding — see repeatedRequestLabels.
|
|
689
669
|
repeated: repeatedRequestLabels(windowEvents),
|
|
690
670
|
},
|
|
691
671
|
...(namedNetIsInFlight(until, stillInFlight) ? { namedRequestInFlight: true } : {}),
|
|
672
|
+
...(impeachForLoss && false === verdict.pass ? { bufferLostEvidence: true } : {}),
|
|
673
|
+
...withDeclinedDialog(windowEvents),
|
|
692
674
|
}), (part) => reloadAndRecheck(deps, session, part, timeout));
|
|
693
|
-
|
|
694
|
-
noteProved(session, recordedVerdict, actResult?.result);
|
|
675
|
+
noteProved(session, String(decision.verified), actResult?.result);
|
|
695
676
|
// Computed once: the verdict block reports it, and the instrumentation gaps are a second
|
|
696
677
|
// reading of the same evidence rather than a new observation.
|
|
697
678
|
const actionSummary = causalSummary(windowEvents, {
|
|
@@ -785,6 +766,7 @@ export const ACT_TOOLS = [
|
|
|
785
766
|
// An unobserved act has no effect to report, and inventing an empty one would read as
|
|
786
767
|
// "the page did nothing" — a claim about the app, from a call that never saw it.
|
|
787
768
|
...(null === actResult ? {} : { effect: leanActResult(actResult.result) }),
|
|
769
|
+
...hiddenTargetField(resolved),
|
|
788
770
|
verdict,
|
|
789
771
|
// Promoted out of `effect` on red only. On green nobody needs it and it is noise; on red it
|
|
790
772
|
// is the first thing the agent wants, and burying a file:line inside the effect block is
|
|
@@ -827,15 +809,21 @@ export const ACT_TOOLS = [
|
|
|
827
809
|
// Without its summary: it is byte-identical to `summary` two fields up. See wireCapsule.
|
|
828
810
|
...(capsule === undefined ? {} : { capsule: wireCapsule(capsule) }),
|
|
829
811
|
...(0 === greenRadius.length ? {} : { blastRadius: greenRadius }),
|
|
812
|
+
// The re-ask on the successor ran on the caller's grace — a budget extension on purpose,
|
|
813
|
+
// declared so the agent can see the extra time it was given (#2009).
|
|
814
|
+
...(followed.budgetExtendedMs === undefined
|
|
815
|
+
? {}
|
|
816
|
+
: { budgetExtendedMs: followed.budgetExtendedMs }),
|
|
830
817
|
since,
|
|
831
818
|
...(session.id === actedSessionId ? {} : { sessionId: session.id }),
|
|
832
819
|
...healthEnvelope(currentOf(deps.sessions, session)),
|
|
833
820
|
});
|
|
834
821
|
}
|
|
835
822
|
finally {
|
|
836
|
-
if (dispatched !== undefined)
|
|
837
|
-
captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait,
|
|
838
|
-
|
|
823
|
+
if (dispatched !== undefined) {
|
|
824
|
+
captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, held, session.id, wroteSince(acted, actedSince));
|
|
825
|
+
}
|
|
826
|
+
deps.recordings.markEnded(pageOf(currentOf(deps.sessions, session).url), session.id);
|
|
839
827
|
acted.finishAction(verdictEffect, settledOutcome, true === settledOutcome ? acted.elapsed() - actedSince : undefined);
|
|
840
828
|
}
|
|
841
829
|
},
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const STALE_BUILD_NOTICE = "Reticle's code on disk changed after this daemon started, so it is still running the old build. Restart it (`npx @reticlehq/server restart`) and retry before trusting a fix to Reticle itself.";
|
|
1
|
+
export declare const STALE_BUILD_NOTICE = "Reticle's code on disk changed after this daemon started, so it is still running the old build. Restart it (`npx @reticlehq/server serve --restart`) and retry before trusting a fix to Reticle itself.";
|
|
2
2
|
/** Newest `.js` mtime under `dir`, or 0 when it cannot be read. */
|
|
3
3
|
export declare function newestJsMtime(dir: string): number;
|
|
4
4
|
/** A watcher over one directory, started now. Exported for tests; the daemon uses the default. */
|
|
@@ -14,7 +14,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
/** How often the walk may run. A few hundred stats, so cheap, but not on every call. */
|
|
16
16
|
const CHECK_EVERY_MS = 30_000;
|
|
17
|
-
export const STALE_BUILD_NOTICE = "Reticle's code on disk changed after this daemon started, so it is still running the old build. Restart it (`npx @reticlehq/server restart`) and retry before trusting a fix to Reticle itself.";
|
|
17
|
+
export const STALE_BUILD_NOTICE = "Reticle's code on disk changed after this daemon started, so it is still running the old build. Restart it (`npx @reticlehq/server serve --restart`) and retry before trusting a fix to Reticle itself.";
|
|
18
18
|
/** `dist/` of this package: this file sits at dist/surface/tools/agent/. */
|
|
19
19
|
const DIST_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
20
20
|
/** Newest `.js` mtime under `dir`, or 0 when it cannot be read. */
|
|
@@ -8,18 +8,19 @@ import { hiddenMatchNote } from '@reticlehq/engine/evidence/already-true.js';
|
|
|
8
8
|
import { provenExpectedLinks, } from '@reticlehq/engine/question/predicate/predicate.js';
|
|
9
9
|
import { findContradictions, } from '@reticlehq/engine/disagreement/contradictions.js';
|
|
10
10
|
import { crashedRuleNotes } from '@reticlehq/engine/disagreement/contradiction-folds.js';
|
|
11
|
-
import { declaredExpectations, declaresBodyIndependentChannel, } from '@reticlehq/engine/question/declared.js';
|
|
12
|
-
import { absenceBlindSpotNote, blindSpotsFromState, buildCoverageStatement, restsOnCompleteWindow, Coverage, impeachesCapture, transportGapNote, } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
11
|
+
import { declaredExpectations, declaresBodyIndependentChannel, provedConsequences, } from '@reticlehq/engine/question/declared.js';
|
|
12
|
+
import { absenceBlindSpotNote, blindSpotsFromState, buildCoverageStatement, failingClauseReadsLostChannel, restsOnCompleteWindow, Coverage, impeachesCapture, transportGapNote, } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
13
13
|
import { buildHonestyBlock } from '@reticlehq/engine/evidence/honesty.js';
|
|
14
14
|
import { acceptedWriteLabels, hasAcceptedWrite, } from '@reticlehq/engine/evidence/accepted-write.js';
|
|
15
15
|
import { unreadWriteLabels, unreadWriteReason } from '@reticlehq/engine/evidence/unread-outcome.js';
|
|
16
|
-
import { decideVerified } from '@reticlehq/engine/evidence/verified.js';
|
|
16
|
+
import { decideVerified, withDeclinedDialog } from '@reticlehq/engine/evidence/verified.js';
|
|
17
17
|
import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/evidence/unsettled.js';
|
|
18
18
|
import { inFlightRequestLabels, repeatedRequestLabels, } from '../act/settle-in-flight.js';
|
|
19
19
|
import { gradeOfPredicate } from './assert-grade.js';
|
|
20
20
|
import { assertSource, stampedSourceIn } from './assert-source.js';
|
|
21
21
|
import { VerdictAttribution, verdictAttributionOf } from '@reticlehq/core';
|
|
22
22
|
import { noteSourceSeen } from '../../../portal/session/recorded-gaps.js';
|
|
23
|
+
import { diagnoseTimeout } from '../act/act-observation.js';
|
|
23
24
|
/**
|
|
24
25
|
* The honesty verdict for a plain `reticle_assert`.
|
|
25
26
|
*
|
|
@@ -62,7 +63,6 @@ changeUndeclared) {
|
|
|
62
63
|
// The window's own counts, so sampling before it is not described as this window's (#1414).
|
|
63
64
|
const windowSpots = blindSpotsFromState(session.blindSpots(since), session.runtime);
|
|
64
65
|
const statement = buildCoverageStatement(spots, windowSpots);
|
|
65
|
-
const absenceBlindSpot = absenceBlindSpotNote(predicate, spots);
|
|
66
66
|
// A green resting on hidden matches says the node exists, not that it shows (#1408).
|
|
67
67
|
const hiddenMatch = hiddenMatchNote(predicate, evidence);
|
|
68
68
|
// Omitted entirely when coverage is full, so an intact page pays nothing and the field's PRESENCE
|
|
@@ -74,6 +74,8 @@ changeUndeclared) {
|
|
|
74
74
|
}
|
|
75
75
|
: {};
|
|
76
76
|
const windowEvents = await session.queryEvents({ since });
|
|
77
|
+
// The window lets a target the page was seen to remove escape the virtualized blind spot.
|
|
78
|
+
const absenceBlindSpot = absenceBlindSpotNote(predicate, spots, windowEvents);
|
|
77
79
|
// Everything before the window, passed as LEARNING material only. A scale error disagrees with a
|
|
78
80
|
// value the API stated earlier in the session, which an action-scoped window can never contain —
|
|
79
81
|
// measured live, `observe` over a wide window reported `unit-mismatch` while `assert` on the same
|
|
@@ -98,7 +100,7 @@ changeUndeclared) {
|
|
|
98
100
|
expectedFailures: declared.netFailures,
|
|
99
101
|
namedNetUrls: declared.netUrls,
|
|
100
102
|
repeatableNetUrls: declared.repeatableNetUrls,
|
|
101
|
-
|
|
103
|
+
...provedConsequences(declared, pass),
|
|
102
104
|
...(actCursor !== undefined && actCursor >= since ? { actionSince: actCursor } : {}),
|
|
103
105
|
});
|
|
104
106
|
// Only a spot that IMPEACHES the capture downgrades a general verdict. Structural boundaries are
|
|
@@ -138,7 +140,9 @@ changeUndeclared) {
|
|
|
138
140
|
});
|
|
139
141
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
140
142
|
const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
|
|
141
|
-
const
|
|
143
|
+
const rawInconclusive = inconclusive ?? (!pass ? session.preconditionFailure?.() : undefined);
|
|
144
|
+
// A timed-out page read is the one `unknown` whose cause and fix are knowable here (#1990).
|
|
145
|
+
const effectiveInconclusive = diagnoseTimeout(rawInconclusive, session);
|
|
142
146
|
/**
|
|
143
147
|
* Does a green here rest on the window having been COMPLETE?
|
|
144
148
|
*
|
|
@@ -153,13 +157,13 @@ changeUndeclared) {
|
|
|
153
157
|
/**
|
|
154
158
|
* The buffer evicted scarce evidence from this window.
|
|
155
159
|
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* its cursor is the action's own.
|
|
160
|
+
* Two cases. (1) An ABSENCE claim needs a complete window; things dropped are the disproof it
|
|
161
|
+
* cannot see. (2) A FAILING positive `allOf` whose NET/SIGNAL/LOG child has no evidence left in
|
|
162
|
+
* the window — the child might have failed because the buffer dropped the request, not because
|
|
163
|
+
* the app never made it (#1231). Only the second reads the events; the first is structural.
|
|
161
164
|
*/
|
|
162
|
-
const bufferLost = session.lostSince(since) &&
|
|
165
|
+
const bufferLost = session.lostSince(since) &&
|
|
166
|
+
(restsOnComplete || (false === pass && failingClauseReadsLostChannel(predicate, windowEvents)));
|
|
163
167
|
/** The durable ledger refused writes, on a query path that read from it. Same rule, other store. */
|
|
164
168
|
const ledgerLost = ledgerClosed && restsOnComplete;
|
|
165
169
|
const decision = decideVerified({
|
|
@@ -182,6 +186,8 @@ changeUndeclared) {
|
|
|
182
186
|
...(absenceBlindSpot === undefined ? {} : { absenceBlindSpot }),
|
|
183
187
|
...(hiddenMatch === undefined ? {} : { hiddenMatch }),
|
|
184
188
|
...(namedNetIsInFlight(predicate, stillInFlight) ? { namedRequestInFlight: true } : {}),
|
|
189
|
+
...(bufferLost && false === pass ? { bufferLostEvidence: true } : {}),
|
|
190
|
+
...withDeclinedDialog(windowEvents),
|
|
185
191
|
honesty: buildHonestyBlock({
|
|
186
192
|
grade: gradeOfPredicate(predicate),
|
|
187
193
|
attribution: 'window',
|