@reticlehq/server 2.2.1 → 2.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/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 +102 -12
- package/dist/bridge.test-harness.d.ts +5 -1
- package/dist/bridge.test-harness.js +12 -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 +47 -3
- package/dist/cli-parse.js +147 -13
- package/dist/cli-port.d.ts +3 -1
- package/dist/cli-port.js +21 -1
- package/dist/cli-verify.d.ts +0 -1
- package/dist/cli-verify.js +1 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +88 -69
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +0 -1
- package/dist/cloud/cloud-sync.d.ts +4 -5
- package/dist/cloud/cloud-sync.js +0 -1
- package/dist/cloud-cli.d.ts +0 -1
- package/dist/cloud-cli.js +9 -2
- 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 +36 -24
- 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 -7
- package/dist/flows/decision.js +47 -7
- 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 +2 -3
- 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 +44 -14
- 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 +0 -1
- package/dist/flows/server-verify.js +0 -1
- 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/capabilities.d.ts +17 -0
- package/dist/init/capabilities.js +51 -0
- 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 +25 -1
- package/dist/init/detect.js +65 -4
- package/dist/init/mcp.d.ts +0 -1
- package/dist/init/mcp.js +0 -1
- package/dist/init/next-patch.d.ts +41 -0
- package/dist/init/next-patch.js +106 -0
- package/dist/init/node-io.d.ts +0 -1
- package/dist/init/node-io.js +25 -1
- package/dist/init/patch-kind.d.ts +20 -0
- package/dist/init/patch-kind.js +10 -0
- package/dist/init/plan-framework.d.ts +35 -0
- package/dist/init/plan-framework.js +217 -0
- package/dist/init/plan.d.ts +55 -4
- package/dist/init/plan.js +130 -112
- package/dist/init/project-id.d.ts +0 -1
- package/dist/init/project-id.js +0 -1
- package/dist/init/run.d.ts +17 -1
- package/dist/init/run.js +237 -18
- package/dist/init/slash-command.d.ts +18 -0
- package/dist/init/slash-command.js +52 -0
- package/dist/init/snippets.d.ts +48 -3
- package/dist/init/snippets.js +156 -6
- package/dist/init/vite-config.d.ts +4 -11
- package/dist/init/vite-config.js +15 -8
- package/dist/input/driven-redaction.d.ts +15 -0
- package/dist/input/driven-redaction.js +76 -0
- package/dist/input/network-detail.d.ts +9 -4
- package/dist/input/network-detail.js +35 -16
- 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 +35 -4
- package/dist/mcp-proxy.js +174 -28
- 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 +0 -1
- package/dist/pool/playwright-launcher.js +10 -2
- package/dist/project/baselines.d.ts +0 -1
- package/dist/project/baselines.js +0 -1
- 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 +0 -1
- package/dist/project/project-tools.d.ts +0 -1
- package/dist/project/project-tools.js +29 -4
- 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 +0 -1
- package/dist/runs/verification-sync.js +0 -1
- 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 +35 -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 +33 -53
- package/dist/session/session.js +102 -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 +35 -8
- package/dist/telemetry/telemetry.js +105 -12
- 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 +115 -5
- 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 +14 -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 +0 -1
- 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-config.d.ts.map +0 -1
- package/dist/cloud/cloud-config.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/cloud-cli.d.ts.map +0 -1
- package/dist/cloud-cli.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/server-verify.d.ts.map +0 -1
- package/dist/flows/server-verify.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/verification-sync.d.ts.map +0 -1
- package/dist/runs/verification-sync.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/telemetry/telemetry.d.ts.map +0 -1
- package/dist/telemetry/telemetry.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
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
import type { Contradiction } from './contradictions.js';
|
|
3
|
+
/** The one contradiction, or none. Reported once per window — a race is a fact about the window. */
|
|
4
|
+
export declare function findStaleResponses(events: readonly ReticleEvent[]): Contradiction[];
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { ContradictionKind, EventType } from '@reticlehq/core';
|
|
2
|
+
function pathOf(url) {
|
|
3
|
+
const q = url.indexOf('?');
|
|
4
|
+
return q === -1 ? url : url.slice(0, q);
|
|
5
|
+
}
|
|
6
|
+
function queryOf(url) {
|
|
7
|
+
const q = url.indexOf('?');
|
|
8
|
+
return q === -1 ? '' : url.slice(q + 1);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parameters that ENUMERATE a collection rather than select within it.
|
|
12
|
+
*
|
|
13
|
+
* Two overlapping reads that differ only in these are a fan-out, not a race: an app fetching page 0
|
|
14
|
+
* and page 5 in parallel wants both, and whichever lands last is not overwriting the other. Measured
|
|
15
|
+
* against a synthetic dashboard doing parallel pagination — every run reported a race, because the
|
|
16
|
+
* requests do overlap and do settle out of order, and the original rule looked no further than that.
|
|
17
|
+
*
|
|
18
|
+
* A filter race differs in a SELECTING parameter (`status`, `q`, a date range): the second request
|
|
19
|
+
* makes the first obsolete, both answer into the same view, and the slower one wins.
|
|
20
|
+
*/
|
|
21
|
+
const ENUMERATING_PARAMS = new Set([
|
|
22
|
+
'page',
|
|
23
|
+
'offset',
|
|
24
|
+
'cursor',
|
|
25
|
+
'limit',
|
|
26
|
+
'size',
|
|
27
|
+
'per_page',
|
|
28
|
+
'perPage',
|
|
29
|
+
'pageSize',
|
|
30
|
+
'after',
|
|
31
|
+
'before',
|
|
32
|
+
'start',
|
|
33
|
+
'end',
|
|
34
|
+
]);
|
|
35
|
+
/** Whether the two queries differ ONLY in how much of the same collection they ask for. */
|
|
36
|
+
function differsOnlyByEnumeration(first, second) {
|
|
37
|
+
const a = new URLSearchParams(first);
|
|
38
|
+
const b = new URLSearchParams(second);
|
|
39
|
+
const keys = new Set([...a.keys(), ...b.keys()]);
|
|
40
|
+
let differed = false;
|
|
41
|
+
for (const key of keys) {
|
|
42
|
+
if (a.get(key) === b.get(key))
|
|
43
|
+
continue;
|
|
44
|
+
if (!ENUMERATING_PARAMS.has(key))
|
|
45
|
+
return false;
|
|
46
|
+
differed = true;
|
|
47
|
+
}
|
|
48
|
+
return differed;
|
|
49
|
+
}
|
|
50
|
+
/** Pair NET_PENDING with its NET_REQUEST by the id both carry. Unpaired events are still in flight. */
|
|
51
|
+
function flights(events) {
|
|
52
|
+
const issued = new Map();
|
|
53
|
+
const out = [];
|
|
54
|
+
for (const event of events) {
|
|
55
|
+
const id = typeof event.data['id'] === 'string' ? event.data['id'] : undefined;
|
|
56
|
+
if (id === undefined)
|
|
57
|
+
continue;
|
|
58
|
+
const at = typeof event.t === 'number' ? event.t : 0;
|
|
59
|
+
if (event.type === EventType.NET_PENDING) {
|
|
60
|
+
const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
|
|
61
|
+
const method = typeof event.data['method'] === 'string' ? event.data['method'] : 'GET';
|
|
62
|
+
issued.set(id, { url, method, at });
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (event.type !== EventType.NET_REQUEST)
|
|
66
|
+
continue;
|
|
67
|
+
const start = issued.get(id);
|
|
68
|
+
if (start === undefined)
|
|
69
|
+
continue; // started before this window — its ordering is unknowable
|
|
70
|
+
out.push({
|
|
71
|
+
id,
|
|
72
|
+
url: start.url,
|
|
73
|
+
method: start.method.toUpperCase(),
|
|
74
|
+
issuedAt: start.at,
|
|
75
|
+
settledAt: at,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Most recent flights compared per endpoint.
|
|
82
|
+
*
|
|
83
|
+
* The comparison is pairwise, so an unbounded window is quadratic: measured at 548ms for 2000
|
|
84
|
+
* concurrent reads of one endpoint, paid on EVERY verdict. A verdict that costs half a second is a
|
|
85
|
+
* verdict agents stop asking for. Racing requests are adjacent in time by definition, so the most
|
|
86
|
+
* recent flights are where a race can be; older ones cannot overlap them anyway.
|
|
87
|
+
*
|
|
88
|
+
* Bounded rather than silent: this is a detection ceiling, not a truncation of reported data — a race
|
|
89
|
+
* among more than this many simultaneous reads of ONE endpoint goes unreported, and that is a
|
|
90
|
+
* deliberate trade for a hot path that runs on every assert.
|
|
91
|
+
*/
|
|
92
|
+
const MAX_FLIGHTS_PER_PATH = 60;
|
|
93
|
+
/** The one contradiction, or none. Reported once per window — a race is a fact about the window. */
|
|
94
|
+
export function findStaleResponses(events) {
|
|
95
|
+
// Grouped by path first: two reads of DIFFERENT endpoints can never race, and comparing them was
|
|
96
|
+
// the bulk of the work on any real page, which talks to many endpoints at once.
|
|
97
|
+
const byPath = new Map();
|
|
98
|
+
for (const flight of flights(events)) {
|
|
99
|
+
if (flight.method !== 'GET')
|
|
100
|
+
continue;
|
|
101
|
+
const path = pathOf(flight.url);
|
|
102
|
+
const group = byPath.get(path) ?? [];
|
|
103
|
+
group.push(flight);
|
|
104
|
+
byPath.set(path, group);
|
|
105
|
+
}
|
|
106
|
+
for (const group of byPath.values()) {
|
|
107
|
+
const reads = group.slice(-MAX_FLIGHTS_PER_PATH);
|
|
108
|
+
const found = raceIn(reads);
|
|
109
|
+
if (found !== undefined)
|
|
110
|
+
return [found];
|
|
111
|
+
}
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
function raceIn(reads) {
|
|
115
|
+
for (const first of reads) {
|
|
116
|
+
for (const second of reads) {
|
|
117
|
+
if (first.id === second.id)
|
|
118
|
+
continue;
|
|
119
|
+
if (second.issuedAt <= first.issuedAt)
|
|
120
|
+
continue; // `first` must be the earlier request
|
|
121
|
+
if (second.issuedAt >= first.settledAt)
|
|
122
|
+
continue; // sequential, not overlapping
|
|
123
|
+
if (second.settledAt >= first.settledAt)
|
|
124
|
+
continue; // settled in order — no race
|
|
125
|
+
if (queryOf(first.url) === queryOf(second.url))
|
|
126
|
+
continue; // a retry, not a superseding query
|
|
127
|
+
// Parallel pagination is not a race — see differsOnlyByEnumeration.
|
|
128
|
+
if (differsOnlyByEnumeration(queryOf(first.url), queryOf(second.url)))
|
|
129
|
+
continue;
|
|
130
|
+
return {
|
|
131
|
+
kind: ContradictionKind.STALE_RESPONSE_APPLIED,
|
|
132
|
+
claim: `both reads of ${pathOf(first.url)} returned successfully and the page settled`,
|
|
133
|
+
counter: `the SUPERSEDED request (${queryOf(first.url)}) settled ${String(Math.max(0, first.settledAt - second.settledAt))}ms AFTER the one that replaced it (${queryOf(second.url)}), so the screen is showing the older query's data`,
|
|
134
|
+
detail: 'a filter/search race: the newer request was issued while the older was still in flight, and the older answered last, so whichever query the server happens to be slower at wins — unless the app cancels superseded requests or drops responses that no longer match current state',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
import type { Contradiction } from './contradictions.js';
|
|
3
|
+
/**
|
|
4
|
+
* @param prior events from BEFORE the window, used only to learn what the API has stated.
|
|
5
|
+
*
|
|
6
|
+
* The scale error is a disagreement with a value the API gave EARLIER — by definition before the
|
|
7
|
+
* action that sends it back. `reticle_assert` scopes its window to the last act's cursor, so the
|
|
8
|
+
* stating response falls outside it and `known` is empty exactly when it matters. Measured live on
|
|
9
|
+
* the payments panel: `reticle_observe` over a wide window reported the mismatch while `assert` on
|
|
10
|
+
* the same session reported none — the verdict tool, the one an agent gates on, was the blind one.
|
|
11
|
+
*
|
|
12
|
+
* Prior events TEACH, they are never themselves findings: widening the window instead would make
|
|
13
|
+
* every other rule blame this action for events it did not cause, and would re-report every earlier
|
|
14
|
+
* mistake on every assert.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findUnitMismatches(events: readonly ReticleEvent[], prior?: readonly ReticleEvent[]): Contradiction[];
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { ContradictionKind, EventType } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* The app sent a money value back in a DIFFERENT unit than the API gave it.
|
|
4
|
+
*
|
|
5
|
+
* Payment APIs overwhelmingly speak minor units — Stripe, Razorpay, Adyen, PayPal all state amounts
|
|
6
|
+
* in paise/cents as integers. A UI renders that as a major-unit string, and the bug is writing the
|
|
7
|
+
* rendered number back into the field the integer came from.
|
|
8
|
+
*
|
|
9
|
+
* Measured on a real payments dashboard: `GET /payments` returns `amount: 118701` for a payment, the
|
|
10
|
+
* row renders "₹1,187.01", and the refund posts `{"amount": 1187.01}` into the same field. The server
|
|
11
|
+
* takes 1187 paise and answers `200 {"status": "processed"}`. That is a 100x UNDER-REFUND, and every
|
|
12
|
+
* channel agrees it worked: the status is 200, the payload says processed, the UI advances, the page
|
|
13
|
+
* settles, and the number in the request is exactly the number on the screen. Nothing disagrees,
|
|
14
|
+
* because the disagreement is with a value the API returned EARLIER in the session.
|
|
15
|
+
*
|
|
16
|
+
* Which is the point: this is only visible to something holding the whole request timeline with
|
|
17
|
+
* bodies. A snapshot cannot see it, a status column cannot see it, and a human reading the request
|
|
18
|
+
* sees the amount they expected.
|
|
19
|
+
*
|
|
20
|
+
* Not a heuristic about decimals. Firing on "an amount had a fractional part" would accuse every API
|
|
21
|
+
* that legitimately uses major units. This fires only when the SAME field of the SAME entity was
|
|
22
|
+
* observed at a different scale — a comparison, not a guess.
|
|
23
|
+
*/
|
|
24
|
+
/** Fields worth comparing. Deliberately short: money, not every number an app sends. */
|
|
25
|
+
const MONEY_FIELDS = new Set(['amount', 'value', 'price', 'total', 'fee', 'cost', 'balance']);
|
|
26
|
+
/**
|
|
27
|
+
* Scales that indicate a minor/major confusion. 100 covers two-decimal currencies; 1000 covers the
|
|
28
|
+
* three-decimal ones (KWD, BHD, JOD, TND).
|
|
29
|
+
*/
|
|
30
|
+
const SCALES = [100, 1000];
|
|
31
|
+
/**
|
|
32
|
+
* Prefixed ids (`pay_NkT10001`) and uuids, matched anywhere in a URL or a string field.
|
|
33
|
+
*
|
|
34
|
+
* Numeric ids are handled separately by path segment: `/api/orders/9/capture` is at least as common
|
|
35
|
+
* as a prefixed id, and a bare `9` cannot be pattern-matched out of arbitrary text without matching
|
|
36
|
+
* every other number too.
|
|
37
|
+
*/
|
|
38
|
+
const ID_PATTERN = /[A-Za-z]{2,}_[A-Za-z0-9]{2,}|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}/g;
|
|
39
|
+
function parse(raw) {
|
|
40
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
41
|
+
return undefined;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(raw);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Every (id, field, value) triple in a payload, from objects that carry an id of their own. */
|
|
50
|
+
function moneyByEntity(node, into) {
|
|
51
|
+
if (Array.isArray(node)) {
|
|
52
|
+
for (const item of node)
|
|
53
|
+
moneyByEntity(item, into);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (typeof node !== 'object' || node === null)
|
|
57
|
+
return;
|
|
58
|
+
const record = node;
|
|
59
|
+
// An id may arrive as a number (`{"id": 9}`) — normalised so a numeric path segment matches it.
|
|
60
|
+
const raw = record['id'];
|
|
61
|
+
const id = typeof raw === 'string' ? raw : typeof raw === 'number' ? String(raw) : undefined;
|
|
62
|
+
if (id !== undefined) {
|
|
63
|
+
for (const [key, value] of Object.entries(record)) {
|
|
64
|
+
if (!MONEY_FIELDS.has(key) || typeof value !== 'number')
|
|
65
|
+
continue;
|
|
66
|
+
const fields = into.get(id) ?? new Map();
|
|
67
|
+
fields.set(key, value);
|
|
68
|
+
into.set(id, fields);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const value of Object.values(record))
|
|
72
|
+
moneyByEntity(value, into);
|
|
73
|
+
}
|
|
74
|
+
/** Ids named anywhere in a URL or a request payload — how a write says which entity it targets. */
|
|
75
|
+
function idsIn(url, body) {
|
|
76
|
+
const found = new Set(url.match(ID_PATTERN) ?? []);
|
|
77
|
+
// Numeric path segments: `/api/orders/9/capture` names entity 9.
|
|
78
|
+
for (const segment of url.split('?')[0]?.split('/') ?? []) {
|
|
79
|
+
if (segment.length > 0 && /^\d+$/.test(segment))
|
|
80
|
+
found.add(segment);
|
|
81
|
+
}
|
|
82
|
+
if (typeof body === 'object' && body !== null) {
|
|
83
|
+
for (const value of Object.values(body)) {
|
|
84
|
+
if (typeof value === 'string')
|
|
85
|
+
for (const id of value.match(ID_PATTERN) ?? [])
|
|
86
|
+
found.add(id);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return Array.from(found);
|
|
90
|
+
}
|
|
91
|
+
/** The scale between a known value and a sent one, or undefined when they are consistent. */
|
|
92
|
+
function scaleBetween(known, sent) {
|
|
93
|
+
if (sent === 0 || known === 0)
|
|
94
|
+
return undefined;
|
|
95
|
+
for (const scale of SCALES) {
|
|
96
|
+
// A tolerance, because the major-unit form is a rounded render of the minor one.
|
|
97
|
+
if (Math.abs(known - sent * scale) <= scale / 2)
|
|
98
|
+
return scale;
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* @param prior events from BEFORE the window, used only to learn what the API has stated.
|
|
104
|
+
*
|
|
105
|
+
* The scale error is a disagreement with a value the API gave EARLIER — by definition before the
|
|
106
|
+
* action that sends it back. `reticle_assert` scopes its window to the last act's cursor, so the
|
|
107
|
+
* stating response falls outside it and `known` is empty exactly when it matters. Measured live on
|
|
108
|
+
* the payments panel: `reticle_observe` over a wide window reported the mismatch while `assert` on
|
|
109
|
+
* the same session reported none — the verdict tool, the one an agent gates on, was the blind one.
|
|
110
|
+
*
|
|
111
|
+
* Prior events TEACH, they are never themselves findings: widening the window instead would make
|
|
112
|
+
* every other rule blame this action for events it did not cause, and would re-report every earlier
|
|
113
|
+
* mistake on every assert.
|
|
114
|
+
*/
|
|
115
|
+
export function findUnitMismatches(events, prior = []) {
|
|
116
|
+
// What the API has told us about each entity so far, in the API's own units.
|
|
117
|
+
const known = new Map();
|
|
118
|
+
for (const event of prior) {
|
|
119
|
+
if (event.type !== EventType.NET_REQUEST)
|
|
120
|
+
continue;
|
|
121
|
+
const body = parse(event.data['responseBody']);
|
|
122
|
+
if (body !== undefined)
|
|
123
|
+
moneyByEntity(body, known);
|
|
124
|
+
}
|
|
125
|
+
const found = [];
|
|
126
|
+
const seen = new Set();
|
|
127
|
+
for (const event of events) {
|
|
128
|
+
if (event.type !== EventType.NET_REQUEST)
|
|
129
|
+
continue;
|
|
130
|
+
const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
|
|
131
|
+
const requestBody = parse(event.data['requestBody']);
|
|
132
|
+
// Compare BEFORE recording this call's own response, or a request that echoes its own reply
|
|
133
|
+
// would compare against itself.
|
|
134
|
+
if (typeof requestBody === 'object' && requestBody !== null) {
|
|
135
|
+
const sentFields = requestBody;
|
|
136
|
+
for (const id of idsIn(url, requestBody)) {
|
|
137
|
+
const fields = known.get(id);
|
|
138
|
+
if (fields === undefined)
|
|
139
|
+
continue;
|
|
140
|
+
for (const [key, sent] of Object.entries(sentFields)) {
|
|
141
|
+
if (!MONEY_FIELDS.has(key) || typeof sent !== 'number')
|
|
142
|
+
continue;
|
|
143
|
+
const priorValue = fields.get(key);
|
|
144
|
+
if (priorValue === undefined)
|
|
145
|
+
continue;
|
|
146
|
+
const scale = scaleBetween(priorValue, sent);
|
|
147
|
+
if (scale === undefined)
|
|
148
|
+
continue;
|
|
149
|
+
const key2 = `${id}:${key}`;
|
|
150
|
+
if (seen.has(key2))
|
|
151
|
+
continue;
|
|
152
|
+
seen.add(key2);
|
|
153
|
+
found.push({
|
|
154
|
+
kind: ContradictionKind.UNIT_MISMATCH,
|
|
155
|
+
claim: `the request sent ${key}=${String(sent)} and the server accepted it`,
|
|
156
|
+
counter: `the API reports ${key}=${String(priorValue)} for ${id} — the value sent is ${String(scale)}x SMALLER, i.e. a major-unit number written into a minor-unit field`,
|
|
157
|
+
detail: `${url} — at this scale the operation moves ${String(sent)} minor units instead of ${String(priorValue)}; nothing else can see this, because the number sent is exactly the number rendered on screen`,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const responseBody = parse(event.data['responseBody']);
|
|
163
|
+
if (responseBody !== undefined)
|
|
164
|
+
moneyByEntity(responseBody, known);
|
|
165
|
+
}
|
|
166
|
+
return found;
|
|
167
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ToolDef } from '../tools/tools.js';
|
|
2
|
+
/**
|
|
3
|
+
* `reticle_affected` — which saved flows must re-verify for a set of changed files.
|
|
4
|
+
*
|
|
5
|
+
* This logic already existed as `reticle affected`, deliberately kept off the MCP surface because an
|
|
6
|
+
* advertised tool costs tokens on every turn whether or not it is used. That reasoning is right, and
|
|
7
|
+
* this does not change it: the tool is NOT advertised by any profile. It is reachable through
|
|
8
|
+
* `reticle_run`, so it costs nothing per turn and is still discoverable via `reticle_tools`.
|
|
9
|
+
*
|
|
10
|
+
* What the reasoning missed is who holds the question. The AGENT is the one that just edited files
|
|
11
|
+
* and has to decide what to re-check; a shell command it may not be able to run is not an answer for
|
|
12
|
+
* an MCP client that has no shell. Leaving it CLI-only meant the party with the diff could not ask
|
|
13
|
+
* the party with the index.
|
|
14
|
+
*
|
|
15
|
+
* Unknown-provenance flows are returned as affected (fail-safe) AND listed separately, so "re-verify
|
|
16
|
+
* this" is never confused with "this definitely touches your change".
|
|
17
|
+
*/
|
|
18
|
+
export declare const AFFECTED_TOOLS: ToolDef[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ReticleTool } from '../tools/tool-names.js';
|
|
3
|
+
import { loadNamedFlows, resolveChangedFiles } from '../cli-flow-commands.js';
|
|
4
|
+
import { affectedSavedFlows } from './flow-sources.js';
|
|
5
|
+
/**
|
|
6
|
+
* `reticle_affected` — which saved flows must re-verify for a set of changed files.
|
|
7
|
+
*
|
|
8
|
+
* This logic already existed as `reticle affected`, deliberately kept off the MCP surface because an
|
|
9
|
+
* advertised tool costs tokens on every turn whether or not it is used. That reasoning is right, and
|
|
10
|
+
* this does not change it: the tool is NOT advertised by any profile. It is reachable through
|
|
11
|
+
* `reticle_run`, so it costs nothing per turn and is still discoverable via `reticle_tools`.
|
|
12
|
+
*
|
|
13
|
+
* What the reasoning missed is who holds the question. The AGENT is the one that just edited files
|
|
14
|
+
* and has to decide what to re-check; a shell command it may not be able to run is not an answer for
|
|
15
|
+
* an MCP client that has no shell. Leaving it CLI-only meant the party with the diff could not ask
|
|
16
|
+
* the party with the index.
|
|
17
|
+
*
|
|
18
|
+
* Unknown-provenance flows are returned as affected (fail-safe) AND listed separately, so "re-verify
|
|
19
|
+
* this" is never confused with "this definitely touches your change".
|
|
20
|
+
*/
|
|
21
|
+
export const AFFECTED_TOOLS = [
|
|
22
|
+
{
|
|
23
|
+
name: ReticleTool.AFFECTED,
|
|
24
|
+
description: 'Which saved flows must re-verify for a set of changed files. Pass the files you edited (and/or `since` for a git ref to diff against). Returns { changedFiles, affected, unknownProvenance } — `affected` is what to re-run, and `unknownProvenance` are flows included only because Reticle cannot tell which sources they cover, so they are re-verified by default rather than silently skipped.',
|
|
25
|
+
example: { files: ['src/App.tsx'] },
|
|
26
|
+
inputSchema: {
|
|
27
|
+
files: z
|
|
28
|
+
.array(z.string())
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Changed file paths, repo-relative (e.g. ["src/App.tsx"]).'),
|
|
31
|
+
since: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('Git ref to diff against (e.g. "HEAD~1", "main"). Unioned with `files`.'),
|
|
35
|
+
},
|
|
36
|
+
outputSchema: {
|
|
37
|
+
changedFiles: z.array(z.string()),
|
|
38
|
+
affected: z.array(z.string()),
|
|
39
|
+
unknownProvenance: z.array(z.string()),
|
|
40
|
+
},
|
|
41
|
+
handler: async (deps, args) => {
|
|
42
|
+
const files = Array.isArray(args['files'])
|
|
43
|
+
? args['files'].filter((f) => typeof f === 'string')
|
|
44
|
+
: [];
|
|
45
|
+
const since = typeof args['since'] === 'string' ? args['since'] : undefined;
|
|
46
|
+
const changedFiles = await resolveChangedFiles(files, since);
|
|
47
|
+
const flows = await loadNamedFlows(deps.fs, deps.reticleRoot);
|
|
48
|
+
const result = affectedSavedFlows(flows, changedFiles);
|
|
49
|
+
return { changedFiles, ...result };
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
];
|
package/dist/flows/affected.d.ts
CHANGED
|
@@ -22,4 +22,3 @@ export interface AffectedResult {
|
|
|
22
22
|
* a repo-relative change matches an absolute stamp and vice-versa.
|
|
23
23
|
*/
|
|
24
24
|
export declare function affectedFlows(flows: readonly FlowSources[], changedFiles: readonly string[]): AffectedResult;
|
|
25
|
-
//# sourceMappingURL=affected.d.ts.map
|
package/dist/flows/affected.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { AnnotationErrorCode, AnnotationSchema } from '@reticlehq/core';
|
|
3
|
+
import { RECOVERY } from '../tools/error-recovery.js';
|
|
4
|
+
/**
|
|
5
|
+
* An unknown kind is almost always a free-text annotation, which this tool deliberately refuses to
|
|
6
|
+
* guess into a predicate. Naming the six kinds turns a dead end into one retry.
|
|
7
|
+
*/
|
|
8
|
+
const UNKNOWN_KIND_RECOVERY = 'Annotations are structured, never free text. Pass one of: ' +
|
|
9
|
+
'{ kind: "assert-signal", name }, { kind: "assert-visible", testid }, ' +
|
|
10
|
+
'{ kind: "assert-state", statePath }, { kind: "mark-dynamic", testid }, ' +
|
|
11
|
+
'{ kind: "success-state", signal|testid }, or { kind: "intent", text }.';
|
|
3
12
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
4
13
|
import { asString } from '../tools/tools-helpers.js';
|
|
5
14
|
import { compileAnnotation } from './annotate.js';
|
|
@@ -20,6 +29,7 @@ const DEFAULT_RECORDING = 'default';
|
|
|
20
29
|
export const ANNOTATE_TOOLS = [
|
|
21
30
|
{
|
|
22
31
|
name: ReticleTool.ANNOTATE,
|
|
32
|
+
example: { kind: 'assert-signal', name: 'todos:loaded' },
|
|
23
33
|
description: 'Attach a STRUCTURED annotation to the active recording, compiling it into the flow. kind: ' +
|
|
24
34
|
'assert-signal { name, dataMatches? } → the last step asserts that signal; assert-visible ' +
|
|
25
35
|
'{ testid } → the last step asserts that element is present; assert-state ' +
|
|
@@ -98,6 +108,7 @@ export const ANNOTATE_TOOLS = [
|
|
|
98
108
|
},
|
|
99
109
|
outputSchema: {
|
|
100
110
|
ok: z.boolean(),
|
|
111
|
+
recovery: z.string().optional(),
|
|
101
112
|
target: z.string().optional(),
|
|
102
113
|
compiled: z.string().optional(),
|
|
103
114
|
code: z.string().optional(),
|
|
@@ -107,12 +118,20 @@ export const ANNOTATE_TOOLS = [
|
|
|
107
118
|
// Structured boundary: a free NL string / unknown kind fails the schema → UNKNOWN_KIND.
|
|
108
119
|
const parsed = AnnotationSchema.safeParse(args);
|
|
109
120
|
if (!parsed.success) {
|
|
110
|
-
return Promise.resolve({
|
|
121
|
+
return Promise.resolve({
|
|
122
|
+
ok: false,
|
|
123
|
+
code: AnnotationErrorCode.UNKNOWN_KIND,
|
|
124
|
+
recovery: UNKNOWN_KIND_RECOVERY,
|
|
125
|
+
});
|
|
111
126
|
}
|
|
112
127
|
const stepCount = deps.recordings.stepCount(name);
|
|
113
128
|
const compiled = deps.recordings.getCompiled(name) !== undefined;
|
|
114
129
|
if (stepCount === undefined && !compiled) {
|
|
115
|
-
return Promise.resolve({
|
|
130
|
+
return Promise.resolve({
|
|
131
|
+
ok: false,
|
|
132
|
+
code: AnnotationErrorCode.NO_ACTIVE_RECORDING,
|
|
133
|
+
recovery: RECOVERY.MISSING_RECORDING,
|
|
134
|
+
});
|
|
116
135
|
}
|
|
117
136
|
const outcome = compileAnnotation(parsed.data, stepCount ?? 0);
|
|
118
137
|
if (!outcome.result.ok)
|
|
@@ -133,4 +152,3 @@ export const ANNOTATE_TOOLS = [
|
|
|
133
152
|
},
|
|
134
153
|
},
|
|
135
154
|
];
|
|
136
|
-
//# sourceMappingURL=annotate-tools.js.map
|
package/dist/flows/annotate.d.ts
CHANGED
|
@@ -19,4 +19,3 @@ export declare function compileAnnotation(a: Annotation, stepCount: number): Ann
|
|
|
19
19
|
* e.g. `will assert signal diff:shown`. The leading word is the named COMPILED_PREDICATE_PREFIX.
|
|
20
20
|
*/
|
|
21
21
|
export declare function describeCompiled(a: Annotation): string;
|
|
22
|
-
//# sourceMappingURL=annotate.d.ts.map
|
package/dist/flows/annotate.js
CHANGED
|
@@ -77,4 +77,3 @@ export declare class AssertionTiersStore {
|
|
|
77
77
|
/** Record one flow's assertion shape + covered sources after it PASSED. Never breaks a replay. */
|
|
78
78
|
recordPassing(name: string, steps: readonly StepExpect[], sources?: readonly string[]): Promise<void>;
|
|
79
79
|
}
|
|
80
|
-
//# sourceMappingURL=assertion-tiers-store.d.ts.map
|
package/dist/flows/coverage.d.ts
CHANGED
package/dist/flows/coverage.js
CHANGED
package/dist/flows/decision.d.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { type FlowFile, type FlowReplayResult, type ReplayDecision, type SuiteVerdict } from '@reticlehq/core';
|
|
2
2
|
export declare function buildDecision(result: FlowReplayResult, flow?: FlowFile): ReplayDecision;
|
|
3
|
-
/**
|
|
4
|
-
* Aggregate per-flow replays into one suite verdict — the autonomous loop's consolidated answer
|
|
5
|
-
* after a build: did anything break, and what's the prioritized fix list. Pure: pass the already
|
|
6
|
-
* decision-annotated replay results + their flows. Passing flows are counted; only failures carry
|
|
7
|
-
* detail (token-cheap), each with the actionable decision so the agent fixes without re-querying.
|
|
8
|
-
*/
|
|
9
3
|
export declare function buildSuiteVerdict(runs: ReadonlyArray<{
|
|
10
4
|
replay: FlowReplayResult;
|
|
11
5
|
flow?: FlowFile;
|
|
12
6
|
}>): SuiteVerdict;
|
|
13
|
-
//# sourceMappingURL=decision.d.ts.map
|
package/dist/flows/decision.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnchorKind, ReplayStatus, } from '@reticlehq/core';
|
|
2
|
-
import { classifyFlowAssertions } from './flow-classify.js';
|
|
2
|
+
import { classifyFlowAssertions, FlowAssertionGrade } from './flow-classify.js';
|
|
3
3
|
import { SUCCESS_STEP_TOOL } from './flow-success.js';
|
|
4
4
|
/**
|
|
5
5
|
* Turn a replay result into the autonomy DECISION envelope — the judgement a human reviewer used to
|
|
@@ -92,12 +92,39 @@ function suiteVerdictOf(status) {
|
|
|
92
92
|
* decision-annotated replay results + their flows. Passing flows are counted; only failures carry
|
|
93
93
|
* detail (token-cheap), each with the actionable decision so the agent fixes without re-querying.
|
|
94
94
|
*/
|
|
95
|
+
/**
|
|
96
|
+
* Why a green replay still verified nothing, or undefined when it genuinely did.
|
|
97
|
+
*
|
|
98
|
+
* A flow with no steps, or one that asserts no observable consequence, replays green no matter what
|
|
99
|
+
* the app does — the grader already knows this at save time and says so. Counting it as `passed`
|
|
100
|
+
* turned that warning into "all 1 flow pass", which is a false green in the exact feature sold as
|
|
101
|
+
* the regression suite. Classified only when the flow file is available; never guessed.
|
|
102
|
+
*/
|
|
103
|
+
function unverifiableReason(flow) {
|
|
104
|
+
if (flow === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
if (flow.steps.length === 0) {
|
|
107
|
+
return 'the flow has no steps — it replays green whatever the app does. Record it again, or add steps with reticle_annotate.';
|
|
108
|
+
}
|
|
109
|
+
const c = classifyFlowAssertions(flow);
|
|
110
|
+
if (c.grade !== FlowAssertionGrade.ASSERTION_FREE)
|
|
111
|
+
return undefined;
|
|
112
|
+
return (c.warning ??
|
|
113
|
+
'the flow asserts no observable consequence, so it passes even when the feature is broken.');
|
|
114
|
+
}
|
|
95
115
|
export function buildSuiteVerdict(runs) {
|
|
96
116
|
const failures = [];
|
|
117
|
+
const unverifiable = [];
|
|
97
118
|
let passed = 0;
|
|
98
119
|
for (const { replay, flow } of runs) {
|
|
99
120
|
if (replay.status === ReplayStatus.OK) {
|
|
100
|
-
|
|
121
|
+
const reason = unverifiableReason(flow);
|
|
122
|
+
// A green that cannot go red is not a pass. Counted apart, so `passed` stays a count of things
|
|
123
|
+
// actually verified rather than of replays that merely completed.
|
|
124
|
+
if (reason !== undefined)
|
|
125
|
+
unverifiable.push({ flow: replay.name, reason });
|
|
126
|
+
else
|
|
127
|
+
passed += 1;
|
|
101
128
|
continue;
|
|
102
129
|
}
|
|
103
130
|
const decision = replay.decision ?? buildDecision(replay, flow);
|
|
@@ -111,10 +138,23 @@ export function buildSuiteVerdict(runs) {
|
|
|
111
138
|
}
|
|
112
139
|
const total = runs.length;
|
|
113
140
|
const failed = failures.length;
|
|
114
|
-
|
|
141
|
+
// A real failure outranks an unverifiable flow: a broken flow is worse news than an empty one.
|
|
142
|
+
const status = failed > 0 ? 'fail' : unverifiable.length > 0 ? 'unverifiable' : 'pass';
|
|
143
|
+
const cannotFail = unverifiable.length === 0
|
|
144
|
+
? ''
|
|
145
|
+
: ` — ${String(unverifiable.length)} verified nothing (${unverifiable.map((u) => u.flow).join(', ')})`;
|
|
115
146
|
const summary = failed === 0
|
|
116
|
-
?
|
|
117
|
-
|
|
118
|
-
|
|
147
|
+
? unverifiable.length === 0
|
|
148
|
+
? `all ${total} flow${total === 1 ? '' : 's'} pass`
|
|
149
|
+
: `${String(passed)}/${String(total)} flows verified${cannotFail}`
|
|
150
|
+
: `${passed}/${total} flows pass — ${failed} need attention: ${failures.map((f) => f.flow).join(', ')}${cannotFail}`;
|
|
151
|
+
return {
|
|
152
|
+
status,
|
|
153
|
+
total,
|
|
154
|
+
passed,
|
|
155
|
+
failed,
|
|
156
|
+
summary,
|
|
157
|
+
failures,
|
|
158
|
+
...(unverifiable.length > 0 ? { unverifiable } : {}),
|
|
159
|
+
};
|
|
119
160
|
}
|
|
120
|
-
//# sourceMappingURL=decision.js.map
|