@reticlehq/server 2.2.0 → 2.3.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/README.md +1 -1
- package/dist/bridge-security.d.ts +0 -1
- package/dist/bridge-security.js +0 -1
- package/dist/bridge.d.ts +0 -1
- package/dist/bridge.js +60 -10
- package/dist/bridge.test-harness.d.ts +0 -1
- package/dist/bridge.test-harness.js +0 -1
- package/dist/capsule/capsule-store.d.ts +2 -3
- package/dist/capsule/capsule-store.js +0 -1
- package/dist/capsule/capsule.d.ts +0 -1
- package/dist/capsule/capsule.js +0 -1
- package/dist/capsule/causal-summary.d.ts +21 -1
- package/dist/capsule/causal-summary.js +20 -2
- package/dist/capsule/divergence.d.ts +0 -1
- package/dist/capsule/divergence.js +0 -1
- package/dist/capsule/minimize.d.ts +0 -1
- package/dist/capsule/minimize.js +0 -1
- package/dist/capsule/predicate-to-links.d.ts +0 -1
- package/dist/capsule/predicate-to-links.js +0 -1
- package/dist/cli-doctor.d.ts +6 -0
- package/dist/cli-doctor.js +60 -0
- package/dist/cli-flow-commands.d.ts +0 -1
- package/dist/cli-flow-commands.js +0 -1
- package/dist/cli-launch.d.ts +0 -1
- package/dist/cli-launch.js +7 -3
- package/dist/cli-parse.d.ts +52 -2
- package/dist/cli-parse.js +147 -3
- package/dist/cli-port.d.ts +0 -1
- package/dist/cli-port.js +0 -1
- package/dist/cli-verify.d.ts +2 -1
- package/dist/cli-verify.js +24 -3
- package/dist/cli.d.ts +2 -4
- package/dist/cli.js +109 -10
- package/dist/cloud/cloud-config.d.ts +36 -0
- package/dist/cloud/cloud-config.js +86 -0
- package/dist/cloud/cloud-sync.d.ts +96 -4
- package/dist/cloud/cloud-sync.js +131 -3
- package/dist/cloud-cli.d.ts +3 -0
- package/dist/cloud-cli.js +514 -0
- package/dist/crawl/crawl-tools.d.ts +0 -1
- package/dist/crawl/crawl-tools.js +1 -2
- package/dist/crawl/crawl.d.ts +17 -3
- package/dist/crawl/crawl.js +43 -4
- package/dist/daemon-resilience.d.ts +6 -1
- package/dist/daemon-resilience.js +63 -1
- package/dist/daemon.d.ts +23 -3
- package/dist/daemon.js +78 -21
- package/dist/domain/domain-model.d.ts +0 -1
- package/dist/domain/domain-model.js +1 -2
- package/dist/domain/domain-tools.d.ts +0 -7
- package/dist/domain/domain-tools.js +21 -4
- package/dist/domain/flow-risk.d.ts +0 -1
- package/dist/domain/flow-risk.js +0 -1
- package/dist/ee/audit-log.d.ts +0 -1
- package/dist/ee/audit-log.js +0 -1
- package/dist/events/body-failures.d.ts +4 -0
- package/dist/events/body-failures.js +113 -0
- package/dist/events/contradictions.d.ts +53 -0
- package/dist/events/contradictions.js +282 -0
- package/dist/events/echo-mismatch.d.ts +4 -0
- package/dist/events/echo-mismatch.js +138 -0
- package/dist/events/event-filters.d.ts +17 -3
- package/dist/events/event-filters.js +13 -3
- package/dist/events/json-salvage.d.ts +32 -0
- package/dist/events/json-salvage.js +96 -0
- package/dist/events/predicate-eval.d.ts +2 -1
- package/dist/events/predicate-eval.js +56 -9
- package/dist/events/predicate.d.ts +0 -1
- package/dist/events/predicate.js +56 -2
- package/dist/events/reaction.d.ts +0 -1
- package/dist/events/reaction.js +0 -1
- package/dist/events/reconcile.d.ts +39 -0
- package/dist/events/reconcile.js +211 -0
- package/dist/events/ring-buffer.d.ts +0 -1
- package/dist/events/ring-buffer.js +0 -1
- package/dist/events/stale-response.d.ts +4 -0
- package/dist/events/stale-response.js +139 -0
- package/dist/events/unit-mismatch.d.ts +16 -0
- package/dist/events/unit-mismatch.js +167 -0
- package/dist/flows/affected-tools.d.ts +18 -0
- package/dist/flows/affected-tools.js +52 -0
- package/dist/flows/affected.d.ts +0 -1
- package/dist/flows/affected.js +0 -1
- package/dist/flows/annotate-tools.d.ts +0 -1
- package/dist/flows/annotate-tools.js +21 -3
- package/dist/flows/annotate.d.ts +0 -1
- package/dist/flows/annotate.js +0 -1
- package/dist/flows/annotation-store.d.ts +0 -1
- package/dist/flows/annotation-store.js +0 -1
- package/dist/flows/assertion-integrity.d.ts +0 -1
- package/dist/flows/assertion-integrity.js +0 -1
- package/dist/flows/assertion-tiers-store.d.ts +0 -1
- package/dist/flows/assertion-tiers-store.js +0 -1
- package/dist/flows/buddy-status.d.ts +0 -1
- package/dist/flows/buddy-status.js +0 -1
- package/dist/flows/coverage.d.ts +0 -1
- package/dist/flows/coverage.js +0 -1
- package/dist/flows/decision.d.ts +0 -1
- package/dist/flows/decision.js +0 -1
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +0 -1
- package/dist/flows/flake.d.ts +0 -1
- package/dist/flows/flake.js +0 -1
- package/dist/flows/flow-classify.d.ts +0 -1
- package/dist/flows/flow-classify.js +0 -1
- package/dist/flows/flow-replay-run.d.ts +0 -1
- package/dist/flows/flow-replay-run.js +24 -8
- package/dist/flows/flow-replay.d.ts +20 -4
- package/dist/flows/flow-replay.js +9 -43
- package/dist/flows/flow-report.d.ts +0 -1
- package/dist/flows/flow-report.js +0 -1
- package/dist/flows/flow-scope.d.ts +0 -1
- package/dist/flows/flow-scope.js +0 -1
- package/dist/flows/flow-sources.d.ts +0 -1
- package/dist/flows/flow-sources.js +0 -1
- package/dist/flows/flow-step-runners.d.ts +23 -0
- package/dist/flows/flow-step-runners.js +102 -0
- package/dist/flows/flow-success.d.ts +0 -1
- package/dist/flows/flow-success.js +0 -1
- package/dist/flows/flow-tools.d.ts +0 -1
- package/dist/flows/flow-tools.js +54 -16
- package/dist/flows/flows.d.ts +6 -2
- package/dist/flows/flows.js +15 -2
- package/dist/flows/gate.d.ts +0 -1
- package/dist/flows/gate.js +0 -1
- package/dist/flows/git-changed.d.ts +0 -1
- package/dist/flows/git-changed.js +0 -1
- package/dist/flows/heal-run.d.ts +0 -1
- package/dist/flows/heal-run.js +0 -1
- package/dist/flows/heal.d.ts +0 -1
- package/dist/flows/heal.js +0 -1
- package/dist/flows/parallel-suite.d.ts +0 -1
- package/dist/flows/parallel-suite.js +0 -1
- package/dist/flows/recordings.d.ts +0 -1
- package/dist/flows/recordings.js +0 -1
- package/dist/flows/replay.d.ts +0 -1
- package/dist/flows/replay.js +71 -4
- package/dist/flows/server-verify.d.ts +15 -0
- package/dist/flows/server-verify.js +42 -0
- package/dist/flows/verify-change-tools.d.ts +2 -0
- package/dist/flows/verify-change-tools.js +187 -0
- package/dist/flows/watch-batcher.d.ts +0 -1
- package/dist/flows/watch-batcher.js +0 -1
- package/dist/honesty/accepted-write.d.ts +14 -0
- package/dist/honesty/accepted-write.js +17 -0
- package/dist/honesty/blind-spots.d.ts +18 -1
- package/dist/honesty/blind-spots.js +47 -5
- package/dist/honesty/honesty.d.ts +0 -1
- package/dist/honesty/honesty.js +0 -1
- package/dist/honesty/uncaptured-bodies.d.ts +19 -0
- package/dist/honesty/uncaptured-bodies.js +30 -0
- package/dist/honesty/unread-outcome.d.ts +2 -0
- package/dist/honesty/unread-outcome.js +50 -0
- package/dist/honesty/verified.d.ts +40 -0
- package/dist/honesty/verified.js +86 -0
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +5 -1
- package/dist/hunt/hunt-report.d.ts +50 -0
- package/dist/hunt/hunt-report.js +84 -0
- package/dist/idle-shutdown.d.ts +0 -1
- package/dist/idle-shutdown.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/init/agent-rules.d.ts +0 -1
- package/dist/init/agent-rules.js +4 -2
- package/dist/init/cursor.d.ts +0 -1
- package/dist/init/cursor.js +0 -1
- package/dist/init/desktop-doctor.d.ts +40 -0
- package/dist/init/desktop-doctor.js +198 -0
- package/dist/init/detect.d.ts +0 -1
- package/dist/init/detect.js +0 -1
- package/dist/init/mcp.d.ts +0 -1
- package/dist/init/mcp.js +0 -1
- package/dist/init/node-io.d.ts +0 -1
- package/dist/init/node-io.js +0 -1
- package/dist/init/plan.d.ts +4 -1
- package/dist/init/plan.js +23 -5
- package/dist/init/project-id.d.ts +0 -1
- package/dist/init/project-id.js +0 -1
- package/dist/init/run.d.ts +0 -1
- package/dist/init/run.js +31 -3
- package/dist/init/snippets.d.ts +5 -1
- package/dist/init/snippets.js +5 -1
- package/dist/init/vite-config.d.ts +0 -1
- package/dist/init/vite-config.js +0 -1
- package/dist/input/network-detail.d.ts +0 -1
- package/dist/input/network-detail.js +0 -1
- package/dist/input/network-mock-tools.d.ts +0 -1
- package/dist/input/network-mock-tools.js +3 -4
- package/dist/input/network-mock.d.ts +0 -1
- package/dist/input/network-mock.js +0 -1
- package/dist/input/real-input.d.ts +14 -1
- package/dist/input/real-input.js +45 -3
- package/dist/input/scroll-find.d.ts +0 -1
- package/dist/input/scroll-find.js +0 -1
- package/dist/input/scroll-tools.d.ts +0 -1
- package/dist/input/scroll-tools.js +0 -1
- package/dist/input/viewport-tools.d.ts +0 -1
- package/dist/input/viewport-tools.js +3 -4
- package/dist/journal/ambient-store.d.ts +0 -1
- package/dist/journal/ambient-store.js +0 -1
- package/dist/journal/ambient.d.ts +0 -1
- package/dist/journal/ambient.js +0 -1
- package/dist/journal/attach-journal.d.ts +0 -1
- package/dist/journal/attach-journal.js +0 -1
- package/dist/journal/deviation-report.d.ts +0 -1
- package/dist/journal/deviation-report.js +0 -1
- package/dist/journal/deviation-service.d.ts +0 -1
- package/dist/journal/deviation-service.js +0 -1
- package/dist/journal/envelope-store.d.ts +0 -1
- package/dist/journal/envelope-store.js +0 -1
- package/dist/journal/envelope.d.ts +8 -9
- package/dist/journal/envelope.js +0 -1
- package/dist/journal/journal-query.d.ts +0 -1
- package/dist/journal/journal-query.js +0 -1
- package/dist/journal/journal-recorder.d.ts +0 -1
- package/dist/journal/journal-recorder.js +0 -1
- package/dist/journal/retention.d.ts +0 -1
- package/dist/journal/retention.js +0 -1
- package/dist/journal/rollups.d.ts +0 -1
- package/dist/journal/rollups.js +0 -1
- package/dist/journal/session-end.d.ts +0 -1
- package/dist/journal/session-end.js +0 -1
- package/dist/journal/session-journal.d.ts +0 -1
- package/dist/journal/session-journal.js +0 -1
- package/dist/license/license.d.ts +0 -1
- package/dist/license/license.js +0 -1
- package/dist/log.d.ts +0 -1
- package/dist/log.js +0 -1
- package/dist/mcp-proxy.d.ts +0 -1
- package/dist/mcp-proxy.js +0 -1
- package/dist/mcp.d.ts +15 -1
- package/dist/mcp.js +145 -17
- package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
- package/dist/oracles/flow-instrument-gaps.js +0 -1
- package/dist/oracles/propose-consequences.d.ts +0 -1
- package/dist/oracles/propose-consequences.js +0 -1
- package/dist/oracles/self-instrument.d.ts +0 -1
- package/dist/oracles/self-instrument.js +0 -1
- package/dist/pairing-token.d.ts +0 -1
- package/dist/pairing-token.js +0 -1
- package/dist/phenomena/phenomena.d.ts +0 -1
- package/dist/phenomena/phenomena.js +0 -1
- package/dist/pool/browser-pool.d.ts +0 -1
- package/dist/pool/browser-pool.js +0 -1
- package/dist/pool/lease-reaper.d.ts +0 -1
- package/dist/pool/lease-reaper.js +0 -1
- package/dist/pool/playwright-launcher.d.ts +2 -1
- package/dist/pool/playwright-launcher.js +22 -2
- package/dist/project/baselines.d.ts +0 -1
- package/dist/project/baselines.js +5 -4
- package/dist/project/file-lock.d.ts +2 -1
- package/dist/project/file-lock.js +12 -2
- package/dist/project/fs-port.d.ts +0 -1
- package/dist/project/fs-port.js +0 -1
- package/dist/project/project-store.d.ts +0 -1
- package/dist/project/project-store.js +20 -9
- package/dist/project/project-tools.d.ts +0 -1
- package/dist/project/project-tools.js +57 -9
- package/dist/project/reticle-dir.d.ts +0 -1
- package/dist/project/reticle-dir.js +0 -1
- package/dist/runs/build-verification-run.d.ts +0 -1
- package/dist/runs/build-verification-run.js +0 -1
- package/dist/runs/profile-redact.d.ts +0 -1
- package/dist/runs/profile-redact.js +0 -1
- package/dist/runs/render-report.d.ts +0 -1
- package/dist/runs/render-report.js +0 -1
- package/dist/runs/repair-prompt.d.ts +0 -1
- package/dist/runs/repair-prompt.js +0 -1
- package/dist/runs/replay-mapping.d.ts +0 -1
- package/dist/runs/replay-mapping.js +0 -1
- package/dist/runs/reticle-runner.d.ts +0 -1
- package/dist/runs/reticle-runner.js +4 -2
- package/dist/runs/risk-classify.d.ts +0 -1
- package/dist/runs/risk-classify.js +0 -1
- package/dist/runs/run-diff.d.ts +0 -1
- package/dist/runs/run-diff.js +0 -1
- package/dist/runs/run-store.d.ts +0 -1
- package/dist/runs/run-store.js +0 -1
- package/dist/runs/run-tools.d.ts +0 -1
- package/dist/runs/run-tools.js +0 -1
- package/dist/runs/runner-port.d.ts +0 -1
- package/dist/runs/runner-port.js +0 -1
- package/dist/runs/verification-sync.d.ts +23 -0
- package/dist/runs/verification-sync.js +66 -0
- package/dist/runs/verify-http.d.ts +0 -1
- package/dist/runs/verify-http.js +0 -1
- package/dist/runs/verify-server.d.ts +0 -1
- package/dist/runs/verify-server.js +0 -1
- package/dist/server-version.d.ts +0 -1
- package/dist/server-version.js +0 -1
- package/dist/session/command-timeout.d.ts +35 -0
- package/dist/session/command-timeout.js +41 -0
- package/dist/session/control-envelope.d.ts +2 -3
- package/dist/session/control-envelope.js +2 -3
- package/dist/session/last-act.d.ts +31 -0
- package/dist/session/last-act.js +24 -0
- package/dist/session/live-control-tools.d.ts +0 -1
- package/dist/session/live-control-tools.js +3 -4
- package/dist/session/live-control.d.ts +0 -1
- package/dist/session/live-control.js +0 -1
- package/dist/session/observed-state.d.ts +12 -2
- package/dist/session/observed-state.js +29 -2
- package/dist/session/output-budget.d.ts +0 -1
- package/dist/session/output-budget.js +0 -1
- package/dist/session/pending-commands.d.ts +12 -0
- package/dist/session/pending-commands.js +36 -0
- package/dist/session/presenter-args.d.ts +0 -1
- package/dist/session/presenter-args.js +0 -1
- package/dist/session/review-store.d.ts +0 -1
- package/dist/session/review-store.js +0 -1
- package/dist/session/session-health.d.ts +26 -2
- package/dist/session/session-health.js +13 -1
- package/dist/session/session-info.d.ts +29 -0
- package/dist/session/session-info.js +1 -0
- package/dist/session/session-lease.d.ts +25 -0
- package/dist/session/session-lease.js +14 -0
- package/dist/session/session-manager.d.ts +7 -19
- package/dist/session/session-manager.js +29 -2
- package/dist/session/session-readiness.d.ts +0 -1
- package/dist/session/session-readiness.js +3 -4
- package/dist/session/session-reaper.d.ts +0 -1
- package/dist/session/session-reaper.js +0 -1
- package/dist/session/session-recommendation.d.ts +0 -1
- package/dist/session/session-recommendation.js +0 -1
- package/dist/session/session-tools.d.ts +0 -1
- package/dist/session/session-tools.js +2 -3
- package/dist/session/session.d.ts +27 -53
- package/dist/session/session.js +95 -66
- package/dist/session/state-select.d.ts +0 -1
- package/dist/session/state-select.js +0 -1
- package/dist/telemetry/argument-shape.d.ts +41 -0
- package/dist/telemetry/argument-shape.js +87 -0
- package/dist/telemetry/bug-found.d.ts +33 -0
- package/dist/telemetry/bug-found.js +95 -0
- package/dist/telemetry/cli-telemetry.d.ts +13 -0
- package/dist/telemetry/cli-telemetry.js +43 -0
- package/dist/telemetry/connect-failure.d.ts +16 -0
- package/dist/telemetry/connect-failure.js +44 -0
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +76 -0
- package/dist/telemetry/dev-repo.d.ts +10 -0
- package/dist/telemetry/dev-repo.js +80 -0
- package/dist/telemetry/error-fingerprint.d.ts +24 -0
- package/dist/telemetry/error-fingerprint.js +88 -0
- package/dist/telemetry/feedback-cli.d.ts +31 -0
- package/dist/telemetry/feedback-cli.js +102 -0
- package/dist/telemetry/feedback-context.d.ts +32 -0
- package/dist/telemetry/feedback-context.js +143 -0
- package/dist/telemetry/feedback.d.ts +66 -0
- package/dist/telemetry/feedback.js +175 -0
- package/dist/telemetry/git-facts.d.ts +21 -0
- package/dist/telemetry/git-facts.js +109 -0
- package/dist/telemetry/identify.d.ts +22 -0
- package/dist/telemetry/identify.js +73 -0
- package/dist/telemetry/init-telemetry.d.ts +26 -0
- package/dist/telemetry/init-telemetry.js +33 -0
- package/dist/telemetry/machine-snapshot.d.ts +6 -0
- package/dist/telemetry/machine-snapshot.js +39 -0
- package/dist/telemetry/mcp-connection.d.ts +5 -0
- package/dist/telemetry/mcp-connection.js +44 -0
- package/dist/telemetry/project-profile.d.ts +44 -0
- package/dist/telemetry/project-profile.js +205 -0
- package/dist/telemetry/run-telemetry.d.ts +21 -0
- package/dist/telemetry/run-telemetry.js +62 -0
- package/dist/telemetry/session-metrics.d.ts +103 -0
- package/dist/telemetry/session-metrics.js +329 -0
- package/dist/telemetry/telemetry.d.ts +68 -0
- package/dist/telemetry/telemetry.js +313 -0
- package/dist/token-auth.d.ts +0 -1
- package/dist/token-auth.js +0 -1
- package/dist/tools/act-capsule.d.ts +23 -0
- package/dist/tools/act-capsule.js +47 -0
- package/dist/tools/act-danger.d.ts +7 -0
- package/dist/tools/act-danger.js +44 -0
- package/dist/tools/act-helpers.d.ts +17 -0
- package/dist/tools/act-helpers.js +40 -0
- package/dist/tools/act-tools.d.ts +8 -1
- package/dist/tools/act-tools.js +96 -98
- package/dist/tools/act-view.d.ts +7 -1
- package/dist/tools/act-view.js +13 -1
- package/dist/tools/assert-grade.d.ts +22 -1
- package/dist/tools/assert-grade.js +46 -1
- package/dist/tools/assert-verdict.d.ts +21 -0
- package/dist/tools/assert-verdict.js +62 -0
- package/dist/tools/browser-tools.d.ts +0 -1
- package/dist/tools/browser-tools.js +2 -2
- package/dist/tools/contract-tools.d.ts +0 -1
- package/dist/tools/contract-tools.js +0 -1
- package/dist/tools/coverage-tools.d.ts +9 -0
- package/dist/tools/coverage-tools.js +92 -0
- package/dist/tools/dynamic-tools.d.ts +0 -1
- package/dist/tools/dynamic-tools.js +21 -2
- package/dist/tools/error-recovery.d.ts +18 -2
- package/dist/tools/error-recovery.js +42 -7
- package/dist/tools/feedback-tools.d.ts +24 -0
- package/dist/tools/feedback-tools.js +180 -0
- package/dist/tools/invoke-tool.d.ts +0 -1
- package/dist/tools/invoke-tool.js +116 -2
- package/dist/tools/lease-tools.d.ts +0 -1
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +0 -1
- package/dist/tools/merge-tools.js +0 -1
- package/dist/tools/observe-tools.d.ts +0 -1
- package/dist/tools/observe-tools.js +91 -39
- package/dist/tools/profiles.d.ts +1 -2
- package/dist/tools/profiles.js +43 -16
- package/dist/tools/query-paginate.d.ts +0 -1
- package/dist/tools/query-paginate.js +0 -1
- package/dist/tools/read-tools.d.ts +0 -1
- package/dist/tools/read-tools.js +10 -8
- package/dist/tools/reconcile-tools.d.ts +2 -0
- package/dist/tools/reconcile-tools.js +111 -0
- package/dist/tools/snapshot-delta.d.ts +0 -1
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-invoker.d.ts +0 -1
- package/dist/tools/tool-invoker.js +0 -1
- package/dist/tools/tool-kit.d.ts +16 -1
- package/dist/tools/tool-kit.js +8 -2
- package/dist/tools/tool-names.d.ts +6 -1
- package/dist/tools/tool-names.js +6 -1
- package/dist/tools/tools-helpers.d.ts +0 -1
- package/dist/tools/tools-helpers.js +0 -1
- package/dist/tools/tools.d.ts +0 -1
- package/dist/tools/tools.js +24 -4
- package/dist/update/update-checker.d.ts +0 -1
- package/dist/update/update-checker.js +26 -2
- package/dist/update/update-nudge.d.ts +20 -0
- package/dist/update/update-nudge.js +72 -0
- package/dist/update/updater.d.ts +14 -1
- package/dist/update/updater.js +33 -2
- package/dist/visual/visual-diff.d.ts +0 -1
- package/dist/visual/visual-diff.js +0 -1
- package/dist/visual/visual-store.d.ts +0 -1
- package/dist/visual/visual-store.js +0 -1
- package/dist/visual/visual-tools.d.ts +0 -1
- package/dist/visual/visual-tools.js +103 -16
- package/package.json +2 -2
- package/dist/bridge-security.d.ts.map +0 -1
- package/dist/bridge-security.js.map +0 -1
- package/dist/bridge.d.ts.map +0 -1
- package/dist/bridge.js.map +0 -1
- package/dist/bridge.test-harness.d.ts.map +0 -1
- package/dist/bridge.test-harness.js.map +0 -1
- package/dist/capsule/capsule-store.d.ts.map +0 -1
- package/dist/capsule/capsule-store.js.map +0 -1
- package/dist/capsule/capsule.d.ts.map +0 -1
- package/dist/capsule/capsule.js.map +0 -1
- package/dist/capsule/causal-summary.d.ts.map +0 -1
- package/dist/capsule/causal-summary.js.map +0 -1
- package/dist/capsule/divergence.d.ts.map +0 -1
- package/dist/capsule/divergence.js.map +0 -1
- package/dist/capsule/minimize.d.ts.map +0 -1
- package/dist/capsule/minimize.js.map +0 -1
- package/dist/capsule/predicate-to-links.d.ts.map +0 -1
- package/dist/capsule/predicate-to-links.js.map +0 -1
- package/dist/cli-flow-commands.d.ts.map +0 -1
- package/dist/cli-flow-commands.js.map +0 -1
- package/dist/cli-launch.d.ts.map +0 -1
- package/dist/cli-launch.js.map +0 -1
- package/dist/cli-parse.d.ts.map +0 -1
- package/dist/cli-parse.js.map +0 -1
- package/dist/cli-port.d.ts.map +0 -1
- package/dist/cli-port.js.map +0 -1
- package/dist/cli-verify.d.ts.map +0 -1
- package/dist/cli-verify.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cloud/cloud-sync.d.ts.map +0 -1
- package/dist/cloud/cloud-sync.js.map +0 -1
- package/dist/crawl/crawl-tools.d.ts.map +0 -1
- package/dist/crawl/crawl-tools.js.map +0 -1
- package/dist/crawl/crawl.d.ts.map +0 -1
- package/dist/crawl/crawl.js.map +0 -1
- package/dist/daemon-resilience.d.ts.map +0 -1
- package/dist/daemon-resilience.js.map +0 -1
- package/dist/daemon.d.ts.map +0 -1
- package/dist/daemon.js.map +0 -1
- package/dist/domain/domain-model.d.ts.map +0 -1
- package/dist/domain/domain-model.js.map +0 -1
- package/dist/domain/domain-tools.d.ts.map +0 -1
- package/dist/domain/domain-tools.js.map +0 -1
- package/dist/domain/flow-risk.d.ts.map +0 -1
- package/dist/domain/flow-risk.js.map +0 -1
- package/dist/ee/audit-log.d.ts.map +0 -1
- package/dist/ee/audit-log.js.map +0 -1
- package/dist/events/event-filters.d.ts.map +0 -1
- package/dist/events/event-filters.js.map +0 -1
- package/dist/events/predicate-eval.d.ts.map +0 -1
- package/dist/events/predicate-eval.js.map +0 -1
- package/dist/events/predicate.d.ts.map +0 -1
- package/dist/events/predicate.js.map +0 -1
- package/dist/events/reaction.d.ts.map +0 -1
- package/dist/events/reaction.js.map +0 -1
- package/dist/events/ring-buffer.d.ts.map +0 -1
- package/dist/events/ring-buffer.js.map +0 -1
- package/dist/flows/affected.d.ts.map +0 -1
- package/dist/flows/affected.js.map +0 -1
- package/dist/flows/annotate-tools.d.ts.map +0 -1
- package/dist/flows/annotate-tools.js.map +0 -1
- package/dist/flows/annotate.d.ts.map +0 -1
- package/dist/flows/annotate.js.map +0 -1
- package/dist/flows/annotation-store.d.ts.map +0 -1
- package/dist/flows/annotation-store.js.map +0 -1
- package/dist/flows/assertion-integrity.d.ts.map +0 -1
- package/dist/flows/assertion-integrity.js.map +0 -1
- package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
- package/dist/flows/assertion-tiers-store.js.map +0 -1
- package/dist/flows/buddy-status.d.ts.map +0 -1
- package/dist/flows/buddy-status.js.map +0 -1
- package/dist/flows/coverage.d.ts.map +0 -1
- package/dist/flows/coverage.js.map +0 -1
- package/dist/flows/decision.d.ts.map +0 -1
- package/dist/flows/decision.js.map +0 -1
- package/dist/flows/flake-store.d.ts.map +0 -1
- package/dist/flows/flake-store.js.map +0 -1
- package/dist/flows/flake.d.ts.map +0 -1
- package/dist/flows/flake.js.map +0 -1
- package/dist/flows/flow-classify.d.ts.map +0 -1
- package/dist/flows/flow-classify.js.map +0 -1
- package/dist/flows/flow-replay-run.d.ts.map +0 -1
- package/dist/flows/flow-replay-run.js.map +0 -1
- package/dist/flows/flow-replay.d.ts.map +0 -1
- package/dist/flows/flow-replay.js.map +0 -1
- package/dist/flows/flow-report.d.ts.map +0 -1
- package/dist/flows/flow-report.js.map +0 -1
- package/dist/flows/flow-scope.d.ts.map +0 -1
- package/dist/flows/flow-scope.js.map +0 -1
- package/dist/flows/flow-sources.d.ts.map +0 -1
- package/dist/flows/flow-sources.js.map +0 -1
- package/dist/flows/flow-success.d.ts.map +0 -1
- package/dist/flows/flow-success.js.map +0 -1
- package/dist/flows/flow-tools.d.ts.map +0 -1
- package/dist/flows/flow-tools.js.map +0 -1
- package/dist/flows/flows.d.ts.map +0 -1
- package/dist/flows/flows.js.map +0 -1
- package/dist/flows/gate.d.ts.map +0 -1
- package/dist/flows/gate.js.map +0 -1
- package/dist/flows/git-changed.d.ts.map +0 -1
- package/dist/flows/git-changed.js.map +0 -1
- package/dist/flows/heal-run.d.ts.map +0 -1
- package/dist/flows/heal-run.js.map +0 -1
- package/dist/flows/heal.d.ts.map +0 -1
- package/dist/flows/heal.js.map +0 -1
- package/dist/flows/parallel-suite.d.ts.map +0 -1
- package/dist/flows/parallel-suite.js.map +0 -1
- package/dist/flows/recordings.d.ts.map +0 -1
- package/dist/flows/recordings.js.map +0 -1
- package/dist/flows/replay.d.ts.map +0 -1
- package/dist/flows/replay.js.map +0 -1
- package/dist/flows/watch-batcher.d.ts.map +0 -1
- package/dist/flows/watch-batcher.js.map +0 -1
- package/dist/honesty/blind-spots.d.ts.map +0 -1
- package/dist/honesty/blind-spots.js.map +0 -1
- package/dist/honesty/honesty.d.ts.map +0 -1
- package/dist/honesty/honesty.js.map +0 -1
- package/dist/http-server.d.ts.map +0 -1
- package/dist/http-server.js.map +0 -1
- package/dist/idle-shutdown.d.ts.map +0 -1
- package/dist/idle-shutdown.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init/agent-rules.d.ts.map +0 -1
- package/dist/init/agent-rules.js.map +0 -1
- package/dist/init/cursor.d.ts.map +0 -1
- package/dist/init/cursor.js.map +0 -1
- package/dist/init/detect.d.ts.map +0 -1
- package/dist/init/detect.js.map +0 -1
- package/dist/init/mcp.d.ts.map +0 -1
- package/dist/init/mcp.js.map +0 -1
- package/dist/init/node-io.d.ts.map +0 -1
- package/dist/init/node-io.js.map +0 -1
- package/dist/init/plan.d.ts.map +0 -1
- package/dist/init/plan.js.map +0 -1
- package/dist/init/project-id.d.ts.map +0 -1
- package/dist/init/project-id.js.map +0 -1
- package/dist/init/run.d.ts.map +0 -1
- package/dist/init/run.js.map +0 -1
- package/dist/init/snippets.d.ts.map +0 -1
- package/dist/init/snippets.js.map +0 -1
- package/dist/init/vite-config.d.ts.map +0 -1
- package/dist/init/vite-config.js.map +0 -1
- package/dist/input/network-detail.d.ts.map +0 -1
- package/dist/input/network-detail.js.map +0 -1
- package/dist/input/network-mock-tools.d.ts.map +0 -1
- package/dist/input/network-mock-tools.js.map +0 -1
- package/dist/input/network-mock.d.ts.map +0 -1
- package/dist/input/network-mock.js.map +0 -1
- package/dist/input/real-input.d.ts.map +0 -1
- package/dist/input/real-input.js.map +0 -1
- package/dist/input/scroll-find.d.ts.map +0 -1
- package/dist/input/scroll-find.js.map +0 -1
- package/dist/input/scroll-tools.d.ts.map +0 -1
- package/dist/input/scroll-tools.js.map +0 -1
- package/dist/input/viewport-tools.d.ts.map +0 -1
- package/dist/input/viewport-tools.js.map +0 -1
- package/dist/journal/ambient-store.d.ts.map +0 -1
- package/dist/journal/ambient-store.js.map +0 -1
- package/dist/journal/ambient.d.ts.map +0 -1
- package/dist/journal/ambient.js.map +0 -1
- package/dist/journal/attach-journal.d.ts.map +0 -1
- package/dist/journal/attach-journal.js.map +0 -1
- package/dist/journal/deviation-report.d.ts.map +0 -1
- package/dist/journal/deviation-report.js.map +0 -1
- package/dist/journal/deviation-service.d.ts.map +0 -1
- package/dist/journal/deviation-service.js.map +0 -1
- package/dist/journal/envelope-store.d.ts.map +0 -1
- package/dist/journal/envelope-store.js.map +0 -1
- package/dist/journal/envelope.d.ts.map +0 -1
- package/dist/journal/envelope.js.map +0 -1
- package/dist/journal/journal-query.d.ts.map +0 -1
- package/dist/journal/journal-query.js.map +0 -1
- package/dist/journal/journal-recorder.d.ts.map +0 -1
- package/dist/journal/journal-recorder.js.map +0 -1
- package/dist/journal/retention.d.ts.map +0 -1
- package/dist/journal/retention.js.map +0 -1
- package/dist/journal/rollups.d.ts.map +0 -1
- package/dist/journal/rollups.js.map +0 -1
- package/dist/journal/session-end.d.ts.map +0 -1
- package/dist/journal/session-end.js.map +0 -1
- package/dist/journal/session-journal.d.ts.map +0 -1
- package/dist/journal/session-journal.js.map +0 -1
- package/dist/license/license.d.ts.map +0 -1
- package/dist/license/license.js.map +0 -1
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/mcp-proxy.d.ts.map +0 -1
- package/dist/mcp-proxy.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
- package/dist/oracles/flow-instrument-gaps.js.map +0 -1
- package/dist/oracles/propose-consequences.d.ts.map +0 -1
- package/dist/oracles/propose-consequences.js.map +0 -1
- package/dist/oracles/self-instrument.d.ts.map +0 -1
- package/dist/oracles/self-instrument.js.map +0 -1
- package/dist/pairing-token.d.ts.map +0 -1
- package/dist/pairing-token.js.map +0 -1
- package/dist/phenomena/phenomena.d.ts.map +0 -1
- package/dist/phenomena/phenomena.js.map +0 -1
- package/dist/pool/browser-pool.d.ts.map +0 -1
- package/dist/pool/browser-pool.js.map +0 -1
- package/dist/pool/lease-reaper.d.ts.map +0 -1
- package/dist/pool/lease-reaper.js.map +0 -1
- package/dist/pool/playwright-launcher.d.ts.map +0 -1
- package/dist/pool/playwright-launcher.js.map +0 -1
- package/dist/project/baselines.d.ts.map +0 -1
- package/dist/project/baselines.js.map +0 -1
- package/dist/project/file-lock.d.ts.map +0 -1
- package/dist/project/file-lock.js.map +0 -1
- package/dist/project/fs-port.d.ts.map +0 -1
- package/dist/project/fs-port.js.map +0 -1
- package/dist/project/project-store.d.ts.map +0 -1
- package/dist/project/project-store.js.map +0 -1
- package/dist/project/project-tools.d.ts.map +0 -1
- package/dist/project/project-tools.js.map +0 -1
- package/dist/project/reticle-dir.d.ts.map +0 -1
- package/dist/project/reticle-dir.js.map +0 -1
- package/dist/runs/build-verification-run.d.ts.map +0 -1
- package/dist/runs/build-verification-run.js.map +0 -1
- package/dist/runs/profile-redact.d.ts.map +0 -1
- package/dist/runs/profile-redact.js.map +0 -1
- package/dist/runs/render-report.d.ts.map +0 -1
- package/dist/runs/render-report.js.map +0 -1
- package/dist/runs/repair-prompt.d.ts.map +0 -1
- package/dist/runs/repair-prompt.js.map +0 -1
- package/dist/runs/replay-mapping.d.ts.map +0 -1
- package/dist/runs/replay-mapping.js.map +0 -1
- package/dist/runs/reticle-runner.d.ts.map +0 -1
- package/dist/runs/reticle-runner.js.map +0 -1
- package/dist/runs/risk-classify.d.ts.map +0 -1
- package/dist/runs/risk-classify.js.map +0 -1
- package/dist/runs/run-diff.d.ts.map +0 -1
- package/dist/runs/run-diff.js.map +0 -1
- package/dist/runs/run-store.d.ts.map +0 -1
- package/dist/runs/run-store.js.map +0 -1
- package/dist/runs/run-tools.d.ts.map +0 -1
- package/dist/runs/run-tools.js.map +0 -1
- package/dist/runs/runner-port.d.ts.map +0 -1
- package/dist/runs/runner-port.js.map +0 -1
- package/dist/runs/verify-http.d.ts.map +0 -1
- package/dist/runs/verify-http.js.map +0 -1
- package/dist/runs/verify-server.d.ts.map +0 -1
- package/dist/runs/verify-server.js.map +0 -1
- package/dist/server-version.d.ts.map +0 -1
- package/dist/server-version.js.map +0 -1
- package/dist/session/control-envelope.d.ts.map +0 -1
- package/dist/session/control-envelope.js.map +0 -1
- package/dist/session/live-control-tools.d.ts.map +0 -1
- package/dist/session/live-control-tools.js.map +0 -1
- package/dist/session/live-control.d.ts.map +0 -1
- package/dist/session/live-control.js.map +0 -1
- package/dist/session/observed-state.d.ts.map +0 -1
- package/dist/session/observed-state.js.map +0 -1
- package/dist/session/output-budget.d.ts.map +0 -1
- package/dist/session/output-budget.js.map +0 -1
- package/dist/session/presenter-args.d.ts.map +0 -1
- package/dist/session/presenter-args.js.map +0 -1
- package/dist/session/review-store.d.ts.map +0 -1
- package/dist/session/review-store.js.map +0 -1
- package/dist/session/session-health.d.ts.map +0 -1
- package/dist/session/session-health.js.map +0 -1
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/session/session-manager.js.map +0 -1
- package/dist/session/session-readiness.d.ts.map +0 -1
- package/dist/session/session-readiness.js.map +0 -1
- package/dist/session/session-reaper.d.ts.map +0 -1
- package/dist/session/session-reaper.js.map +0 -1
- package/dist/session/session-recommendation.d.ts.map +0 -1
- package/dist/session/session-recommendation.js.map +0 -1
- package/dist/session/session-tools.d.ts.map +0 -1
- package/dist/session/session-tools.js.map +0 -1
- package/dist/session/session.d.ts.map +0 -1
- package/dist/session/session.js.map +0 -1
- package/dist/session/state-select.d.ts.map +0 -1
- package/dist/session/state-select.js.map +0 -1
- package/dist/token-auth.d.ts.map +0 -1
- package/dist/token-auth.js.map +0 -1
- package/dist/tools/act-tools.d.ts.map +0 -1
- package/dist/tools/act-tools.js.map +0 -1
- package/dist/tools/act-view.d.ts.map +0 -1
- package/dist/tools/act-view.js.map +0 -1
- package/dist/tools/assert-grade.d.ts.map +0 -1
- package/dist/tools/assert-grade.js.map +0 -1
- package/dist/tools/browser-tools.d.ts.map +0 -1
- package/dist/tools/browser-tools.js.map +0 -1
- package/dist/tools/contract-tools.d.ts.map +0 -1
- package/dist/tools/contract-tools.js.map +0 -1
- package/dist/tools/dynamic-tools.d.ts.map +0 -1
- package/dist/tools/dynamic-tools.js.map +0 -1
- package/dist/tools/error-recovery.d.ts.map +0 -1
- package/dist/tools/error-recovery.js.map +0 -1
- package/dist/tools/invoke-tool.d.ts.map +0 -1
- package/dist/tools/invoke-tool.js.map +0 -1
- package/dist/tools/lease-tools.d.ts.map +0 -1
- package/dist/tools/lease-tools.js.map +0 -1
- package/dist/tools/merge-tools.d.ts.map +0 -1
- package/dist/tools/merge-tools.js.map +0 -1
- package/dist/tools/observe-tools.d.ts.map +0 -1
- package/dist/tools/observe-tools.js.map +0 -1
- package/dist/tools/profiles.d.ts.map +0 -1
- package/dist/tools/profiles.js.map +0 -1
- package/dist/tools/query-paginate.d.ts.map +0 -1
- package/dist/tools/query-paginate.js.map +0 -1
- package/dist/tools/read-tools.d.ts.map +0 -1
- package/dist/tools/read-tools.js.map +0 -1
- package/dist/tools/snapshot-delta.d.ts.map +0 -1
- package/dist/tools/snapshot-delta.js.map +0 -1
- package/dist/tools/tool-invoker.d.ts.map +0 -1
- package/dist/tools/tool-invoker.js.map +0 -1
- package/dist/tools/tool-kit.d.ts.map +0 -1
- package/dist/tools/tool-kit.js.map +0 -1
- package/dist/tools/tool-names.d.ts.map +0 -1
- package/dist/tools/tool-names.js.map +0 -1
- package/dist/tools/tools-helpers.d.ts.map +0 -1
- package/dist/tools/tools-helpers.js.map +0 -1
- package/dist/tools/tools.d.ts.map +0 -1
- package/dist/tools/tools.js.map +0 -1
- package/dist/update/update-checker.d.ts.map +0 -1
- package/dist/update/update-checker.js.map +0 -1
- package/dist/update/updater.d.ts.map +0 -1
- package/dist/update/updater.js.map +0 -1
- package/dist/visual/visual-diff.d.ts.map +0 -1
- package/dist/visual/visual-diff.js.map +0 -1
- package/dist/visual/visual-store.d.ts.map +0 -1
- package/dist/visual/visual-store.js.map +0 -1
- package/dist/visual/visual-tools.d.ts.map +0 -1
- package/dist/visual/visual-tools.js.map +0 -1
package/dist/flows/replay.js
CHANGED
|
@@ -64,6 +64,24 @@ export function compileActStep(args, res) {
|
|
|
64
64
|
testidArgs['source'] = source;
|
|
65
65
|
return { tool: ReticleTool.ACT, stable: true, args: testidArgs };
|
|
66
66
|
}
|
|
67
|
+
// Role + NAME before component: a component/source anchor names the JSX site, so every row's copy
|
|
68
|
+
// of the same control collapses onto it. The accessible name separates them, and it is also the
|
|
69
|
+
// only stable anchor an app with no testids has. Measured: three rows' checkboxes compiled to one
|
|
70
|
+
// identical component anchor and replayed onto a single element.
|
|
71
|
+
const role = asString(r['role']);
|
|
72
|
+
const name = asString(r['name']);
|
|
73
|
+
if (role !== undefined && name !== undefined) {
|
|
74
|
+
const roleArgs = {
|
|
75
|
+
by: QueryBy.ROLE,
|
|
76
|
+
value: role,
|
|
77
|
+
name,
|
|
78
|
+
action,
|
|
79
|
+
args: actArgs,
|
|
80
|
+
};
|
|
81
|
+
if (source !== undefined)
|
|
82
|
+
roleArgs['source'] = source;
|
|
83
|
+
return { tool: ReticleTool.ACT, stable: true, args: roleArgs };
|
|
84
|
+
}
|
|
67
85
|
const component = asString(r['component']);
|
|
68
86
|
if (component !== undefined || source !== undefined) {
|
|
69
87
|
const componentArgs = { by: QueryBy.COMPONENT, action, args: actArgs };
|
|
@@ -99,7 +117,16 @@ export function compileSequenceStep(args, res) {
|
|
|
99
117
|
});
|
|
100
118
|
return { tool: ReticleTool.ACT_SEQUENCE, stable, args: { steps: subSteps } };
|
|
101
119
|
}
|
|
102
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a recorded step's element to a live ref, by whichever anchor the compiler chose.
|
|
122
|
+
*
|
|
123
|
+
* Every anchor the compiler can EMIT must be resolvable here. It could not be: `compileActStep`
|
|
124
|
+
* emits `by: component` steps (and marks them `stable: true`), and this function only understood
|
|
125
|
+
* `testid` — so every component-anchored step failed with "no testid or ref to resolve", and the
|
|
126
|
+
* `stable` flag on it was a claim the replayer could not honour. Measured on a console with 5 steps:
|
|
127
|
+
* the 2 with testids replayed, the 3 without were unreplayable, and the flow reported ok:false at
|
|
128
|
+
* the first of them.
|
|
129
|
+
*/
|
|
103
130
|
async function resolveRef(session, step) {
|
|
104
131
|
const by = asString(step.by);
|
|
105
132
|
const value = asString(step.value);
|
|
@@ -113,9 +140,50 @@ async function resolveRef(session, step) {
|
|
|
113
140
|
throw new Error(`testid '${value}' did not resolve in current page`);
|
|
114
141
|
return refs.length > 1 ? { ref, note: ambiguousTestidNote(value) } : { ref };
|
|
115
142
|
}
|
|
143
|
+
// Role + accessible NAME: the anchor that distinguishes one row's control from another's, which
|
|
144
|
+
// neither a testid-less app nor a shared JSX source location can do.
|
|
145
|
+
if (by === QueryBy.ROLE && value !== undefined) {
|
|
146
|
+
const name = asString(step.name);
|
|
147
|
+
const query = { by, value, ...(name === undefined ? {} : { name }) };
|
|
148
|
+
const result = await session.command(ReticleCommand.QUERY, query);
|
|
149
|
+
if (!result.ok)
|
|
150
|
+
throw new Error(result.error ?? 'query failed');
|
|
151
|
+
const ref = queryRefs(result)[0];
|
|
152
|
+
if (ref === undefined) {
|
|
153
|
+
throw new Error(`${value} named '${String(name)}' did not resolve in current page`);
|
|
154
|
+
}
|
|
155
|
+
return { ref };
|
|
156
|
+
}
|
|
157
|
+
if (by === QueryBy.COMPONENT) {
|
|
158
|
+
const component = asString(step.component);
|
|
159
|
+
const source = step.source;
|
|
160
|
+
const query = {
|
|
161
|
+
by,
|
|
162
|
+
...(component === undefined ? {} : { component, value: component }),
|
|
163
|
+
...(source === undefined ? {} : { source }),
|
|
164
|
+
};
|
|
165
|
+
const result = await session.command(ReticleCommand.QUERY, query);
|
|
166
|
+
if (!result.ok)
|
|
167
|
+
throw new Error(result.error ?? 'query failed');
|
|
168
|
+
const refs = queryRefs(result);
|
|
169
|
+
const ref = refs[0];
|
|
170
|
+
if (ref === undefined) {
|
|
171
|
+
throw new Error(`component '${String(component)}' did not resolve in current page`);
|
|
172
|
+
}
|
|
173
|
+
// A source location identifies a JSX SITE, not an instance: one `<input>` inside a row renders
|
|
174
|
+
// once per row and every one of them shares this anchor. Saying so is the difference between a
|
|
175
|
+
// replay that repeated itself and a replay that reports it might have.
|
|
176
|
+
return refs.length > 1
|
|
177
|
+
? {
|
|
178
|
+
ref,
|
|
179
|
+
note: `component anchor matched ${String(refs.length)} elements — replayed the first`,
|
|
180
|
+
}
|
|
181
|
+
: { ref };
|
|
182
|
+
}
|
|
116
183
|
const ref = asString(step.ref);
|
|
117
|
-
if (ref === undefined || ref.length === 0)
|
|
118
|
-
throw new Error('step has no testid
|
|
184
|
+
if (ref === undefined || ref.length === 0) {
|
|
185
|
+
throw new Error('step has no resolvable anchor (testid, role+name, component) and no ref');
|
|
186
|
+
}
|
|
119
187
|
return { ref, note: 'replayed by stale ref (not portable across sessions)' };
|
|
120
188
|
}
|
|
121
189
|
/** Re-execute every step of a compiled program in order, stopping at the first failure. */
|
|
@@ -190,4 +258,3 @@ function buildResult(tool, ok, error, notes) {
|
|
|
190
258
|
base.note = notes.join('; ');
|
|
191
259
|
return base;
|
|
192
260
|
}
|
|
193
|
-
//# sourceMappingURL=replay.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verify:server delegation. When a project's cloud config sets `verify: 'server'`, the FLOW_VERIFY tool
|
|
3
|
+
* runs the suite on the hosted runner (POST /v1/verifications) instead of replaying in the local browser,
|
|
4
|
+
* and maps the server's report back into the SAME SuiteVerdict the local path returns — so the agent's
|
|
5
|
+
* contract is identical either way. Falls back to local (returns null) when not attached, wrong mode, or
|
|
6
|
+
* there is no reachable preview URL for the server to hit.
|
|
7
|
+
*/
|
|
8
|
+
import type { SuiteVerdict } from '@reticlehq/core';
|
|
9
|
+
import type { ToolDeps } from '../tools/tools.js';
|
|
10
|
+
import { type ProjectCloud } from './../cloud/cloud-config.js';
|
|
11
|
+
import { type ServerVerification } from '../cloud/cloud-sync.js';
|
|
12
|
+
/** Map the hosted runner's report onto the local suite-verdict shape (status/total/passed/failed/failures). */
|
|
13
|
+
export declare function toSuiteVerdict(report: ServerVerification): SuiteVerdict;
|
|
14
|
+
/** Run the suite on the hosted runner, or null to signal the caller should replay locally. */
|
|
15
|
+
export declare function runServerVerify(deps: ToolDeps, cloud: ProjectCloud, sessionId: string | undefined, flows: string[]): Promise<SuiteVerdict | null>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { VerifyMode } from './../cloud/cloud-config.js';
|
|
2
|
+
import { submitServerVerification } from '../cloud/cloud-sync.js';
|
|
3
|
+
const PASS = 'pass';
|
|
4
|
+
const UNVERIFIED = 'unverified';
|
|
5
|
+
const SOURCE = 'reticle-mcp';
|
|
6
|
+
/** Map the hosted runner's report onto the local suite-verdict shape (status/total/passed/failed/failures). */
|
|
7
|
+
export function toSuiteVerdict(report) {
|
|
8
|
+
const failures = report.flows
|
|
9
|
+
.filter((f) => f.status !== PASS)
|
|
10
|
+
.map((f) => ({
|
|
11
|
+
flow: f.name,
|
|
12
|
+
verdict: 'fail',
|
|
13
|
+
nextAction: `verified on the server — see report ${report.verificationId}`,
|
|
14
|
+
}));
|
|
15
|
+
const total = report.flows.length;
|
|
16
|
+
const passed = total - failures.length;
|
|
17
|
+
const status = report.verdict === PASS && failures.length === 0 ? 'pass' : 'fail';
|
|
18
|
+
return { status, total, passed, failed: failures.length, summary: report.summary, failures };
|
|
19
|
+
}
|
|
20
|
+
/** Run the suite on the hosted runner, or null to signal the caller should replay locally. */
|
|
21
|
+
export async function runServerVerify(deps, cloud, sessionId, flows) {
|
|
22
|
+
if (cloud.verify !== VerifyMode.SERVER || cloud.config === null)
|
|
23
|
+
return null;
|
|
24
|
+
let previewUrl;
|
|
25
|
+
try {
|
|
26
|
+
previewUrl = deps.sessions.resolve(sessionId).url;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
previewUrl = undefined;
|
|
30
|
+
}
|
|
31
|
+
// The server hits the URL itself; with no URL (or a localhost one it can't reach) fall back to local.
|
|
32
|
+
if (previewUrl === undefined || previewUrl.length === 0)
|
|
33
|
+
return null;
|
|
34
|
+
const report = await submitServerVerification({ previewUrl, flows, source: SOURCE }, cloud.config, (url, init) => fetch(url, init));
|
|
35
|
+
if (report === null)
|
|
36
|
+
return null;
|
|
37
|
+
// The hosted runner said it couldn't actually verify (e.g. it's not enabled yet). Never surface that as
|
|
38
|
+
// a pass or a fail — fall back to the real local replay so the verdict reflects a browser that ran.
|
|
39
|
+
if (report.verdict === UNVERIFIED)
|
|
40
|
+
return null;
|
|
41
|
+
return toSuiteVerdict(report);
|
|
42
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { Verified } from '@reticlehq/core';
|
|
3
|
+
import { ReticleTool } from '../tools/tool-names.js';
|
|
4
|
+
import { asNumber, asRecord, asString } from '../tools/tools-helpers.js';
|
|
5
|
+
import { loadNamedFlows, resolveChangedFiles } from '../cli-flow-commands.js';
|
|
6
|
+
import { affectedSavedFlows } from './flow-sources.js';
|
|
7
|
+
import { FLOW_TOOLS } from './flow-tools.js';
|
|
8
|
+
import { findContradictions } from '../events/contradictions.js';
|
|
9
|
+
import { parseControls } from '../tools/coverage-tools.js';
|
|
10
|
+
import { ReticleCommand, SnapshotMode } from '@reticlehq/core';
|
|
11
|
+
const PASS = 'pass';
|
|
12
|
+
export const VERIFY_CHANGE_TOOLS = [
|
|
13
|
+
{
|
|
14
|
+
name: ReticleTool.VERIFY_CHANGE,
|
|
15
|
+
description: 'Did my change break anything? Give it the files you edited (or `since` for a git ref) and it works out which saved flows cover them, replays exactly those, and answers with one `verified` (yes|no|unknown) plus `because`. `unknown` when NO saved flow covers the change — that is the honest answer, never a green: nothing ran, so nothing was proved. Returns { verified, because, changedFiles, flowsRun, suite, unknownProvenance }.',
|
|
16
|
+
example: { files: ['src/App.tsx'] },
|
|
17
|
+
inputSchema: {
|
|
18
|
+
files: z
|
|
19
|
+
.array(z.string())
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Changed file paths, repo-relative (e.g. ["src/App.tsx"]).'),
|
|
22
|
+
since: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Git ref to diff against (e.g. "HEAD~1", "main"). Unioned with `files`.'),
|
|
26
|
+
parallel: z
|
|
27
|
+
.number()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Replay this many affected flows at once (needs the browser pool).'),
|
|
30
|
+
sessionId: z
|
|
31
|
+
.string()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('OMIT THIS unless you mean a specific tab — Reticle resolves it.'),
|
|
34
|
+
},
|
|
35
|
+
outputSchema: {
|
|
36
|
+
verified: z
|
|
37
|
+
.string()
|
|
38
|
+
.describe('yes | no | unknown. `unknown` means the evidence could not decide — most often that no saved flow covers these files, which is NOT a pass.'),
|
|
39
|
+
because: z.string(),
|
|
40
|
+
changedFiles: z.array(z.string()),
|
|
41
|
+
flowsRun: z.array(z.string()),
|
|
42
|
+
suite: z.unknown().optional(),
|
|
43
|
+
// Session-EXEMPT: declare the one-shot human feedback ask or a validating profile strips it.
|
|
44
|
+
feedback_prompt: z.unknown().optional(),
|
|
45
|
+
unknownProvenance: z.array(z.string()),
|
|
46
|
+
contradictions: z
|
|
47
|
+
.array(z.unknown())
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Channels that disagreed DURING the replay. Any entry forces verified:"no" even when every flow passed — a suite that goes green over a failed write is the false green this exists to catch. OMITTED when clean; see `measured` when it could not be looked for.'),
|
|
50
|
+
untouched: z
|
|
51
|
+
.array(z.unknown())
|
|
52
|
+
.optional()
|
|
53
|
+
.describe('Controls on the page that the covering flows never drove. A green over a small untouched list is stronger evidence than the same green over a large one.'),
|
|
54
|
+
measured: z
|
|
55
|
+
.array(z.string())
|
|
56
|
+
.describe('What was actually looked for. An absent `contradictions` means "none found" ONLY if "contradictions" appears here — otherwise it was never measured.'),
|
|
57
|
+
},
|
|
58
|
+
handler: async (deps, args) => {
|
|
59
|
+
const files = Array.isArray(args['files'])
|
|
60
|
+
? args['files'].filter((f) => typeof f === 'string')
|
|
61
|
+
: [];
|
|
62
|
+
const since = asString(args['since']);
|
|
63
|
+
const changedFiles = await resolveChangedFiles(files, since);
|
|
64
|
+
const flows = await loadNamedFlows(deps.fs, deps.reticleRoot);
|
|
65
|
+
const { affected, unknownProvenance } = affectedSavedFlows(flows, changedFiles);
|
|
66
|
+
if (changedFiles.length === 0) {
|
|
67
|
+
return {
|
|
68
|
+
verified: Verified.UNKNOWN,
|
|
69
|
+
because: 'no changed files were given, so there was nothing to decide about',
|
|
70
|
+
changedFiles,
|
|
71
|
+
flowsRun: [],
|
|
72
|
+
unknownProvenance,
|
|
73
|
+
// Nothing was looked for, and the schema requires this field to say so. Omitting it made
|
|
74
|
+
// the MCP layer reject the whole response, turning an honest UNKNOWN into a protocol error.
|
|
75
|
+
measured: [],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// The guard: an uncovered change is UNKNOWN. Reporting `yes` here would mean "your change is
|
|
79
|
+
// fine" on the strength of having run nothing at all.
|
|
80
|
+
if (affected.length === 0) {
|
|
81
|
+
return {
|
|
82
|
+
verified: Verified.UNKNOWN,
|
|
83
|
+
because: `no saved flow covers ${changedFiles.length === 1 ? 'this file' : 'these files'} — record one with reticle_record { action: "start" } then reticle_flow_save, or verify by driving the app directly`,
|
|
84
|
+
changedFiles,
|
|
85
|
+
flowsRun: [],
|
|
86
|
+
unknownProvenance,
|
|
87
|
+
// No flow ran, so nothing was measured — said explicitly rather than left undefined.
|
|
88
|
+
measured: [],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const provenanceNote = unknownProvenance.length > 0
|
|
92
|
+
? ` (${String(unknownProvenance.length)} of them re-run only because Reticle cannot tell which sources they cover)`
|
|
93
|
+
: '';
|
|
94
|
+
// Marked BEFORE the replay so the contradiction sweep afterwards reads exactly the window the
|
|
95
|
+
// flows produced, and never events from whatever the agent did before calling this.
|
|
96
|
+
const cursor = cursorBeforeReplay(deps, args);
|
|
97
|
+
const verify = FLOW_TOOLS.find((tool) => tool.name === ReticleTool.FLOW_VERIFY);
|
|
98
|
+
if (verify === undefined)
|
|
99
|
+
throw new Error('reticle_flow_verify is not registered');
|
|
100
|
+
const suite = asRecord(await verify.handler(deps, {
|
|
101
|
+
names: affected,
|
|
102
|
+
...(asNumber(args['parallel']) === undefined ? {} : { parallel: args['parallel'] }),
|
|
103
|
+
...(asString(args['sessionId']) === undefined ? {} : { sessionId: args['sessionId'] }),
|
|
104
|
+
}));
|
|
105
|
+
const failed = suite.failed ?? 0;
|
|
106
|
+
const passed = suite.passed ?? 0;
|
|
107
|
+
const failedSuite = suite.status !== PASS || failed > 0;
|
|
108
|
+
if (failedSuite) {
|
|
109
|
+
return {
|
|
110
|
+
verified: Verified.NO,
|
|
111
|
+
because: `${String(failed)} of ${String(suite.total ?? affected.length)} covering flows failed${provenanceNote}`,
|
|
112
|
+
changedFiles,
|
|
113
|
+
flowsRun: affected,
|
|
114
|
+
suite,
|
|
115
|
+
unknownProvenance,
|
|
116
|
+
measured: ['flows'],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// The suite went green. That is exactly when the remaining two channels are worth reading:
|
|
120
|
+
// a replay that passes while a write fails is the false green this whole product is about.
|
|
121
|
+
const extra = await inspectAfterReplay(deps, args, cursor);
|
|
122
|
+
if (extra.contradictions.length > 0) {
|
|
123
|
+
const kinds = extra.contradictions.map((c) => c.kind).join(', ');
|
|
124
|
+
return {
|
|
125
|
+
verified: Verified.NO,
|
|
126
|
+
because: `every covering flow passed, but channels disagreed during the replay (${kinds}) — a green suite over a failed write is the false green worth looking at${provenanceNote}`,
|
|
127
|
+
changedFiles,
|
|
128
|
+
flowsRun: affected,
|
|
129
|
+
suite,
|
|
130
|
+
unknownProvenance,
|
|
131
|
+
contradictions: extra.contradictions,
|
|
132
|
+
...(extra.untouched === undefined ? {} : { untouched: extra.untouched }),
|
|
133
|
+
measured: extra.measured,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
verified: Verified.YES,
|
|
138
|
+
because: `all ${String(passed)} flows covering these files passed${provenanceNote}${extra.untouched === undefined ? '' : `, with ${String(extra.untouched.length)} controls left undriven`}`,
|
|
139
|
+
changedFiles,
|
|
140
|
+
flowsRun: affected,
|
|
141
|
+
suite,
|
|
142
|
+
unknownProvenance,
|
|
143
|
+
...(extra.untouched === undefined ? {} : { untouched: extra.untouched }),
|
|
144
|
+
measured: extra.measured,
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
/** The event cursor to sweep from, or 0 when there is no readable session (nothing to sweep). */
|
|
150
|
+
function cursorBeforeReplay(deps, args) {
|
|
151
|
+
try {
|
|
152
|
+
return deps.sessions.resolve(asString(args['sessionId'])).elapsed();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Read the two channels a suite verdict cannot see: did anything DISAGREE during the replay, and
|
|
160
|
+
* what did the flows never touch.
|
|
161
|
+
*
|
|
162
|
+
* Both are skipped when the flows ran in parallel leased contexts, because the events and driven
|
|
163
|
+
* refs then belong to those leases rather than to the session read here. Reporting "no
|
|
164
|
+
* contradictions" from the wrong session would be a false green produced by the false-green
|
|
165
|
+
* detector, so `measured` states what was actually looked for and the caller is never left to infer
|
|
166
|
+
* it from an absent field.
|
|
167
|
+
*/
|
|
168
|
+
async function inspectAfterReplay(deps, args, cursor) {
|
|
169
|
+
if (asNumber(args['parallel']) !== undefined) {
|
|
170
|
+
return { contradictions: [], measured: ['flows'] };
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
174
|
+
const contradictions = findContradictions(session.eventsSince(cursor));
|
|
175
|
+
const snapshot = await session.command(ReticleCommand.SNAPSHOT, {
|
|
176
|
+
mode: SnapshotMode.INTERACTIVE,
|
|
177
|
+
});
|
|
178
|
+
const tree = snapshot.ok ? (asString(asRecord(snapshot.result)['tree']) ?? '') : '';
|
|
179
|
+
const acted = session.actedRefs();
|
|
180
|
+
const untouched = parseControls(tree).filter((c) => !acted.has(c.ref));
|
|
181
|
+
return { contradictions, untouched, measured: ['flows', 'contradictions', 'coverage'] };
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// A session that went away after the replay is not evidence of cleanliness.
|
|
185
|
+
return { contradictions: [], measured: ['flows'] };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* Did a write in this window answer `202 Accepted`?
|
|
4
|
+
*
|
|
5
|
+
* `202` is the only status in HTTP whose meaning is "no outcome yet" — the server took the request
|
|
6
|
+
* and has not finished with it. Folding it into the 2xx success band is how an asynchronous workflow
|
|
7
|
+
* gets a green verdict at exactly the moment nothing has been decided.
|
|
8
|
+
*
|
|
9
|
+
* Measured on a logistics console with server-side reconciliation: a dispatch answered 202, the row
|
|
10
|
+
* optimistically rendered "dispatched", the page settled, every channel agreed — and the server
|
|
11
|
+
* REVERTED it to `held` 1.2 s later. The verdict was not wrong about what it observed. It was early,
|
|
12
|
+
* and nothing in the response said so except the status code nobody was reading.
|
|
13
|
+
*/
|
|
14
|
+
export declare function hasAcceptedWrite(events: readonly ReticleEvent[]): boolean;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EventType, HTTP_ACCEPTED } from '@reticlehq/core';
|
|
2
|
+
import { asNumber } from '../tools/tools-helpers.js';
|
|
3
|
+
/**
|
|
4
|
+
* Did a write in this window answer `202 Accepted`?
|
|
5
|
+
*
|
|
6
|
+
* `202` is the only status in HTTP whose meaning is "no outcome yet" — the server took the request
|
|
7
|
+
* and has not finished with it. Folding it into the 2xx success band is how an asynchronous workflow
|
|
8
|
+
* gets a green verdict at exactly the moment nothing has been decided.
|
|
9
|
+
*
|
|
10
|
+
* Measured on a logistics console with server-side reconciliation: a dispatch answered 202, the row
|
|
11
|
+
* optimistically rendered "dispatched", the page settled, every channel agreed — and the server
|
|
12
|
+
* REVERTED it to `held` 1.2 s later. The verdict was not wrong about what it observed. It was early,
|
|
13
|
+
* and nothing in the response said so except the status code nobody was reading.
|
|
14
|
+
*/
|
|
15
|
+
export function hasAcceptedWrite(events) {
|
|
16
|
+
return events.some((e) => e.type === EventType.NET_REQUEST && asNumber(e.data['status']) === HTTP_ACCEPTED);
|
|
17
|
+
}
|
|
@@ -16,6 +16,24 @@ export interface CoverageStatement {
|
|
|
16
16
|
note?: string;
|
|
17
17
|
spots: BlindSpot[];
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Blind spots that IMPEACH the capture, as opposed to bounding what it covers.
|
|
21
|
+
*
|
|
22
|
+
* The distinction decides whether a verdict is downgraded to UNKNOWN or merely carries a caveat, and
|
|
23
|
+
* conflating them breaks the tool in one direction or the other:
|
|
24
|
+
*
|
|
25
|
+
* - **Impeaching**: events were DROPPED, so the window itself is a sample and any claim over it may
|
|
26
|
+
* be a false negative. Nothing observed can be trusted to be complete.
|
|
27
|
+
* - **Bounding**: a region is structurally unobservable — a cross-origin frame, a closed shadow
|
|
28
|
+
* root, the 9,970 virtualized rows that were never rendered. What WAS observed is completely and
|
|
29
|
+
* correctly observed; there is simply a boundary, and it is usually permanent.
|
|
30
|
+
*
|
|
31
|
+
* Treating the second kind as impeaching made every verdict on any virtualized list UNKNOWN — which
|
|
32
|
+
* is most data-heavy software, permanently. A tool that answers "unknown" to everything is as
|
|
33
|
+
* useless as one that answers "yes" to everything, and it is the same failure: a verdict that does
|
|
34
|
+
* not depend on the evidence.
|
|
35
|
+
*/
|
|
36
|
+
export declare function impeachesCapture(kind: BlindSpotKind): boolean;
|
|
19
37
|
/** Compose the coverage statement. `full` (no note) when nothing was unobserved. */
|
|
20
38
|
export declare function buildCoverageStatement(spots: readonly BlindSpot[]): CoverageStatement;
|
|
21
39
|
/**
|
|
@@ -34,4 +52,3 @@ export declare function blindSpotsFromEvents(events: readonly ReticleEvent[]): B
|
|
|
34
52
|
* from what happened to be said recently.
|
|
35
53
|
*/
|
|
36
54
|
export declare function blindSpotsFromState(state: Readonly<Record<string, number>>): BlindSpot[];
|
|
37
|
-
//# sourceMappingURL=blind-spots.d.ts.map
|
|
@@ -9,19 +9,62 @@
|
|
|
9
9
|
export { BlindSpotKind } from '@reticlehq/core';
|
|
10
10
|
import { BlindSpotKind, EventType } from '@reticlehq/core';
|
|
11
11
|
const LABEL = {
|
|
12
|
-
[BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${n === 1 ? '' : 's'}`,
|
|
13
|
-
[BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${n === 1 ? '' : 's'}`,
|
|
14
|
-
|
|
12
|
+
[BlindSpotKind.CLOSED_SHADOW_ROOT]: (n) => `${String(n)} closed shadow root${n === 1 ? '' : 's'} unobserved`,
|
|
13
|
+
[BlindSpotKind.CROSS_ORIGIN_IFRAME]: (n) => `${String(n)} cross-origin frame${n === 1 ? '' : 's'} unobserved`,
|
|
14
|
+
// The DOM of these frames IS observed; only their network is not. Saying so precisely matters — a
|
|
15
|
+
// flat "unobserved" would discard a real capability and push agents back to guessing.
|
|
16
|
+
[BlindSpotKind.UNINSTRUMENTED_FRAME]: (n) => `${String(n)} same-origin frame${n === 1 ? '' : 's'} observed for DOM but not network — requests they make are invisible`,
|
|
17
|
+
[BlindSpotKind.VIRTUALIZED_UNMOUNTED]: (n) => `${String(n)} virtualized unmounted row${n === 1 ? '' : 's'} unobserved`,
|
|
18
|
+
// Not "some rows we could not see" — the events never reached the observer, so this window is a
|
|
19
|
+
// SAMPLE of what the app did. Phrased as a caveat on what the whole result MEANS.
|
|
20
|
+
[BlindSpotKind.RATE_LIMITED]: (n) => `${String(n)} event${n === 1 ? '' : 's'} dropped by the bridge rate cap, so this window is SAMPLED — raise RETICLE_MAX_MESSAGES_PER_SECOND for a busy app`,
|
|
15
21
|
// Not a count of things — a single fact about the page. Phrased so the coverage line reads as a
|
|
16
22
|
// caveat on what the network view MEANS, not as a tally.
|
|
23
|
+
// A count of unverifiable ACTIONS, not of things we failed to look at. The distinction matters:
|
|
24
|
+
// nothing here was missed, there was simply never a verdict to observe, and no amount of extra
|
|
25
|
+
// instrumentation would produce one.
|
|
26
|
+
[BlindSpotKind.VERDICTLESS_SEND]: (n) => `${String(n)} one-way IPC send${n === 1 ? '' : 's'} dispatched with NO verdict — the renderer never learns whether the main process handled ${n === 1 ? 'it' : 'them'}, so this cannot be confirmed from the page`,
|
|
17
27
|
[BlindSpotKind.WRAPPED_NETWORK]: () => 'fetch was already wrapped before Reticle, so recorded requests may differ from what was sent',
|
|
28
|
+
// A fact about the app's wiring, not a tally. Says what the empty network view MEANS, because an
|
|
29
|
+
// empty one here is indistinguishable from "this app made no backend calls" — and that reading is
|
|
30
|
+
// the false green: every IPC call went unseen and every `assert { net }` over them is vacuous.
|
|
31
|
+
[BlindSpotKind.UNOBSERVED_IPC]: () => "this Electron renderer has no Reticle preload, so NO ipcRenderer.invoke is observed — an empty network view here means unseen, not none (add require('@reticlehq/electron/preload') to your preload)",
|
|
18
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Blind spots that IMPEACH the capture, as opposed to bounding what it covers.
|
|
35
|
+
*
|
|
36
|
+
* The distinction decides whether a verdict is downgraded to UNKNOWN or merely carries a caveat, and
|
|
37
|
+
* conflating them breaks the tool in one direction or the other:
|
|
38
|
+
*
|
|
39
|
+
* - **Impeaching**: events were DROPPED, so the window itself is a sample and any claim over it may
|
|
40
|
+
* be a false negative. Nothing observed can be trusted to be complete.
|
|
41
|
+
* - **Bounding**: a region is structurally unobservable — a cross-origin frame, a closed shadow
|
|
42
|
+
* root, the 9,970 virtualized rows that were never rendered. What WAS observed is completely and
|
|
43
|
+
* correctly observed; there is simply a boundary, and it is usually permanent.
|
|
44
|
+
*
|
|
45
|
+
* Treating the second kind as impeaching made every verdict on any virtualized list UNKNOWN — which
|
|
46
|
+
* is most data-heavy software, permanently. A tool that answers "unknown" to everything is as
|
|
47
|
+
* useless as one that answers "yes" to everything, and it is the same failure: a verdict that does
|
|
48
|
+
* not depend on the evidence.
|
|
49
|
+
*/
|
|
50
|
+
export function impeachesCapture(kind) {
|
|
51
|
+
return kind === BlindSpotKind.RATE_LIMITED;
|
|
52
|
+
}
|
|
19
53
|
/** Compose the coverage statement. `full` (no note) when nothing was unobserved. */
|
|
20
54
|
export function buildCoverageStatement(spots) {
|
|
21
55
|
const present = spots.filter((s) => s.count > 0);
|
|
22
56
|
if (present.length === 0)
|
|
23
57
|
return { coverage: 'full', spots: [] };
|
|
24
|
-
|
|
58
|
+
// Each label carries its own ending. Appending a blanket " unobserved" here produced
|
|
59
|
+
// "...may differ from what was sent unobserved" for the wrapped-network caveat, which is a
|
|
60
|
+
// sentence rather than a count — and the same dangle appeared the moment a second prose-shaped
|
|
61
|
+
// spot (rate-limited sampling) was added.
|
|
62
|
+
// A kind this daemon does not know about still has to READ as a blind spot. An SDK newer than the
|
|
63
|
+
// daemon can report one, and `LABEL[kind](count)` threw a TypeError on the verdict path when it
|
|
64
|
+
// did — turning "there is something I could not see" into a crashed assert, which is worse than
|
|
65
|
+
// either the caveat or the silence. Unknown kinds degrade to their own name.
|
|
66
|
+
const label = (s) => typeof LABEL[s.kind] === 'function' ? LABEL[s.kind](s.count) : `${s.kind} (${String(s.count)})`;
|
|
67
|
+
const note = `partial — ${present.map(label).join(', ')}`;
|
|
25
68
|
return { coverage: 'partial', note, spots: present };
|
|
26
69
|
}
|
|
27
70
|
/**
|
|
@@ -54,4 +97,3 @@ export function blindSpotsFromEvents(events) {
|
|
|
54
97
|
export function blindSpotsFromState(state) {
|
|
55
98
|
return Object.entries(state).map(([kind, count]) => ({ kind: kind, count }));
|
|
56
99
|
}
|
|
57
|
-
//# sourceMappingURL=blind-spots.js.map
|
package/dist/honesty/honesty.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Say so when a payload exists but was not recorded.
|
|
3
|
+
*
|
|
4
|
+
* A `reticle_network` row for a POST lists method/url/status and nothing else, and an agent reading
|
|
5
|
+
* that has no way to tell "this request had no interesting payload" from "Reticle was not looking at
|
|
6
|
+
* payloads". The second reading is the dangerous one: on a real payments dashboard the defect WAS
|
|
7
|
+
* the payload — a refund POSTing `amount: 1187.01` into a paise field, a 100x under-refund that
|
|
8
|
+
* every other field in the record agrees is a clean 200.
|
|
9
|
+
*
|
|
10
|
+
* So an omission is declared rather than left to inference, with the one line that fixes it. Present
|
|
11
|
+
* only when a body-bearing call was returned AND none of them carried a body, so an app that already
|
|
12
|
+
* captures bodies pays nothing and the field's PRESENCE is the warning.
|
|
13
|
+
*/
|
|
14
|
+
export declare function bodiesNotCaptured(calls: {
|
|
15
|
+
method?: string;
|
|
16
|
+
requestBody?: string;
|
|
17
|
+
}[]): {
|
|
18
|
+
bodiesNotCaptured?: string;
|
|
19
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Methods that normally carry a payload — the ones where a missing body is worth explaining. */
|
|
2
|
+
const BODY_BEARING_METHODS = new Set(['POST', 'PUT', 'PATCH']);
|
|
3
|
+
/**
|
|
4
|
+
* Say so when a payload exists but was not recorded.
|
|
5
|
+
*
|
|
6
|
+
* A `reticle_network` row for a POST lists method/url/status and nothing else, and an agent reading
|
|
7
|
+
* that has no way to tell "this request had no interesting payload" from "Reticle was not looking at
|
|
8
|
+
* payloads". The second reading is the dangerous one: on a real payments dashboard the defect WAS
|
|
9
|
+
* the payload — a refund POSTing `amount: 1187.01` into a paise field, a 100x under-refund that
|
|
10
|
+
* every other field in the record agrees is a clean 200.
|
|
11
|
+
*
|
|
12
|
+
* So an omission is declared rather than left to inference, with the one line that fixes it. Present
|
|
13
|
+
* only when a body-bearing call was returned AND none of them carried a body, so an app that already
|
|
14
|
+
* captures bodies pays nothing and the field's PRESENCE is the warning.
|
|
15
|
+
*/
|
|
16
|
+
export function bodiesNotCaptured(calls) {
|
|
17
|
+
const bodyBearing = calls.filter((c) => BODY_BEARING_METHODS.has((c.method ?? '').toUpperCase()));
|
|
18
|
+
if (bodyBearing.length === 0)
|
|
19
|
+
return {};
|
|
20
|
+
if (bodyBearing.some((c) => c.requestBody !== undefined))
|
|
21
|
+
return {};
|
|
22
|
+
return {
|
|
23
|
+
// Framework-neutral on purpose. The first version named vite.config, and driving a Next.js app
|
|
24
|
+
// returned that advice verbatim for a SERVER ACTION — a POST a Next user cannot fix in a Vite
|
|
25
|
+
// config they do not have. Remediation that does not apply to the reader's stack is worse than
|
|
26
|
+
// none: it sends them to edit a file that is not there and reads as a tool that does not know
|
|
27
|
+
// what it is looking at.
|
|
28
|
+
bodiesNotCaptured: 'request/response bodies are NOT being recorded, so an absent body here means UNSEEN, not empty — the payload of these calls was never inspected. Turn it on where your app calls connect(): `reticle.connect({ captureNetworkBodies: true })`, or for the Vite plugin `reticle({ captureNetworkBodies: true })` / VITE_RETICLE_CAPTURE_BODIES=1. Then re-run the action.',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { EventType, MUTATING_METHODS, NetInitiator } from '@reticlehq/core';
|
|
2
|
+
const IPC_METHOD = NetInitiator.IPC.toUpperCase();
|
|
3
|
+
/**
|
|
4
|
+
* A write whose outcome is sitting in a payload nobody read.
|
|
5
|
+
*
|
|
6
|
+
* `findBodyFailures` catches a 2xx that reports failure inside its body — but only when body capture
|
|
7
|
+
* is on, and it is OFF by default. Without this, the same window produces `verified: "yes"` with the
|
|
8
|
+
* reason "no channel disagreeing", which is true only because one channel was never opened. That is
|
|
9
|
+
* lying by omission, and it is the precise failure this honesty layer exists to prevent.
|
|
10
|
+
*
|
|
11
|
+
* Measured on a shipments console: `POST /api/bulk-hold` → 200, banner reads "9 shipments held",
|
|
12
|
+
* three of the nine failed inside the body. With capture on Reticle now says so. With capture off it
|
|
13
|
+
* said `verified: "yes"`.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately narrow, because over-warning trains agents to ignore the field:
|
|
16
|
+
*
|
|
17
|
+
* - **writes only.** A GET's payload is what the UI renders, so the DOM already witnesses it. A
|
|
18
|
+
* write's outcome has no other witness.
|
|
19
|
+
* - **a payload that DEMONSTRABLY exists.** `responseSize > 0` with no recorded body means unread.
|
|
20
|
+
* An absent size or a genuinely empty response says nothing and is left alone — the distinction
|
|
21
|
+
* between "empty" and "unseen" is the whole point, so it must not be guessed.
|
|
22
|
+
* - **HTTP only.** An IPC record is excluded, and the reason is the rule's own premise: a 2xx is
|
|
23
|
+
* emitted by a framework whatever the app decided, so it describes the transport. An IPC `ok`
|
|
24
|
+
* means the main-process handler ran to completion without throwing — an application-level
|
|
25
|
+
* verdict, already reported. Treating the two as equivalent made every ordinary Electron action
|
|
26
|
+
* return `unknown` (measured: a healthy `todos:add` on the default config), which is the
|
|
27
|
+
* cry-wolf failure that teaches agents to ignore the field.
|
|
28
|
+
*
|
|
29
|
+
* The residual gap is real and narrower: a handler that RESOLVES with a failure inside its payload
|
|
30
|
+
* is invisible without body capture. That case is `findBodyFailures`, which reads the payload and
|
|
31
|
+
* catches it precisely — with capture on, where it belongs.
|
|
32
|
+
*/
|
|
33
|
+
const OK_MIN = 200;
|
|
34
|
+
const OK_MAX = 300;
|
|
35
|
+
export function hasUnreadWriteOutcome(events) {
|
|
36
|
+
return events.some((event) => {
|
|
37
|
+
if (event.type !== EventType.NET_REQUEST)
|
|
38
|
+
return false;
|
|
39
|
+
const method = (typeof event.data['method'] === 'string' ? event.data['method'] : '').toUpperCase();
|
|
40
|
+
if (method === IPC_METHOD || !MUTATING_METHODS.includes(method))
|
|
41
|
+
return false;
|
|
42
|
+
const status = event.data['status'];
|
|
43
|
+
if (typeof status !== 'number' || status < OK_MIN || status >= OK_MAX)
|
|
44
|
+
return false;
|
|
45
|
+
if (event.data['responseBody'] !== undefined)
|
|
46
|
+
return false; // read — findBodyFailures judged it
|
|
47
|
+
const size = event.data['responseSize'];
|
|
48
|
+
return typeof size === 'number' && size > 0;
|
|
49
|
+
});
|
|
50
|
+
}
|