@reticlehq/server 3.2.0 → 3.4.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-ENTERPRISE +1 -1
- package/README.md +3 -3
- package/SKILL.md +23 -22
- package/dist/chromium-launch-options.d.ts +4 -3
- package/dist/chromium-launch-options.js +6 -2
- package/dist/command/cli/adhoc-suite.d.ts +41 -0
- package/dist/command/cli/adhoc-suite.js +159 -0
- package/dist/command/cli/adhoc-verdict.d.ts +58 -2
- package/dist/command/cli/adhoc-verdict.js +108 -13
- package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
- package/dist/command/cli/answers/gate-hook-message.js +6 -0
- package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
- package/dist/command/cli/auth/cloud-keystore.js +0 -3
- package/dist/command/cli/auth/cloud-session.d.ts +4 -0
- package/dist/command/cli/auth/cloud-session.js +2 -0
- package/dist/command/cli/cli-doctor.js +30 -8
- package/dist/command/cli/cli-flow-commands.d.ts +3 -6
- package/dist/command/cli/cli-flow-commands.js +67 -4
- package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
- package/dist/command/cli/cli-parse-grammar.js +7 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -5
- package/dist/command/cli/cli-parse-verify.js +86 -13
- package/dist/command/cli/cli-parse.d.ts +14 -1
- package/dist/command/cli/cli-parse.js +54 -8
- package/dist/command/cli/cli-update-commands.js +8 -1
- package/dist/command/cli/cli-verify.d.ts +80 -0
- package/dist/command/cli/cli-verify.js +181 -26
- package/dist/command/cli/cloud-cli.js +5 -2
- package/dist/command/cli/cloud-kit.d.ts +0 -2
- package/dist/command/cli/cloud-kit.js +3 -5
- package/dist/command/cli/cloud-login.js +21 -3
- package/dist/command/cli/demo/demo-page.js +6 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
- package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
- package/dist/command/cli/launch/cli-launch.d.ts +9 -29
- package/dist/command/cli/launch/cli-launch.js +27 -49
- package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
- package/dist/command/cli/launch/sdk-version-match.js +206 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
- package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
- package/dist/command/cli/ports/resolve/cli-port.js +169 -15
- package/dist/command/cli/report-command.d.ts +16 -0
- package/dist/command/cli/report-command.js +97 -0
- package/dist/command/cli/setup-mcp-cli.js +13 -13
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +21 -7
- package/dist/command/cli.js +67 -10
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
- package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
- package/dist/command/daemon/binding/port-presence.d.ts +1 -1
- package/dist/command/daemon/daemon-resolve.d.ts +9 -0
- package/dist/command/daemon/daemon-resolve.js +1 -1
- package/dist/command/daemon/idle-shutdown.d.ts +2 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
- package/dist/command/dev/stale-issue-guard.d.ts +3 -4
- package/dist/command/dev/stale-issue-guard.js +8 -8
- package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
- package/dist/command/setup/bringup/connect-lease.js +38 -0
- package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
- package/dist/command/setup/bringup/dev-server-files.js +131 -0
- package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
- package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
- package/dist/command/setup/bringup/ensure-daemon.js +135 -16
- package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
- package/dist/command/setup/bringup/static-page-server.js +151 -0
- package/dist/command/setup/desktop-shape.d.ts +4 -0
- package/dist/command/setup/desktop-shape.js +18 -2
- package/dist/command/setup/init/init-host.js +8 -0
- package/dist/command/setup/init/init-port.d.ts +15 -0
- package/dist/command/setup/init/init-port.js +44 -0
- package/dist/command/setup/init/init-runtime.d.ts +1 -1
- package/dist/command/setup/init/init-runtime.js +39 -2
- package/dist/command/setup/node-effects.d.ts +27 -14
- package/dist/command/setup/node-effects.js +80 -44
- package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
- package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
- package/dist/command/setup/probe/page-probe.d.ts +13 -2
- package/dist/command/setup/probe/page-probe.js +18 -3
- package/dist/command/setup/run-setup.d.ts +26 -1
- package/dist/command/setup/run-setup.js +96 -13
- package/dist/command/setup/session-pick.d.ts +13 -0
- package/dist/command/setup/session-pick.js +20 -0
- package/dist/command/setup/setup-command.d.ts +2 -14
- package/dist/command/setup/setup-command.js +105 -31
- package/dist/command/setup/setup-mcp.js +3 -3
- package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
- package/dist/command/setup/terminal/wait-progress.js +17 -0
- package/dist/features/crawl/crawl-empty.js +1 -1
- package/dist/features/crawl/crawl-tools.d.ts +6 -0
- package/dist/features/crawl/crawl-tools.js +57 -0
- package/dist/features/crawl/crawl.d.ts +2 -0
- package/dist/features/crawl/crawl.js +171 -156
- package/dist/features/exhaust/app-coverage.d.ts +33 -0
- package/dist/features/exhaust/app-coverage.js +31 -0
- package/dist/features/exhaust/code-coverage.d.ts +47 -0
- package/dist/features/exhaust/code-coverage.js +77 -0
- package/dist/features/exhaust/exhaust-run.d.ts +33 -0
- package/dist/features/exhaust/exhaust-run.js +82 -0
- package/dist/features/exhaust/explorer.d.ts +103 -0
- package/dist/features/exhaust/explorer.js +195 -0
- package/dist/features/exhaust/failure-branches.d.ts +33 -0
- package/dist/features/exhaust/failure-branches.js +92 -0
- package/dist/features/exhaust/ledger.d.ts +202 -0
- package/dist/features/exhaust/ledger.js +252 -0
- package/dist/features/exhaust/session-fold.d.ts +31 -0
- package/dist/features/exhaust/session-fold.js +79 -0
- package/dist/features/exhaust/session-port.d.ts +36 -0
- package/dist/features/exhaust/session-port.js +102 -0
- package/dist/features/harness/drive-report.d.ts +0 -9
- package/dist/features/harness/drive-report.js +18 -0
- package/dist/features/harness/driver.js +4 -7
- package/dist/features/harness/fill-values.d.ts +6 -0
- package/dist/features/harness/fill-values.js +3 -0
- package/dist/features/harness/jev-driver.js +36 -22
- package/dist/features/harness/openai-driver.js +4 -7
- package/dist/features/harness/platform-config.d.ts +10 -0
- package/dist/features/harness/platform-config.js +13 -6
- package/dist/index.d.ts +10 -1
- package/dist/index.js +78 -104
- package/dist/judgement/capsule/capsule-store.d.ts +31 -2
- package/dist/judgement/capsule/capsule-store.js +58 -6
- package/dist/judgement/capsule/capsule.js +5 -0
- package/dist/judgement/capsule/causal-summary.d.ts +13 -1
- package/dist/judgement/capsule/causal-summary.js +7 -0
- package/dist/judgement/domain/domain-model.js +40 -9
- package/dist/judgement/oracles/self-instrument.js +4 -2
- package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
- package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
- package/dist/judgement/runs/artifact/gap-report.js +46 -0
- package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
- package/dist/judgement/runs/artifact/gap-summary.js +85 -0
- package/dist/judgement/runs/artifact/render-report.js +4 -1
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
- package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
- package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
- package/dist/judgement/runs/artifact/to-artifact.js +1 -1
- package/dist/judgement/runs/context-tools.js +21 -3
- package/dist/judgement/runs/drive-run.js +7 -2
- package/dist/judgement/runs/verification-sync.d.ts +3 -1
- package/dist/judgement/runs/verification-sync.js +1 -1
- package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
- package/dist/language/flows/annotate-notes/annotate.js +66 -18
- package/dist/language/flows/change/affected.d.ts +9 -0
- package/dist/language/flows/change/affected.js +35 -0
- package/dist/language/flows/change/gate.d.ts +20 -0
- package/dist/language/flows/change/gate.js +12 -1
- package/dist/language/flows/flow-anchor.d.ts +12 -0
- package/dist/language/flows/flow-anchor.js +20 -0
- package/dist/language/flows/flow-author.d.ts +7 -0
- package/dist/language/flows/flow-author.js +19 -0
- package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
- package/dist/language/flows/flow-expect-grammar.js +92 -11
- package/dist/language/flows/flow-intent.js +1 -1
- package/dist/language/flows/flow-journey.d.ts +54 -0
- package/dist/language/flows/flow-journey.js +119 -0
- package/dist/language/flows/flow-learning.d.ts +3 -0
- package/dist/language/flows/flow-learning.js +39 -8
- package/dist/language/flows/flow-replay-run.d.ts +33 -12
- package/dist/language/flows/flow-replay-run.js +131 -52
- package/dist/language/flows/flow-replay-types.d.ts +9 -0
- package/dist/language/flows/flow-replay.d.ts +27 -12
- package/dist/language/flows/flow-replay.js +127 -111
- package/dist/language/flows/flow-result.d.ts +2 -0
- package/dist/language/flows/flow-result.js +25 -0
- package/dist/language/flows/flow-step-runners.d.ts +26 -10
- package/dist/language/flows/flow-step-runners.js +20 -4
- package/dist/language/flows/flow-success.d.ts +21 -6
- package/dist/language/flows/flow-success.js +50 -138
- package/dist/language/flows/flow-tools.js +17 -5
- package/dist/language/flows/flows.d.ts +18 -5
- package/dist/language/flows/flows.js +101 -16
- package/dist/language/flows/heal.d.ts +9 -1
- package/dist/language/flows/heal.js +24 -2
- package/dist/language/flows/learned-sources.d.ts +21 -0
- package/dist/language/flows/learned-sources.js +84 -0
- package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
- package/dist/language/flows/recording/recording-backtrack.js +1 -1
- package/dist/language/flows/recording/replay-halt.d.ts +2 -1
- package/dist/language/flows/recording/replay-halt.js +3 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
- package/dist/language/flows/recording/tape/recordings.js +55 -1
- package/dist/language/flows/replay.d.ts +19 -0
- package/dist/language/flows/replay.js +53 -13
- package/dist/language/flows/stores/annotation-store.d.ts +5 -5
- package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
- package/dist/language/flows/stores/flake-store.js +2 -3
- package/dist/language/flows/suite/coverage.d.ts +1 -1
- package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
- package/dist/language/flows/verify-change-tools.js +19 -2
- package/dist/launch-chromium.d.ts +80 -0
- package/dist/launch-chromium.js +218 -0
- package/dist/memory/cloud/cloud-config.d.ts +11 -2
- package/dist/memory/cloud/cloud-config.js +47 -7
- package/dist/memory/cloud/cloud-sync.d.ts +4 -3
- package/dist/memory/cloud/cloud-sync.js +7 -10
- package/dist/memory/cloud/harness-config.d.ts +2 -0
- package/dist/memory/cloud/harness-offer.js +5 -6
- package/dist/memory/cloud/harness-switch.js +5 -6
- package/dist/memory/cloud/sync-cycle.d.ts +78 -1
- package/dist/memory/cloud/sync-cycle.js +321 -53
- package/dist/memory/cloud/sync-daemon.d.ts +13 -0
- package/dist/memory/cloud/sync-daemon.js +45 -20
- package/dist/memory/cloud/sync-disk.js +27 -8
- package/dist/memory/impact/impact-store.js +6 -0
- package/dist/memory/intent/inline-intent.js +8 -3
- package/dist/memory/intent/intent-shard-store.d.ts +33 -47
- package/dist/memory/intent/intent-shard-store.js +252 -140
- package/dist/memory/intent/intent-shard.d.ts +0 -23
- package/dist/memory/intent/intent-shard.js +1 -11
- package/dist/memory/intent/intent-store.d.ts +13 -8
- package/dist/memory/intent/intent-store.js +46 -90
- package/dist/memory/intent/intent-tools.js +34 -23
- package/dist/memory/journal/ambient-store.js +2 -3
- package/dist/memory/journal/deviation-report.js +4 -1
- package/dist/memory/journal/deviation-service.js +10 -2
- package/dist/memory/journal/drive-flow.d.ts +19 -14
- package/dist/memory/journal/drive-flow.js +65 -48
- package/dist/memory/journal/envelope-store.js +2 -3
- package/dist/memory/journal/journal-recorder.d.ts +21 -0
- package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
- package/dist/memory/journal/on-disk/retain-policy.js +44 -0
- package/dist/memory/journal/on-disk/retention.d.ts +14 -10
- package/dist/memory/journal/on-disk/retention.js +13 -12
- package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
- package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
- package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
- package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
- package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
- package/dist/memory/journal/route-template.d.ts +22 -0
- package/dist/memory/journal/route-template.js +44 -0
- package/dist/memory/journal/session-end.d.ts +13 -2
- package/dist/memory/journal/session-end.js +88 -18
- package/dist/memory/journal/session-journal.d.ts +8 -1
- package/dist/memory/journal/session-journal.js +10 -0
- package/dist/memory/project/baselines.d.ts +1 -1
- package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
- package/dist/memory/project/dir/reticle-dir.js +1 -0
- package/dist/memory/project/fs/fs-port.js +44 -5
- package/dist/memory/project/fs/write-atomic.d.ts +26 -0
- package/dist/memory/project/fs/write-atomic.js +48 -0
- package/dist/memory/project/project-tools.js +3 -1
- package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
- package/dist/memory/recall/prior/connection-memory.js +8 -0
- package/dist/memory/recall/registered-projects.d.ts +2 -1
- package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
- package/dist/portal/bridge/auth-failure-reason.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +8 -0
- package/dist/portal/bridge/bridge.js +43 -2
- package/dist/portal/input/js-coverage.d.ts +25 -0
- package/dist/portal/input/js-coverage.js +30 -0
- package/dist/portal/input/real-input.d.ts +11 -0
- package/dist/portal/input/real-input.js +31 -5
- package/dist/portal/pool/browser-pool.d.ts +10 -0
- package/dist/portal/pool/browser-pool.js +10 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +21 -13
- package/dist/portal/pool/pool-contract.d.ts +2 -0
- package/dist/portal/pool/storage-seed.d.ts +2 -1
- package/dist/portal/pool/zero-install.d.ts +27 -0
- package/dist/portal/pool/zero-install.js +54 -0
- package/dist/portal/realm/web-realm.js +6 -0
- package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
- package/dist/portal/session/dev-server/dev-command.js +30 -12
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
- package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
- package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
- package/dist/portal/session/dev-server/route-status-probe.js +57 -0
- package/dist/portal/session/dev-server/served-document.d.ts +21 -0
- package/dist/portal/session/dev-server/served-document.js +57 -0
- package/dist/portal/session/facts/background-traffic.d.ts +9 -0
- package/dist/portal/session/facts/background-traffic.js +25 -0
- package/dist/portal/session/facts/observed-state.d.ts +11 -0
- package/dist/portal/session/facts/observed-state.js +34 -0
- package/dist/portal/session/live-control-tools.js +48 -3
- package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
- package/dist/portal/session/no-session-diagnosis.js +62 -5
- package/dist/portal/session/no-session-next-action.d.ts +13 -0
- package/dist/portal/session/no-session-next-action.js +48 -9
- package/dist/portal/session/no-session-watch.d.ts +18 -0
- package/dist/portal/session/no-session-watch.js +88 -2
- package/dist/portal/session/presence/attachment-history.d.ts +13 -2
- package/dist/portal/session/session-health.d.ts +61 -0
- package/dist/portal/session/session-health.js +43 -3
- package/dist/portal/session/session-info.d.ts +6 -0
- package/dist/portal/session/session-manager.d.ts +29 -6
- package/dist/portal/session/session-manager.js +42 -5
- package/dist/portal/session/session-reaper.d.ts +28 -0
- package/dist/portal/session/session-reaper.js +49 -1
- package/dist/portal/session/session-successor.d.ts +11 -0
- package/dist/portal/session/session-successor.js +14 -1
- package/dist/portal/session/session-verdict-facts.d.ts +28 -0
- package/dist/portal/session/session-verdict-facts.js +15 -0
- package/dist/portal/session/session.d.ts +10 -0
- package/dist/portal/session/session.js +34 -26
- package/dist/surface/http-server.d.ts +2 -1
- package/dist/surface/http-server.js +4 -2
- package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
- package/dist/surface/mcp/mcp-proxy.js +5 -5
- package/dist/surface/mcp/mcp.js +4 -2
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
- package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
- package/dist/surface/mcp/server-instructions.js +21 -8
- package/dist/surface/tools/act/after-match.d.ts +17 -0
- package/dist/surface/tools/act/after-match.js +30 -0
- package/dist/surface/tools/act/already-true.d.ts +40 -0
- package/dist/surface/tools/act/already-true.js +36 -0
- package/dist/surface/tools/act/durable.d.ts +69 -0
- package/dist/surface/tools/act/durable.js +139 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
- package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
- package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
- package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
- package/dist/surface/tools/act/proved-controls.d.ts +9 -0
- package/dist/surface/tools/act/proved-controls.js +11 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
- package/dist/surface/tools/act/sequence-grade.js +32 -1
- package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
- package/dist/surface/tools/act/settle-in-flight.js +29 -6
- package/dist/surface/tools/act-capsule.d.ts +7 -0
- package/dist/surface/tools/act-capsule.js +68 -8
- package/dist/surface/tools/act-sequence-tool.js +25 -8
- package/dist/surface/tools/act-tools.js +51 -74
- package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
- package/dist/surface/tools/args/numeric-bounds.js +30 -3
- package/dist/surface/tools/assert/assert-grade.js +26 -3
- package/dist/surface/tools/assert/assert-verdict.js +32 -6
- package/dist/surface/tools/browser-tools.js +17 -4
- package/dist/surface/tools/coverage-tools.js +27 -1
- package/dist/surface/tools/dynamic-tools.js +6 -0
- package/dist/surface/tools/error-recovery.js +4 -4
- package/dist/surface/tools/feedback-invite.js +6 -4
- package/dist/surface/tools/feedback-tools.d.ts +2 -1
- package/dist/surface/tools/feedback-tools.js +1 -1
- package/dist/surface/tools/harness-explore.d.ts +3 -2
- package/dist/surface/tools/harness-explore.js +7 -6
- package/dist/surface/tools/invoke-tool.js +17 -4
- package/dist/surface/tools/lease-hint.d.ts +8 -0
- package/dist/surface/tools/lease-hint.js +10 -0
- package/dist/surface/tools/lease-tools.d.ts +16 -28
- package/dist/surface/tools/lease-tools.js +68 -11
- package/dist/surface/tools/lineage-tools.js +1 -1
- package/dist/surface/tools/live-call-text.js +4 -1
- package/dist/surface/tools/observe-tools.js +23 -7
- package/dist/surface/tools/real-input-attempt.d.ts +0 -5
- package/dist/surface/tools/real-input-attempt.js +1 -1
- package/dist/surface/tools/tool-kit.d.ts +5 -0
- package/dist/surface/tools/tool-kit.js +6 -1
- package/dist/surface/tools/tool-surface.js +17 -5
- package/dist/surface/tools/tools.js +68 -29
- package/dist/telemetry/argument-shape.d.ts +0 -2
- package/dist/telemetry/argument-shape.js +0 -4
- package/dist/telemetry/error-class.d.ts +2 -3
- package/dist/telemetry/error-class.js +2 -3
- package/dist/telemetry/feedback-local.d.ts +1 -0
- package/dist/telemetry/feedback-local.js +1 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/harness-drive.d.ts +0 -2
- package/dist/telemetry/harness-drive.js +0 -4
- package/dist/telemetry/hud-metrics.d.ts +32 -0
- package/dist/telemetry/hud-metrics.js +95 -0
- package/dist/telemetry/session-metrics.d.ts +5 -0
- package/dist/telemetry/session-metrics.js +15 -1
- package/dist/wire-journal.d.ts +34 -0
- package/dist/wire-journal.js +104 -0
- package/dist/workspace-packages.d.ts +0 -2
- package/dist/workspace-packages.js +1 -9
- package/docs/README.md +5 -2
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +4 -4
- package/docs/architecture.md +6 -6
- package/docs/best-practices.mdx +1 -1
- package/docs/capabilities.mdx +32 -1
- package/docs/cli/cloud.mdx +21 -9
- package/docs/cli/doctor.mdx +4 -0
- package/docs/cli/feedback.mdx +2 -2
- package/docs/cli/gate.mdx +9 -4
- package/docs/cli/init.mdx +1 -0
- package/docs/cli/report.mdx +44 -0
- package/docs/cli/update.mdx +10 -0
- package/docs/cli.mdx +9 -0
- package/docs/desktop.mdx +14 -10
- package/docs/environment.mdx +87 -0
- package/docs/faq.mdx +18 -16
- package/docs/first-drive.md +5 -13
- package/docs/flows.md +32 -2
- package/docs/frameworks.mdx +140 -9
- package/docs/getting-started.md +3 -3
- package/docs/http-transport.md +6 -3
- package/docs/human-control.md +2 -2
- package/docs/index.mdx +16 -6
- package/docs/install-agentic.mdx +37 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/integration-patterns.md +3 -3
- package/docs/multi-agent-testing.md +1 -1
- package/docs/packages/babel-plugin.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/react.mdx +2 -2
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/vite-plugin.mdx +2 -2
- package/docs/packages.mdx +9 -9
- package/docs/predicates.mdx +176 -7
- package/docs/quickstart.mdx +2 -2
- package/docs/recipes.mdx +2 -2
- package/docs/state-management.mdx +2 -2
- package/docs/system-map.md +1 -1
- package/docs/telemetry.md +1 -1
- package/docs/token-efficiency.md +3 -3
- package/docs/tools/act-and-wait.mdx +1 -0
- package/docs/tools/act-sequence.mdx +1 -1
- package/docs/tools/console.mdx +1 -1
- package/docs/tools/inspect.mdx +1 -1
- package/docs/tools/network.mdx +1 -1
- package/docs/tools/query.mdx +11 -11
- package/docs/tools/sessions.mdx +1 -1
- package/docs/tools/snapshot.mdx +1 -1
- package/docs/tools/state.mdx +1 -1
- package/docs/tools/wait-for.mdx +1 -1
- package/docs/usage.md +8 -7
- package/docs/use-cases.mdx +157 -0
- package/docs/vs-screenshots.mdx +3 -3
- package/docs/what-is-recorded.md +62 -0
- package/docs/what-is-reticle.mdx +17 -20
- package/docs/why-reticle.mdx +14 -21
- package/package.json +11 -10
- package/dist/judgement/capsule/minimize.d.ts +0 -12
- package/dist/judgement/capsule/minimize.js +0 -22
- package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
- package/dist/judgement/outcome/predicate-to-expect.js +0 -148
- package/dist/judgement/phenomena/phenomena.d.ts +0 -26
- package/dist/judgement/phenomena/phenomena.js +0 -101
- package/dist/language/flows/flow-report.d.ts +0 -22
- package/dist/language/flows/flow-report.js +0 -106
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Pure: no IO, no clock. The tool layer loads flows + contract and calls this.
|
|
14
14
|
*/
|
|
15
|
-
import { AnchorKind, } from '@reticlehq/core';
|
|
15
|
+
import { AnchorKind, PredicateKind, compareSourceClauses, } from '@reticlehq/core';
|
|
16
16
|
import { classifyFlowAssertions, FlowAssertionGrade } from '../../language/flows/flow-classify.js';
|
|
17
17
|
import { successLabel } from '../../language/flows/flow-success.js';
|
|
18
18
|
import { flowRisk, latestRun, rankByRisk, RiskLevel } from './flow-risk.js';
|
|
@@ -25,16 +25,47 @@ function flatten(steps) {
|
|
|
25
25
|
}
|
|
26
26
|
return out;
|
|
27
27
|
}
|
|
28
|
+
/*
|
|
29
|
+
* The vocabulary a flow uses, read out of a predicate TREE.
|
|
30
|
+
*
|
|
31
|
+
* These were property reads when `expect` was a struct with one slot per kind. A predicate nests, and
|
|
32
|
+
* the domain model is about what a flow TALKS ABOUT, so the walk goes all the way down: a signal
|
|
33
|
+
* named inside an `allOf` two levels deep is still a signal this flow depends on, and missing it
|
|
34
|
+
* would quietly shrink the model that decides which flows a change affects.
|
|
35
|
+
*/
|
|
36
|
+
function walkClauses(predicate) {
|
|
37
|
+
if (predicate === undefined)
|
|
38
|
+
return [];
|
|
39
|
+
if (PredicateKind.ALL_OF === predicate.kind || PredicateKind.ANY_OF === predicate.kind) {
|
|
40
|
+
return predicate.predicates.flatMap(walkClauses);
|
|
41
|
+
}
|
|
42
|
+
if (PredicateKind.NOT === predicate.kind)
|
|
43
|
+
return walkClauses(predicate.predicate);
|
|
44
|
+
if (PredicateKind.COMPARE === predicate.kind)
|
|
45
|
+
return compareSourceClauses(predicate);
|
|
46
|
+
return [predicate];
|
|
47
|
+
}
|
|
48
|
+
function signalNamesIn(predicate) {
|
|
49
|
+
return walkClauses(predicate)
|
|
50
|
+
.filter((c) => PredicateKind.SIGNAL === c.kind)
|
|
51
|
+
.map((c) => (PredicateKind.SIGNAL === c.kind ? c.name : undefined))
|
|
52
|
+
.filter((name) => name !== undefined);
|
|
53
|
+
}
|
|
54
|
+
function elementTestidsIn(predicate) {
|
|
55
|
+
return walkClauses(predicate)
|
|
56
|
+
.map((c) => (PredicateKind.ELEMENT === c.kind ? c.query.testid : undefined))
|
|
57
|
+
.filter((testid) => testid !== undefined);
|
|
58
|
+
}
|
|
28
59
|
function flowSignals(flow) {
|
|
29
60
|
const set = new Set();
|
|
30
61
|
for (const step of flatten(flow.steps)) {
|
|
31
62
|
if (step.anchor.kind === AnchorKind.SIGNAL)
|
|
32
63
|
set.add(step.anchor.name);
|
|
33
|
-
|
|
34
|
-
set.add(
|
|
64
|
+
for (const name of signalNamesIn(step.expect))
|
|
65
|
+
set.add(name);
|
|
35
66
|
}
|
|
36
|
-
|
|
37
|
-
set.add(
|
|
67
|
+
for (const name of signalNamesIn(flow.success))
|
|
68
|
+
set.add(name);
|
|
38
69
|
return [...set];
|
|
39
70
|
}
|
|
40
71
|
function flowTestids(flow) {
|
|
@@ -42,11 +73,11 @@ function flowTestids(flow) {
|
|
|
42
73
|
for (const step of flatten(flow.steps)) {
|
|
43
74
|
if (step.anchor.kind === AnchorKind.TESTID)
|
|
44
75
|
set.add(step.anchor.value);
|
|
45
|
-
|
|
46
|
-
set.add(
|
|
76
|
+
for (const testid of elementTestidsIn(step.expect))
|
|
77
|
+
set.add(testid);
|
|
47
78
|
}
|
|
48
|
-
|
|
49
|
-
set.add(
|
|
79
|
+
for (const testid of elementTestidsIn(flow.success))
|
|
80
|
+
set.add(testid);
|
|
50
81
|
return [...set];
|
|
51
82
|
}
|
|
52
83
|
const EMPTY_CONTRACT = { testids: [], signals: [], stores: [], flows: [] };
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* `missing-signal` while honesty said `no-signal-on-mutation` for the same absence.
|
|
10
10
|
*/
|
|
11
11
|
import { InstrumentationGapKind } from '@reticlehq/core/artifacts';
|
|
12
|
-
/** PascalCase a store name for a `useX
|
|
12
|
+
/** PascalCase a store name for a `useX` hint (cart → Cart). */
|
|
13
13
|
function pascal(name) {
|
|
14
14
|
return 0 === name.length ? name : name[0]?.toUpperCase() + name.slice(1);
|
|
15
15
|
}
|
|
@@ -18,7 +18,9 @@ function insertFor(gap) {
|
|
|
18
18
|
case InstrumentationGapKind.NO_SIGNAL_ON_MUTATION:
|
|
19
19
|
return `reticle.signal('${gap.name}');`;
|
|
20
20
|
case InstrumentationGapKind.NO_STORE_REGISTERED:
|
|
21
|
-
|
|
21
|
+
// The store itself, so its subscribe is wired too. A `() => useX.getState()` getter is
|
|
22
|
+
// readable but never reports a change, which is the state this gap is about (#1146).
|
|
23
|
+
return `registerStore('${gap.name}', use${pascal(gap.name)});`;
|
|
22
24
|
case InstrumentationGapKind.MISSING_TESTID:
|
|
23
25
|
return `data-testid="${gap.name}"`;
|
|
24
26
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Predicate } from '@reticlehq/core';
|
|
2
2
|
/**
|
|
3
3
|
* Anti-reward-hacking (research-mandated). Test-gated agents pass gates by WEAKENING assertions — the
|
|
4
4
|
* canonical documented failure. Flows are git-checked and agent-editable, so a mustHold that dropped
|
|
@@ -7,10 +7,10 @@ import { type FlowExpect } from '@reticlehq/core';
|
|
|
7
7
|
* and flow_verify surface it.
|
|
8
8
|
*/
|
|
9
9
|
/** True when `after` weakened `before` — a real consequence became a fakeable presence-only check. */
|
|
10
|
-
export declare function isAssertionDowngrade(before:
|
|
10
|
+
export declare function isAssertionDowngrade(before: Predicate | undefined, after: Predicate | undefined): boolean;
|
|
11
11
|
export interface StepExpect {
|
|
12
12
|
step: number;
|
|
13
|
-
expect?:
|
|
13
|
+
expect?: Predicate;
|
|
14
14
|
}
|
|
15
15
|
interface DowngradeFinding {
|
|
16
16
|
step: number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The session gap, as a person reads it — and as a Stop hook prints it.
|
|
3
|
+
*
|
|
4
|
+
* `gapSummary` folds the journal into what was claimed and what held. This is its only renderer, so
|
|
5
|
+
* `reticle report` and the hook cannot describe the same session two different ways.
|
|
6
|
+
*/
|
|
7
|
+
import type { GapSummary } from './gap-summary.js';
|
|
8
|
+
/**
|
|
9
|
+
* One line when the agent finishes without a single `yes`, and nothing otherwise.
|
|
10
|
+
*
|
|
11
|
+
* Silent after a `yes` on purpose: a hook that speaks on every stop is a hook people turn off, and the
|
|
12
|
+
* question it exists to raise is "did anything get proved at all". Every answer that is not a yes is
|
|
13
|
+
* counted by name — an `unknown` is never folded into anything, because that fold is the false green.
|
|
14
|
+
*/
|
|
15
|
+
export declare function gapHookLine(gap: GapSummary): string | undefined;
|
|
16
|
+
/** The whole gap: held of claimed first, then each kind of not-held with who can act on it. */
|
|
17
|
+
export declare function gapReportLines(gap: GapSummary): string[];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const HOOK_PREFIX = 'Reticle: not verified.';
|
|
2
|
+
const NO_CLAIM_HOOK = `${HOOK_PREFIX} No claim was checked this session`;
|
|
3
|
+
const NO_CLAIM_REPORT = 'no claims this session, so nothing was verified';
|
|
4
|
+
const plural = (n, word) => `${String(n)} ${word}${1 === n ? '' : 's'}`;
|
|
5
|
+
/**
|
|
6
|
+
* One line when the agent finishes without a single `yes`, and nothing otherwise.
|
|
7
|
+
*
|
|
8
|
+
* Silent after a `yes` on purpose: a hook that speaks on every stop is a hook people turn off, and the
|
|
9
|
+
* question it exists to raise is "did anything get proved at all". Every answer that is not a yes is
|
|
10
|
+
* counted by name — an `unknown` is never folded into anything, because that fold is the false green.
|
|
11
|
+
*/
|
|
12
|
+
export function gapHookLine(gap) {
|
|
13
|
+
if (0 < gap.held)
|
|
14
|
+
return undefined;
|
|
15
|
+
if (0 === gap.claims)
|
|
16
|
+
return NO_CLAIM_HOOK;
|
|
17
|
+
const parts = [
|
|
18
|
+
0 < gap.failed ? `${String(gap.failed)} failed` : undefined,
|
|
19
|
+
0 < gap.undecided ? `${String(gap.undecided)} unknown` : undefined,
|
|
20
|
+
0 < gap.nothingToProve ? `${String(gap.nothingToProve)} proved nothing` : undefined,
|
|
21
|
+
].filter((part) => part !== undefined);
|
|
22
|
+
return `${HOOK_PREFIX} ${plural(gap.claims, 'claim')}: ${parts.join(', ')}`;
|
|
23
|
+
}
|
|
24
|
+
/** The whole gap: held of claimed first, then each kind of not-held with who can act on it. */
|
|
25
|
+
export function gapReportLines(gap) {
|
|
26
|
+
if (0 === gap.claims)
|
|
27
|
+
return [NO_CLAIM_REPORT];
|
|
28
|
+
const lines = [`${String(gap.held)} of ${plural(gap.claims, 'claim')} held`];
|
|
29
|
+
if (0 < gap.failed) {
|
|
30
|
+
const caught = 0 < gap.falseGreensCaught
|
|
31
|
+
? `, ${String(gap.falseGreensCaught)} of them a green a channel contradicted`
|
|
32
|
+
: '';
|
|
33
|
+
lines.push(`${String(gap.failed)} failed${caught}`);
|
|
34
|
+
}
|
|
35
|
+
if (0 < gap.undecided) {
|
|
36
|
+
const owners = Object.entries(gap.undecidedBy)
|
|
37
|
+
.map(([owner, n]) => `${owner}: ${String(n)}`)
|
|
38
|
+
.join(', ');
|
|
39
|
+
lines.push(`${String(gap.undecided)} unknown${'' === owners ? '' : ` (${owners})`}`);
|
|
40
|
+
}
|
|
41
|
+
if (0 < gap.nothingToProve)
|
|
42
|
+
lines.push(`${String(gap.nothingToProve)} proved nothing`);
|
|
43
|
+
for (const failure of gap.failures)
|
|
44
|
+
lines.push(` ✗ ${failure.claim}`);
|
|
45
|
+
return lines;
|
|
46
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gap, as a number the person who ran the session can see.
|
|
3
|
+
*
|
|
4
|
+
* Reticle's whole claim is that it measures the distance between what an agent believed happened
|
|
5
|
+
* and what did. It measures that on every verdict, writes the answer into the journal, and shows it
|
|
6
|
+
* to nobody: the counts exist, the reasons exist, the contradictions exist, and no surface anywhere
|
|
7
|
+
* says "you made 14 claims, 9 held, 2 were false, 3 could not be decided, and here is who owns each
|
|
8
|
+
* of those three". The value of the product is the one thing it never reports.
|
|
9
|
+
*
|
|
10
|
+
* A FOLD over the journal, never a second store — the rule `run-context.ts` next door states, for
|
|
11
|
+
* the same reason: two ways to compute one number is worse than one way, because the day they
|
|
12
|
+
* disagree the disagreement lands inside a verdict and a user finds it before we do.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here sends anything anywhere, and that is deliberate rather than incidental. This is the
|
|
15
|
+
* LOCAL half. Whether a fleet-wide version of the same number is worth collecting is a separate
|
|
16
|
+
* decision with a separate owner, and building the local one first is what makes that decision
|
|
17
|
+
* answerable from something other than a guess.
|
|
18
|
+
*/
|
|
19
|
+
import { VerifiedReason, VerdictAttribution, type JournalAction } from '@reticlehq/core';
|
|
20
|
+
/** One claim that did not hold, in the words it was made and the engine's reason for refusing it. */
|
|
21
|
+
export interface GapFailure {
|
|
22
|
+
claim: string;
|
|
23
|
+
reason?: VerifiedReason;
|
|
24
|
+
}
|
|
25
|
+
export interface GapSummary {
|
|
26
|
+
/** Actions that asserted something. An action that only drove the app is not a claim. */
|
|
27
|
+
claims: number;
|
|
28
|
+
held: number;
|
|
29
|
+
failed: number;
|
|
30
|
+
/** `unknown`: Reticle could not tell. Never folded into held or failed — that is the false green. */
|
|
31
|
+
undecided: number;
|
|
32
|
+
/**
|
|
33
|
+
* `no-fault`: nothing was declared, so nothing was checked.
|
|
34
|
+
*
|
|
35
|
+
* The fourth answer, kept apart from the other three. Folding it anywhere is how a session that
|
|
36
|
+
* proved nothing reads as a session that proved something.
|
|
37
|
+
*/
|
|
38
|
+
nothingToProve: number;
|
|
39
|
+
/**
|
|
40
|
+
* WHO can act on each undecided verdict, counted per owner.
|
|
41
|
+
*
|
|
42
|
+
* The only part of an `unknown` a reader can do anything with: the four owners imply four
|
|
43
|
+
* different next moves — wait, fix the app, fix the harness, look again. Empty when nothing was
|
|
44
|
+
* undecided, and a verdict that recorded no reason contributes to no owner rather than to a
|
|
45
|
+
* guessed one.
|
|
46
|
+
*/
|
|
47
|
+
undecidedBy: Partial<Record<VerdictAttribution, number>>;
|
|
48
|
+
/**
|
|
49
|
+
* Failures where a CHANNEL disagreed with what the app showed.
|
|
50
|
+
*
|
|
51
|
+
* Counted apart from an ordinary failure because they mean different things to the reader: an
|
|
52
|
+
* assertion that failed is a check doing its job, and a contradiction is a green that would have
|
|
53
|
+
* been believed. This number is the product's own headline, measured on the reader's own session.
|
|
54
|
+
*/
|
|
55
|
+
falseGreensCaught: number;
|
|
56
|
+
failures: GapFailure[];
|
|
57
|
+
}
|
|
58
|
+
export declare function gapSummary(actions: readonly JournalAction[]): GapSummary;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gap, as a number the person who ran the session can see.
|
|
3
|
+
*
|
|
4
|
+
* Reticle's whole claim is that it measures the distance between what an agent believed happened
|
|
5
|
+
* and what did. It measures that on every verdict, writes the answer into the journal, and shows it
|
|
6
|
+
* to nobody: the counts exist, the reasons exist, the contradictions exist, and no surface anywhere
|
|
7
|
+
* says "you made 14 claims, 9 held, 2 were false, 3 could not be decided, and here is who owns each
|
|
8
|
+
* of those three". The value of the product is the one thing it never reports.
|
|
9
|
+
*
|
|
10
|
+
* A FOLD over the journal, never a second store — the rule `run-context.ts` next door states, for
|
|
11
|
+
* the same reason: two ways to compute one number is worse than one way, because the day they
|
|
12
|
+
* disagree the disagreement lands inside a verdict and a user finds it before we do.
|
|
13
|
+
*
|
|
14
|
+
* Nothing here sends anything anywhere, and that is deliberate rather than incidental. This is the
|
|
15
|
+
* LOCAL half. Whether a fleet-wide version of the same number is worth collecting is a separate
|
|
16
|
+
* decision with a separate owner, and building the local one first is what makes that decision
|
|
17
|
+
* answerable from something other than a guess.
|
|
18
|
+
*/
|
|
19
|
+
import { JournalVerdictEffectSchema, Verified, VerifiedReason, VerdictAttribution, verdictAttributionOf, } from '@reticlehq/core';
|
|
20
|
+
/**
|
|
21
|
+
* The reason, as the engine's own enum, or undefined.
|
|
22
|
+
*
|
|
23
|
+
* The journal stores `reason` as a free string rather than the enum — deliberately, because the
|
|
24
|
+
* ledger has to keep reading records written by an older engine whose vocabulary it cannot know.
|
|
25
|
+
* So a reason this build does not recognise is treated exactly like an absent one: no owner. The
|
|
26
|
+
* alternative is attributing an unknown word to one of four buckets, which is inventing an
|
|
27
|
+
* attribution nobody recorded.
|
|
28
|
+
*/
|
|
29
|
+
function knownReason(reason) {
|
|
30
|
+
if (reason === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
const known = Object.values(VerifiedReason);
|
|
33
|
+
return known.includes(reason) ? reason : undefined;
|
|
34
|
+
}
|
|
35
|
+
/** The verdict a verification tool recorded on this action, if it recorded one. */
|
|
36
|
+
function verdictOf(action) {
|
|
37
|
+
const parsed = JournalVerdictEffectSchema.safeParse(action.effect);
|
|
38
|
+
return parsed.success ? parsed.data : undefined;
|
|
39
|
+
}
|
|
40
|
+
export function gapSummary(actions) {
|
|
41
|
+
const summary = {
|
|
42
|
+
claims: 0,
|
|
43
|
+
held: 0,
|
|
44
|
+
failed: 0,
|
|
45
|
+
undecided: 0,
|
|
46
|
+
nothingToProve: 0,
|
|
47
|
+
undecidedBy: {},
|
|
48
|
+
falseGreensCaught: 0,
|
|
49
|
+
failures: [],
|
|
50
|
+
};
|
|
51
|
+
for (const action of actions) {
|
|
52
|
+
const verdict = verdictOf(action);
|
|
53
|
+
if (verdict === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
summary.claims += 1;
|
|
56
|
+
switch (verdict.verified) {
|
|
57
|
+
case Verified.YES:
|
|
58
|
+
summary.held += 1;
|
|
59
|
+
break;
|
|
60
|
+
case Verified.NO: {
|
|
61
|
+
summary.failed += 1;
|
|
62
|
+
if (VerifiedReason.CONTRADICTED === verdict.reason)
|
|
63
|
+
summary.falseGreensCaught += 1;
|
|
64
|
+
const reason = knownReason(verdict.reason);
|
|
65
|
+
summary.failures.push(reason === undefined ? { claim: verdict.claim } : { claim: verdict.claim, reason });
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case Verified.UNKNOWN: {
|
|
69
|
+
summary.undecided += 1;
|
|
70
|
+
// A record written before `reason` existed has none, and must not be read as though it did:
|
|
71
|
+
// counting it under an owner would invent an attribution nobody recorded.
|
|
72
|
+
const reason = knownReason(verdict.reason);
|
|
73
|
+
const owner = reason === undefined ? undefined : verdictAttributionOf(reason);
|
|
74
|
+
if (owner !== undefined && VerdictAttribution.NONE !== owner) {
|
|
75
|
+
summary.undecidedBy[owner] = (summary.undecidedBy[owner] ?? 0) + 1;
|
|
76
|
+
}
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case Verified.NO_FAULT:
|
|
80
|
+
summary.nothingToProve += 1;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return summary;
|
|
85
|
+
}
|
|
@@ -35,7 +35,10 @@ const CHECK_GLYPH = {
|
|
|
35
35
|
[Verified.NO_FAULT]: '–',
|
|
36
36
|
};
|
|
37
37
|
function checkLine(c) {
|
|
38
|
-
|
|
38
|
+
// No kind, no prefix. A check folded from a journal that never recorded one has nothing to name
|
|
39
|
+
// here, and printing a placeholder would read as a kind.
|
|
40
|
+
const read = c.kind === undefined ? '' : `${c.kind}: `;
|
|
41
|
+
return ` ${CHECK_GLYPH[c.status]} ${read}${c.predicate}`;
|
|
39
42
|
}
|
|
40
43
|
function riskLine(r) {
|
|
41
44
|
return ` ⚠ ${r.surface} (${r.severity})${r.gated ? ' [GATED]' : ''} — ${r.detail}`;
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* perspective a flow that drifted no longer behaves, so it must not read as green. The actionable
|
|
5
5
|
* "why" is lifted from the replay's decision envelope (or its error) into failureReason.
|
|
6
6
|
*/
|
|
7
|
-
import { ReplayStatus, RunFlowStatus, type FlowReplayResult, type RunFlowResult } from '@reticlehq/core';
|
|
7
|
+
import { ReplayStatus, RunFlowStatus, type FlowFile, type FlowReplayResult, type RunFlowResult } from '@reticlehq/core';
|
|
8
8
|
/** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
|
|
9
9
|
export declare function runFlowStatusOf(status: ReplayStatus): RunFlowStatus;
|
|
10
10
|
/** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
|
|
11
|
-
export declare function mapReplayToFlowResult(replay: FlowReplayResult, durationMs: number): RunFlowResult;
|
|
11
|
+
export declare function mapReplayToFlowResult(replay: FlowReplayResult, durationMs: number, flow?: FlowFile): RunFlowResult;
|
|
@@ -4,21 +4,52 @@
|
|
|
4
4
|
* perspective a flow that drifted no longer behaves, so it must not read as green. The actionable
|
|
5
5
|
* "why" is lifted from the replay's decision envelope (or its error) into failureReason.
|
|
6
6
|
*/
|
|
7
|
-
import { ReplayStatus, RunFlowStatus, } from '@reticlehq/core';
|
|
7
|
+
import { ReplayStatus, RUN_RECORDING_MAX_BYTES, RUN_STEP_RESULTS_MAX, RUN_TEXT_MAX, RunFlowStatus, } from '@reticlehq/core';
|
|
8
8
|
import { SUCCESS_STEP_TOOL } from '../../../language/flows/flow-success.js';
|
|
9
9
|
/** OK → PASS; DRIFT/ERROR → FAIL (a healed flow is produced by the heal path, not plain replay). */
|
|
10
10
|
export function runFlowStatusOf(status) {
|
|
11
11
|
return status === ReplayStatus.OK ? RunFlowStatus.PASS : RunFlowStatus.FAIL;
|
|
12
12
|
}
|
|
13
|
+
const clip = (text) => text.length > RUN_TEXT_MAX ? `${text.slice(0, RUN_TEXT_MAX - 1)}…` : text;
|
|
14
|
+
/** One step as synced: what it did, where, and whether it held. */
|
|
15
|
+
function stepResultOf(step) {
|
|
16
|
+
return {
|
|
17
|
+
step: step.step,
|
|
18
|
+
anchor: clip(step.anchor),
|
|
19
|
+
ok: step.ok,
|
|
20
|
+
...(step.page === undefined ? {} : { page: step.page }),
|
|
21
|
+
...(step.endPage === undefined ? {} : { endPage: step.endPage }),
|
|
22
|
+
...(step.consequence === undefined ? {} : { consequence: clip(step.consequence) }),
|
|
23
|
+
...(step.error === undefined ? {} : { error: clip(step.error) }),
|
|
24
|
+
...(step.drift === undefined ? {} : { drift: step.drift.reasonKind }),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The flow as recorded, when it is small enough to travel — what lets a teammate replay this run
|
|
29
|
+
* from the cloud. Fill values were already redacted when the flow was saved.
|
|
30
|
+
*/
|
|
31
|
+
function recordingOf(flow) {
|
|
32
|
+
const recording = {
|
|
33
|
+
...(flow.startPath === undefined ? {} : { startPath: flow.startPath }),
|
|
34
|
+
steps: flow.steps,
|
|
35
|
+
};
|
|
36
|
+
return Buffer.byteLength(JSON.stringify(recording)) > RUN_RECORDING_MAX_BYTES
|
|
37
|
+
? { recordingOmitted: true }
|
|
38
|
+
: { recording };
|
|
39
|
+
}
|
|
13
40
|
/** Map one replay (plus its measured duration) into a RunFlowResult for the artifact's flows[]. */
|
|
14
|
-
export function mapReplayToFlowResult(replay, durationMs) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
export function mapReplayToFlowResult(replay, durationMs, flow) {
|
|
42
|
+
// A replay that could not start returns OK with no steps. Nothing ran, so it is SKIPPED — which
|
|
43
|
+
// every reader of a run (the verdict, the gate) already refuses to count as a pass.
|
|
44
|
+
const status = replay.unverifiable === undefined ? runFlowStatusOf(replay.status) : RunFlowStatus.SKIPPED;
|
|
45
|
+
const failureReason = replay.unverifiable !== undefined
|
|
46
|
+
? replay.unverifiable.reason
|
|
47
|
+
: status === RunFlowStatus.FAIL
|
|
48
|
+
? (replay.decision?.whatChanged ??
|
|
49
|
+
replay.decision?.summary ??
|
|
50
|
+
replay.error?.message ??
|
|
51
|
+
'flow failed')
|
|
52
|
+
: undefined;
|
|
22
53
|
// A flow with a success oracle gets a synthetic 'success' step appended by replay; surface its label
|
|
23
54
|
// as the run's `oracle` so the verdict counts this flow as consequence-backed (→ HIGH confidence),
|
|
24
55
|
// not a bare smoke click. Without this, an oracle-backed pass reads as MEDIUM and undersells itself.
|
|
@@ -30,5 +61,9 @@ export function mapReplayToFlowResult(replay, durationMs) {
|
|
|
30
61
|
durationMs,
|
|
31
62
|
...(oracle !== undefined ? { oracle } : {}),
|
|
32
63
|
...(failureReason !== undefined ? { failureReason } : {}),
|
|
64
|
+
...(0 === replay.steps.length
|
|
65
|
+
? {}
|
|
66
|
+
: { stepResults: replay.steps.slice(0, RUN_STEP_RESULTS_MAX).map(stepResultOf) }),
|
|
67
|
+
...(flow === undefined ? {} : recordingOf(flow)),
|
|
33
68
|
};
|
|
34
69
|
}
|
|
@@ -22,8 +22,13 @@ export declare const OVP_ARTIFACT_VERSION = 1;
|
|
|
22
22
|
export interface ExportedCheck {
|
|
23
23
|
/** What was claimed, as the person or agent wrote it. */
|
|
24
24
|
readonly claim: string;
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Which source of truth answering it required.
|
|
27
|
+
*
|
|
28
|
+
* Absent when the run did not record one -- which is the same rule the rest of this file follows:
|
|
29
|
+
* a kind nobody wrote down is left out, never filled in with a plausible one.
|
|
30
|
+
*/
|
|
31
|
+
readonly reads?: PredicateKind;
|
|
27
32
|
/**
|
|
28
33
|
* Was the claim written down before the action, or after it?
|
|
29
34
|
*
|
|
@@ -31,7 +31,7 @@ function exportedChecks(run) {
|
|
|
31
31
|
for (const check of run.checks) {
|
|
32
32
|
decided.push({
|
|
33
33
|
claim: check.predicate,
|
|
34
|
-
reads: check.kind,
|
|
34
|
+
...(check.kind === undefined ? {} : { reads: check.kind }),
|
|
35
35
|
verdict: check.status,
|
|
36
36
|
// Spread, so a value the run did not record leaves the key out rather than writing a
|
|
37
37
|
// comfortable default. `declaredBeforeActing: false` says the claim came afterwards; absent
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import {} from '@reticlehq/core';
|
|
3
3
|
import { runContextFor } from './artifact/run-context.js';
|
|
4
|
+
import { gapSummary } from './artifact/gap-summary.js';
|
|
4
5
|
import { openSessionIntents } from '../../memory/intent/open-intents.js';
|
|
5
6
|
import { ReticleTool } from '@reticlehq/core';
|
|
6
7
|
import { sessionIdShape } from '../../surface/tools/tool-kit.js';
|
|
@@ -27,9 +28,13 @@ const CONTEXT_OUTPUT_SCHEMA = {
|
|
|
27
28
|
proven: z
|
|
28
29
|
.array(z.unknown())
|
|
29
30
|
.describe('Claims a verdict already settled, each `{ claim, verified, source?, doc?, epoch? }`. Read this before re-driving something: re-proving it is slow, and assuming it is a false green.'),
|
|
31
|
+
gap: z
|
|
32
|
+
.object({})
|
|
33
|
+
.passthrough()
|
|
34
|
+
.describe('The distance between what was claimed and what held, over THIS session: `{ claims, held, failed, undecided, nothingToProve, undecidedBy, falseGreensCaught, failures }`. `undecidedBy` says WHO can act on each unknown — environment (wait), code (fix the app), harness (fix Reticle or the call), could-not-see (look again). Folded from the same journal as everything else here, so it cannot disagree with it.'),
|
|
30
35
|
remaining: z
|
|
31
36
|
.array(z.string())
|
|
32
|
-
.describe('The intents from .reticle/intent
|
|
37
|
+
.describe('The intents from .reticle/intent/ that no verdict has discharged. Derived from the ledger, never a guess at what you meant to do next.'),
|
|
33
38
|
};
|
|
34
39
|
/** The ledger and the live page state this run is folded out of. `[]`/undefined when nothing is connected. */
|
|
35
40
|
async function evidenceFor(deps, sessionId) {
|
|
@@ -57,14 +62,27 @@ async function evidenceFor(deps, sessionId) {
|
|
|
57
62
|
export const CONTEXT_TOOLS = [
|
|
58
63
|
{
|
|
59
64
|
name: ReticleTool.CONTEXT,
|
|
60
|
-
description: 'What THIS run has already established, so you do not rediscover it. Call it when your own copy is gone: right after a compaction, at the top of a fresh sub-agent, or at the start of a turn you did not begin. Returns `established` (what Reticle OBSERVED, with the source file:line where one was reported), `proven` (claims a verdict already settled, so you neither re-prove them nor assume them) and `remaining` (the intents from .reticle/intent
|
|
65
|
+
description: 'What THIS run has already established, so you do not rediscover it. Call it when your own copy is gone: right after a compaction, at the top of a fresh sub-agent, or at the start of a turn you did not begin. Returns `established` (what Reticle OBSERVED, with the source file:line where one was reported), `proven` (claims a verdict already settled, so you neither re-prove them nor assume them) and `remaining` (the intents from .reticle/intent/ that nothing has discharged). It is a FOLD over the journal, never a second store, so it cannot disagree with the ledger. Bounded and superseding rather than accumulating, and anything observed under a replaced document or before your last source edit is already dropped rather than presented as current. Only what Reticle observed goes in: it never reports what you intended or believed.',
|
|
61
66
|
example: {},
|
|
62
67
|
inputSchema: { ...sessionIdShape },
|
|
63
68
|
outputSchema: CONTEXT_OUTPUT_SCHEMA,
|
|
64
69
|
handler: async (deps, args) => {
|
|
65
70
|
const sessionId = asString(args['sessionId']);
|
|
66
71
|
const evidence = await evidenceFor(deps, sessionId);
|
|
67
|
-
|
|
72
|
+
const context = runContextFor({
|
|
73
|
+
...evidence,
|
|
74
|
+
intents: await openSessionIntents(deps, sessionId),
|
|
75
|
+
});
|
|
76
|
+
/*
|
|
77
|
+
* The gap rides on `reticle_context` rather than on a tool of its own.
|
|
78
|
+
*
|
|
79
|
+
* This is the one call an agent makes when it needs to know what the run has already settled,
|
|
80
|
+
* which is exactly the moment "and what did NOT settle, and whose problem each of those is"
|
|
81
|
+
* is worth reading. It is folded from the same journal the rest of this response is folded
|
|
82
|
+
* from, so it costs one more pass over an array already in hand and cannot disagree with the
|
|
83
|
+
* `proven` list beside it.
|
|
84
|
+
*/
|
|
85
|
+
return { ...context, gap: gapSummary(evidence.actions) };
|
|
68
86
|
},
|
|
69
87
|
},
|
|
70
88
|
];
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { isValidRunId } from '../../memory/project/dir/reticle-dir.js';
|
|
26
26
|
import { defaultRunId } from './runner-port.js';
|
|
27
|
-
import { JournalVerdictEffectSchema, RunAgentKind,
|
|
27
|
+
import { JournalVerdictEffectSchema, RunAgentKind, RunFramework, RunProfile, RunTrigger, } from '@reticlehq/core';
|
|
28
28
|
import { withCorrections } from './late-answer.js';
|
|
29
29
|
/** The author of record when no MCP peer introduced itself. Mirrors verification-sync's default. */
|
|
30
30
|
const UNNAMED_AGENT = 'reticle-mcp';
|
|
@@ -77,13 +77,18 @@ export function driveRunFrom(actions, deps) {
|
|
|
77
77
|
const checks = [];
|
|
78
78
|
for (const verdict of found) {
|
|
79
79
|
checks.push({
|
|
80
|
-
kind: PredicateKind.ELEMENT,
|
|
81
80
|
predicate: verdict.claim,
|
|
82
81
|
status: verdict.verified,
|
|
83
82
|
...(verdict.source === undefined ? {} : { evidence: { source: verdict.source } }),
|
|
84
83
|
// Carried through rather than recomputed. These were established at the moment the verdict
|
|
85
84
|
// was made and written down then; a run built later cannot know any of them, and inferring
|
|
86
85
|
// them here would be inventing evidence about evidence.
|
|
86
|
+
//
|
|
87
|
+
// `kind` was the one field that rule was not applied to: it was stamped `element` on every
|
|
88
|
+
// check ever folded, including the ones whose `grade` in the same object said `net`. A
|
|
89
|
+
// journal old enough to have no kind now produces a check with no kind, which is the honest
|
|
90
|
+
// answer -- a missing field, rather than a wrong one nothing downstream can question.
|
|
91
|
+
...(verdict.kind === undefined ? {} : { kind: verdict.kind }),
|
|
87
92
|
...(verdict.declaredBeforeActing === undefined
|
|
88
93
|
? {}
|
|
89
94
|
: { declaredBeforeActing: verdict.declaredBeforeActing }),
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { type ProjectId, type FlowReplayResult } from '@reticlehq/core';
|
|
1
|
+
import { type ProjectId, type FlowFile, type FlowReplayResult } from '@reticlehq/core';
|
|
2
2
|
import type { ToolDeps } from '../../surface/tools/tool-kit.js';
|
|
3
3
|
/** A replay plus the wall-clock time it took — the shape the verify handler already collects. */
|
|
4
4
|
export interface TimedReplay {
|
|
5
5
|
replay: FlowReplayResult;
|
|
6
6
|
durationMs: number;
|
|
7
|
+
/** The flow file that was replayed, so the synced run can carry its recording. */
|
|
8
|
+
flow?: FlowFile;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* Persist the suite's run artifact and best-effort mirror it to the cloud. Never throws into the verify
|
|
@@ -23,7 +23,7 @@ import { rootForProjectId } from '../../memory/project/session-root.js';
|
|
|
23
23
|
const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
|
|
24
24
|
/** Assemble the ReticleVerificationRun artifact for a verify suite (pure — no IO). */
|
|
25
25
|
function assembleRun(deps, timed, projectId) {
|
|
26
|
-
const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs));
|
|
26
|
+
const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs, t.flow));
|
|
27
27
|
const input = {
|
|
28
28
|
runId: defaultRunId(),
|
|
29
29
|
durationMs: flows.reduce((sum, f) => sum + f.durationMs, 0),
|
|
@@ -1,19 +1,4 @@
|
|
|
1
1
|
import { type Annotation, type AnnotateOutcome } from '@reticlehq/core';
|
|
2
|
-
/**
|
|
3
|
-
* The PURE compiler at the heart of the annotation facet. A structured annotation +
|
|
4
|
-
* the current captured-step count → an AnnotateOutcome (a result envelope + the patch to apply to
|
|
5
|
-
* the AnnotationStore). No IO, no clock, unit-testable in isolation.
|
|
6
|
-
*
|
|
7
|
-
* assert-signal → step.expect.signal (+ signalData) on the LAST step (needs ≥1 step)
|
|
8
|
-
* assert-visible → step.expect.element.testid on the LAST step (needs ≥1 step)
|
|
9
|
-
* mark-dynamic → flow.dynamic[] += testid flow-level, allowed with 0 steps
|
|
10
|
-
* success-state → flow.success = { signal | state | net | console | element | text } flow-level,
|
|
11
|
-
* resolved in that precedence order (a consequence beats a presence check)
|
|
12
|
-
*
|
|
13
|
-
* FIRST CUT: only the four structured kinds above. Free natural-language annotation → predicate
|
|
14
|
-
* compilation is explicitly FUTURE — an NL string never reaches here (AnnotationSchema
|
|
15
|
-
* rejects it upstream; the tool maps that to UNKNOWN_KIND). No NL parser exists or is faked.
|
|
16
|
-
*/
|
|
17
2
|
export declare function compileAnnotation(a: Annotation, stepCount: number): AnnotateOutcome;
|
|
18
3
|
/**
|
|
19
4
|
* Human-readable confirmation text for the recorder strip / tool result,
|