@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
|
@@ -8,16 +8,78 @@
|
|
|
8
8
|
* per Node's guidance, so LOG a clear reason and exit cleanly; the next `reticle mcp` respawns a fresh
|
|
9
9
|
* daemon, which beats crashing silently or limping along corrupt.
|
|
10
10
|
*/
|
|
11
|
+
import { TelemetryActor, TelemetryEventKind } from '@reticlehq/core';
|
|
12
|
+
import { errorSkeleton, errorTypeOf, fingerprintCrash, MAX_REPORTED_FRAMES, reticleFrames, } from './telemetry/error-fingerprint.js';
|
|
13
|
+
import { getSessionMetrics } from './telemetry/session-metrics.js';
|
|
14
|
+
import { machineSnapshot } from './telemetry/machine-snapshot.js';
|
|
15
|
+
import { getTelemetry } from './telemetry/telemetry.js';
|
|
11
16
|
function describe(value) {
|
|
12
17
|
return value instanceof Error ? value.message : String(value);
|
|
13
18
|
}
|
|
19
|
+
/** The two ways a failure reaches the top of the process. Named so the analytics can tell them apart. */
|
|
20
|
+
export const CrashKind = {
|
|
21
|
+
UNHANDLED_REJECTION: 'unhandled_rejection',
|
|
22
|
+
UNCAUGHT_EXCEPTION: 'uncaught_exception',
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Report a crash with enough detail to actually diagnose it.
|
|
26
|
+
*
|
|
27
|
+
* This is the only place in the product that learns about a crash at all. An uncaught exception in a
|
|
28
|
+
* long-running daemon takes down every agent attached to it, and the only other record is a line in a
|
|
29
|
+
* local log nobody sends us.
|
|
30
|
+
*
|
|
31
|
+
* The first version sent a hash and nothing else, which made crashes rankable and undiagnosable — you
|
|
32
|
+
* could see that forty machines hit `a3f2c1d8e9b0` and had no way to learn what that was. So it now
|
|
33
|
+
* carries the four things an RCA needs: WHERE (our own frames, with function names and line numbers),
|
|
34
|
+
* WHAT (the message with every variable part stripped), WHEN (the tool in flight), and WHY-ish (the
|
|
35
|
+
* agent's approach run before it). All of it is our code and our vocabulary; the user's stack frames,
|
|
36
|
+
* their paths, and the contents of their message are removed before any of it is built.
|
|
37
|
+
*
|
|
38
|
+
* Best-effort and wrapped: reporting a crash must never be the reason a crash gets worse.
|
|
39
|
+
*/
|
|
40
|
+
function reportCrash(kind, value) {
|
|
41
|
+
try {
|
|
42
|
+
const errorType = errorTypeOf(value);
|
|
43
|
+
const stack = value instanceof Error ? (value.stack ?? '') : '';
|
|
44
|
+
const message = describe(value);
|
|
45
|
+
const { breadcrumb, inFlight } = getSessionMetrics().trail;
|
|
46
|
+
const machine = machineSnapshot();
|
|
47
|
+
void getTelemetry().emit(TelemetryEventKind.RUNTIME_CRASHED, {
|
|
48
|
+
// A crash is ALWAYS reached through something the agent asked for — the daemon does nothing on
|
|
49
|
+
// its own — so attributing it to the agent is accurate rather than a guess.
|
|
50
|
+
actor: TelemetryActor.AGENT,
|
|
51
|
+
crash: {
|
|
52
|
+
kind,
|
|
53
|
+
errorType,
|
|
54
|
+
fingerprint: fingerprintCrash(errorType, stack, message),
|
|
55
|
+
// The skeleton, not the message: every quoted string, path, URL, id and number is replaced
|
|
56
|
+
// by `*` first. This is what makes the fingerprint mean something to a human reading a chart.
|
|
57
|
+
message: errorSkeleton(message).slice(0, 300),
|
|
58
|
+
// Our own frames, our own published code. The file, the line, and the function — which is the
|
|
59
|
+
// whole of "where did it break". Frames from the user's app never survive this.
|
|
60
|
+
frames: reticleFrames(stack).slice(0, MAX_REPORTED_FRAMES),
|
|
61
|
+
...(inFlight !== undefined ? { tool: inFlight } : {}),
|
|
62
|
+
...(breadcrumb.length > 0 ? { breadcrumb } : {}),
|
|
63
|
+
// Crashes cluster hard by runtime version and architecture, and we were recording neither.
|
|
64
|
+
nodeVersion: process.versions.node,
|
|
65
|
+
arch: process.arch,
|
|
66
|
+
// "Out of memory" and "our bug" look identical in a stack trace. This is what tells them apart.
|
|
67
|
+
...(machine !== undefined ? { machine } : {}),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* a crash report must never be the reason a crash gets worse */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
14
75
|
export function installDaemonResilience(proc, log, onFatal) {
|
|
15
76
|
proc.on('unhandledRejection', (reason) => {
|
|
16
77
|
log('reticle_daemon_unhandled_rejection', { reason: describe(reason) });
|
|
78
|
+
reportCrash(CrashKind.UNHANDLED_REJECTION, reason);
|
|
17
79
|
});
|
|
18
80
|
proc.on('uncaughtException', (err) => {
|
|
19
81
|
log('reticle_daemon_uncaught_exception', { error: describe(err) });
|
|
82
|
+
reportCrash(CrashKind.UNCAUGHT_EXCEPTION, err);
|
|
20
83
|
onFatal();
|
|
21
84
|
});
|
|
22
85
|
}
|
|
23
|
-
//# sourceMappingURL=daemon-resilience.js.map
|
package/dist/daemon.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare function logPath(port: number): string;
|
|
2
|
-
export declare function readPid(port: number): number | null;
|
|
2
|
+
export declare function readPid(port: number, home?: string): number | null;
|
|
3
3
|
export declare function isAlive(pid: number): boolean;
|
|
4
4
|
export declare function writePid(port: number): void;
|
|
5
5
|
/**
|
|
@@ -41,10 +41,30 @@ export declare function discoverDaemonPort(): number | null;
|
|
|
41
41
|
* ~/.reticle and the process.kill(pid,0) liveness probe).
|
|
42
42
|
*/
|
|
43
43
|
export declare function reclaimStaleDaemons(home?: string, pidAlive?: (pid: number) => boolean): number[];
|
|
44
|
+
/** The minimal shape of a spawned child that spawnDaemon uses. */
|
|
45
|
+
export interface SpawnedChild {
|
|
46
|
+
readonly pid?: number | undefined;
|
|
47
|
+
on(event: string, handler: (...args: unknown[]) => void): unknown;
|
|
48
|
+
unref(): void;
|
|
49
|
+
}
|
|
50
|
+
/** Injectable deps for spawnDaemon — the testability seam. Defaults to the real implementations. */
|
|
51
|
+
export interface SpawnDaemonDeps {
|
|
52
|
+
readonly home: string;
|
|
53
|
+
openFile(path: string, flags: string): number;
|
|
54
|
+
closeFile(fd: number): void;
|
|
55
|
+
spawnChild(command: string, args: readonly string[], options: {
|
|
56
|
+
detached: boolean;
|
|
57
|
+
stdio: readonly ('ignore' | number)[];
|
|
58
|
+
}): SpawnedChild;
|
|
59
|
+
pidAlive(pid: number): boolean;
|
|
60
|
+
}
|
|
61
|
+
export declare function defaultSpawnDaemonDeps(): SpawnDaemonDeps;
|
|
44
62
|
/**
|
|
45
63
|
* Spawn the reticle daemon as a detached background process, redirecting output to the log file.
|
|
46
64
|
* Writes the PID file from the parent before returning so callers can call isRunning
|
|
47
65
|
* immediately without a race window.
|
|
66
|
+
*
|
|
67
|
+
* `deps` is injectable for testing (default: real fs/spawn against ~/.reticle). The same seam
|
|
68
|
+
* pattern as reclaimStaleDaemons(home, pidAlive).
|
|
48
69
|
*/
|
|
49
|
-
export declare function spawnDaemon(nodeExec: string, scriptPath: string, args: string[], port: number): boolean;
|
|
50
|
-
//# sourceMappingURL=daemon.d.ts.map
|
|
70
|
+
export declare function spawnDaemon(nodeExec: string, scriptPath: string, args: string[], port: number, deps?: SpawnDaemonDeps): boolean;
|
package/dist/daemon.js
CHANGED
|
@@ -4,8 +4,8 @@ import { mkdirSync, readFileSync, writeFileSync, existsSync, unlinkSync, openSyn
|
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import { daemonRegistryFileName, daemonRegistryPort, DaemonRegistryEntrySchema, pickDaemonPort, } from '@reticlehq/core';
|
|
6
6
|
const RETICLE_HOME = join(homedir(), '.reticle');
|
|
7
|
-
function pidPath(port) {
|
|
8
|
-
return join(
|
|
7
|
+
function pidPath(port, home = RETICLE_HOME) {
|
|
8
|
+
return join(home, `daemon-${port}.pid`);
|
|
9
9
|
}
|
|
10
10
|
function registryPath(port) {
|
|
11
11
|
return join(RETICLE_HOME, daemonRegistryFileName(port));
|
|
@@ -13,8 +13,8 @@ function registryPath(port) {
|
|
|
13
13
|
export function logPath(port) {
|
|
14
14
|
return join(RETICLE_HOME, `daemon-${port}.log`);
|
|
15
15
|
}
|
|
16
|
-
export function readPid(port) {
|
|
17
|
-
const path = pidPath(port);
|
|
16
|
+
export function readPid(port, home = RETICLE_HOME) {
|
|
17
|
+
const path = pidPath(port, home);
|
|
18
18
|
if (!existsSync(path))
|
|
19
19
|
return null;
|
|
20
20
|
const n = parseInt(readFileSync(path, 'utf8').trim(), 10);
|
|
@@ -180,43 +180,100 @@ export function reclaimStaleDaemons(home = RETICLE_HOME, pidAlive = isAlive) {
|
|
|
180
180
|
}
|
|
181
181
|
return reclaimed;
|
|
182
182
|
}
|
|
183
|
+
export function defaultSpawnDaemonDeps() {
|
|
184
|
+
return {
|
|
185
|
+
home: RETICLE_HOME,
|
|
186
|
+
openFile: openSync,
|
|
187
|
+
closeFile: closeSync,
|
|
188
|
+
spawnChild: (command, args, options) => spawn(command, [...args], { detached: options.detached, stdio: [...options.stdio] }),
|
|
189
|
+
pidAlive: isAlive,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
183
192
|
/**
|
|
184
193
|
* Spawn the reticle daemon as a detached background process, redirecting output to the log file.
|
|
185
194
|
* Writes the PID file from the parent before returning so callers can call isRunning
|
|
186
195
|
* immediately without a race window.
|
|
196
|
+
*
|
|
197
|
+
* `deps` is injectable for testing (default: real fs/spawn against ~/.reticle). The same seam
|
|
198
|
+
* pattern as reclaimStaleDaemons(home, pidAlive).
|
|
187
199
|
*/
|
|
188
|
-
export function spawnDaemon(nodeExec, scriptPath, args, port) {
|
|
189
|
-
mkdirSync(
|
|
190
|
-
const
|
|
200
|
+
export function spawnDaemon(nodeExec, scriptPath, args, port, deps = defaultSpawnDaemonDeps()) {
|
|
201
|
+
mkdirSync(deps.home, { recursive: true });
|
|
202
|
+
const pidFilePath = join(deps.home, `daemon-${port}.pid`);
|
|
203
|
+
const logFilePath = join(deps.home, `daemon-${port}.log`);
|
|
191
204
|
// O_EXCL spawn-lock: only the FIRST racer to create the pidfile spawns. A concurrent second gets
|
|
192
205
|
// EEXIST — if a LIVE daemon owns the port it skips (no duplicate detached daemon, no clobbered pid);
|
|
193
206
|
// a stale pidfile from a crashed daemon is reclaimed. Returns false when it did not spawn.
|
|
194
207
|
let lockFd;
|
|
195
208
|
try {
|
|
196
|
-
lockFd =
|
|
209
|
+
lockFd = deps.openFile(pidFilePath, 'wx');
|
|
197
210
|
}
|
|
198
211
|
catch {
|
|
199
|
-
const existing = readPid(port);
|
|
200
|
-
if (existing !== null &&
|
|
212
|
+
const existing = readPid(port, deps.home);
|
|
213
|
+
if (existing !== null && deps.pidAlive(existing))
|
|
201
214
|
return false;
|
|
202
215
|
try {
|
|
203
|
-
unlinkSync(
|
|
204
|
-
lockFd =
|
|
216
|
+
unlinkSync(pidFilePath);
|
|
217
|
+
lockFd = deps.openFile(pidFilePath, 'wx');
|
|
205
218
|
}
|
|
206
219
|
catch {
|
|
207
220
|
return false; // lost a concurrent reclaim race
|
|
208
221
|
}
|
|
209
222
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
223
|
+
let logFd;
|
|
224
|
+
try {
|
|
225
|
+
logFd = deps.openFile(logFilePath, 'a');
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Log path unwritable (permissions, disk full). Clean up the lock so we don't leave a ghost.
|
|
229
|
+
deps.closeFile(lockFd);
|
|
230
|
+
try {
|
|
231
|
+
unlinkSync(pidFilePath);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// racing another reclaimer — fine
|
|
235
|
+
}
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
let child;
|
|
239
|
+
try {
|
|
240
|
+
child = deps.spawnChild(nodeExec, [scriptPath, ...args], {
|
|
241
|
+
detached: true,
|
|
242
|
+
stdio: ['ignore', logFd, logFd],
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// spawn can throw synchronously on some platforms (e.g. ENOMEM, invalid args).
|
|
247
|
+
deps.closeFile(logFd);
|
|
248
|
+
deps.closeFile(lockFd);
|
|
249
|
+
try {
|
|
250
|
+
unlinkSync(pidFilePath);
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// racing another reclaimer — fine
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
// The parent's copy of logFd is no longer needed — spawn duplicated it into the child.
|
|
258
|
+
deps.closeFile(logFd);
|
|
259
|
+
// Suppress the async ENOENT/EACCES that fires when the executable is missing or unexecutable.
|
|
260
|
+
// The failure is already detected synchronously via `child.pid === undefined`; without this
|
|
261
|
+
// handler the error propagates as an uncaught exception and crashes the parent process.
|
|
262
|
+
child.on('error', () => undefined);
|
|
263
|
+
if (child.pid === undefined) {
|
|
264
|
+
// Spawn failed silently (resource exhaustion, invalid executable on some platforms). The pidfile
|
|
265
|
+
// is empty — clean it up so discovery doesn't see a ghost, and report failure honestly.
|
|
266
|
+
deps.closeFile(lockFd);
|
|
267
|
+
try {
|
|
268
|
+
unlinkSync(pidFilePath);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// racing another reclaimer — fine
|
|
272
|
+
}
|
|
273
|
+
return false;
|
|
217
274
|
}
|
|
218
|
-
|
|
275
|
+
writeFileSync(lockFd, String(child.pid), 'utf8');
|
|
276
|
+
deps.closeFile(lockFd);
|
|
219
277
|
child.unref();
|
|
220
278
|
return true;
|
|
221
279
|
}
|
|
222
|
-
//# sourceMappingURL=daemon.js.map
|
|
@@ -108,7 +108,7 @@ export function buildDomainModel(flows, contract, runs = []) {
|
|
|
108
108
|
}
|
|
109
109
|
function buildSummary(flowCount, coverage, gaps, topRisk) {
|
|
110
110
|
if (flowCount === 0) {
|
|
111
|
-
return 'No saved flows yet — record the critical journeys (
|
|
111
|
+
return 'No saved flows yet — record the critical journeys (reticle_record{action:"start"}) so the agent learns the app.';
|
|
112
112
|
}
|
|
113
113
|
const parts = [
|
|
114
114
|
`${String(flowCount)} flow${flowCount === 1 ? '' : 's'}: ${String(coverage.asserted)} asserted, ${String(coverage.presenceOnly)} presence-only, ${String(coverage.assertionFree)} assertion-free`,
|
|
@@ -124,4 +124,3 @@ function buildSummary(flowCount, coverage, gaps, topRisk) {
|
|
|
124
124
|
}
|
|
125
125
|
return parts.join('. ') + '.';
|
|
126
126
|
}
|
|
127
|
-
//# sourceMappingURL=domain-model.js.map
|
|
@@ -1,9 +1,2 @@
|
|
|
1
1
|
import type { ToolDef } from '../tools/tools.js';
|
|
2
|
-
/**
|
|
3
|
-
* reticle_domain — the "learn the app before testing it" tool. Synthesizes every saved flow + the
|
|
4
|
-
* registered capabilities into a compact domain model: the journeys, what each asserts, and the
|
|
5
|
-
* GAPS (declared signals/testids no flow verifies). An agent reads this once instead of crawling
|
|
6
|
-
* the whole app or reading all the source — and it points straight at untested intent.
|
|
7
|
-
*/
|
|
8
2
|
export declare const DOMAIN_TOOLS: ToolDef[];
|
|
9
|
-
//# sourceMappingURL=domain-tools.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { asNumber } from '../tools/tools-helpers.js';
|
|
2
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
3
4
|
import { readContract } from '../project/reticle-dir.js';
|
|
4
5
|
import { buildDomainModel } from './domain-model.js';
|
|
@@ -10,11 +11,18 @@ import { instrumentationGapsForFlows } from '../oracles/flow-instrument-gaps.js'
|
|
|
10
11
|
* GAPS (declared signals/testids no flow verifies). An agent reads this once instead of crawling
|
|
11
12
|
* the whole app or reading all the source — and it points straight at untested intent.
|
|
12
13
|
*/
|
|
14
|
+
/** Flows detailed when the caller does not ask for a specific count. */
|
|
15
|
+
const DEFAULT_FLOW_DETAIL_LIMIT = 25;
|
|
13
16
|
export const DOMAIN_TOOLS = [
|
|
14
17
|
{
|
|
15
18
|
name: ReticleTool.DOMAIN,
|
|
16
19
|
description: 'Read the app domain model BEFORE testing: every saved flow with its assertion grade, the consequence that MUST hold for it (mustHold = what it actually tests), the anchors/signals it exercises, plus GAPS — declared signals/testids that NO flow asserts (untested intent), and flows that assert no observable consequence. Use this to decide what to test and where the real risk is, instead of crawling the whole app. Reads .reticle/flows/ + .reticle/contract.json (no browser needed).',
|
|
17
|
-
inputSchema: {
|
|
20
|
+
inputSchema: {
|
|
21
|
+
limit: z
|
|
22
|
+
.number()
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Most-recent N flows to detail. Defaults to 25 — the per-flow list grows with every saved flow (measured at ~11KB / ~2,700 tokens at 22 flows) and a large project would spend most of an agent context on flows it is not asking about. `flowCount` is always the true total, and the gaps/coverage summary is computed over ALL flows regardless, so capping the detail never changes the analysis.'),
|
|
25
|
+
},
|
|
18
26
|
outputSchema: {
|
|
19
27
|
flowCount: z.number(),
|
|
20
28
|
flows: z.array(z.object({
|
|
@@ -35,6 +43,10 @@ export const DOMAIN_TOOLS = [
|
|
|
35
43
|
signals: z.array(z.string()),
|
|
36
44
|
stores: z.array(z.string()),
|
|
37
45
|
}),
|
|
46
|
+
flowsTruncated: z
|
|
47
|
+
.number()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('How many flows were omitted from `flows` by `limit`. Absent means the listing is complete. gaps/coverage always cover every flow.'),
|
|
38
50
|
coverage: z.object({
|
|
39
51
|
asserted: z.number(),
|
|
40
52
|
presenceOnly: z.number(),
|
|
@@ -54,7 +66,7 @@ export const DOMAIN_TOOLS = [
|
|
|
54
66
|
.optional()
|
|
55
67
|
.describe('Ready-to-apply instrumentation proposals for gaps that have a source location — { file, line, insert, rationale }. Apply, re-verify, and the app’s observability compounds.'),
|
|
56
68
|
},
|
|
57
|
-
handler: async (deps) => {
|
|
69
|
+
handler: async (deps, args) => {
|
|
58
70
|
const names = await deps.flows.list();
|
|
59
71
|
const flows = [];
|
|
60
72
|
for (const name of names) {
|
|
@@ -69,8 +81,13 @@ export const DOMAIN_TOOLS = [
|
|
|
69
81
|
// Self-instrumentation: turn located gaps (unasserted flows with a source stamp) into apply-ready diffs.
|
|
70
82
|
const stepsByName = new Map(flows.map((f) => [f.name, f.steps]));
|
|
71
83
|
const instrumentation = proposeInstrumentation(instrumentationGapsForFlows(model.gaps.unassertedFlows, stepsByName));
|
|
72
|
-
|
|
84
|
+
// The per-flow detail is capped; `flowCount`, `gaps` and `coverage` are computed over every
|
|
85
|
+
// flow, so the ANALYSIS is never truncated — only the listing an agent reads past is.
|
|
86
|
+
const cap = asNumber(args['limit']) ?? DEFAULT_FLOW_DETAIL_LIMIT;
|
|
87
|
+
const capped = model.flows.length > cap
|
|
88
|
+
? { ...model, flows: model.flows.slice(-cap), flowsTruncated: model.flows.length - cap }
|
|
89
|
+
: model;
|
|
90
|
+
return instrumentation.length > 0 ? { ...capped, instrumentation } : capped;
|
|
73
91
|
},
|
|
74
92
|
},
|
|
75
93
|
];
|
|
76
|
-
//# sourceMappingURL=domain-tools.js.map
|
package/dist/domain/flow-risk.js
CHANGED
package/dist/ee/audit-log.d.ts
CHANGED
|
@@ -12,4 +12,3 @@ interface AuditEvent {
|
|
|
12
12
|
/** Record an audit event — gated. Throws EnterpriseLicenseError in production without a valid license. */
|
|
13
13
|
export declare function recordAuditEvent(event: AuditEvent, ctx: GateContext): AuditEvent;
|
|
14
14
|
export {};
|
|
15
|
-
//# sourceMappingURL=audit-log.d.ts.map
|
package/dist/ee/audit-log.js
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
import type { Contradiction } from './contradictions.js';
|
|
3
|
+
/** Contradictions for 2xx responses whose bodies report failure. One per offending call. */
|
|
4
|
+
export declare function findBodyFailures(events: readonly ReticleEvent[]): Contradiction[];
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ContradictionKind, EventType } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* A request that returned 2xx and reported failure INSIDE its body.
|
|
4
|
+
*
|
|
5
|
+
* The status line is not the outcome. Three shapes make this routine rather than exotic:
|
|
6
|
+
*
|
|
7
|
+
* - **GraphQL** answers HTTP 200 for every error it has ever produced. `errors: [...]` in a 200 body
|
|
8
|
+
* is the normal way a GraphQL request fails, so any verdict that reads only the status is blind to
|
|
9
|
+
* the entire error surface of an entire ecosystem.
|
|
10
|
+
* - **Bulk endpoints** answer 200 for the batch and put per-item results in the body. Measured on a
|
|
11
|
+
* shipments console: `POST /api/bulk-hold` → 200, banner reads "9 shipments held", and three of
|
|
12
|
+
* the nine carry `{"ok": false, "error": "carrier_locked"}`. Reticle had that body in hand and
|
|
13
|
+
* reported `verified: "yes"`.
|
|
14
|
+
* - **Envelope APIs** answer 200 with `{"success": false}` — common wherever a gateway normalises
|
|
15
|
+
* status codes.
|
|
16
|
+
*
|
|
17
|
+
* Every channel above the body agrees with the lie: the request succeeded, the UI advanced, the page
|
|
18
|
+
* settled, nothing 5xx'd. Only the payload disagrees, which is why this needs body capture — and why
|
|
19
|
+
* an agent reading a status column can never catch it.
|
|
20
|
+
*/
|
|
21
|
+
/** Keys whose truthiness means "this failed". Checked at the top level and per item. */
|
|
22
|
+
const FAILURE_FLAGS = ['ok', 'success', 'succeeded'];
|
|
23
|
+
/** Keys that, when carrying content, name a failure. */
|
|
24
|
+
const ERROR_KEYS = ['error', 'errors', 'errorMessage', 'failureReason'];
|
|
25
|
+
/** Arrays worth walking for per-item outcomes. Bulk APIs converge on a handful of names. */
|
|
26
|
+
const ITEM_KEYS = ['results', 'items', 'data', 'records', 'responses'];
|
|
27
|
+
function isRecord(value) {
|
|
28
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
29
|
+
}
|
|
30
|
+
/** Whether one object reports a failure of its own. */
|
|
31
|
+
function reportsFailure(item) {
|
|
32
|
+
if (!isRecord(item))
|
|
33
|
+
return false;
|
|
34
|
+
for (const flag of FAILURE_FLAGS) {
|
|
35
|
+
if (item[flag] === false)
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
for (const key of ERROR_KEYS) {
|
|
39
|
+
const value = item[key];
|
|
40
|
+
if (value === undefined || value === null)
|
|
41
|
+
continue;
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
if (value.length > 0)
|
|
44
|
+
return true;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// An empty string or an explicit null is an API saying "no error", not an error.
|
|
48
|
+
if (typeof value === 'string' && value.length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/** Failed / total across the first item array found. Zero total when the body is not a batch. */
|
|
55
|
+
function itemOutcomes(body) {
|
|
56
|
+
for (const key of ITEM_KEYS) {
|
|
57
|
+
const list = body[key];
|
|
58
|
+
if (!Array.isArray(list) || list.length === 0)
|
|
59
|
+
continue;
|
|
60
|
+
const failed = list.filter(reportsFailure).length;
|
|
61
|
+
return { failed, total: list.length };
|
|
62
|
+
}
|
|
63
|
+
return { failed: 0, total: 0 };
|
|
64
|
+
}
|
|
65
|
+
function parse(raw) {
|
|
66
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
67
|
+
return undefined;
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
return isRecord(parsed) ? parsed : undefined;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined; // not JSON — nothing to read, and guessing at prose would invent findings
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const OK_MIN = 200;
|
|
77
|
+
const OK_MAX = 300;
|
|
78
|
+
/** Contradictions for 2xx responses whose bodies report failure. One per offending call. */
|
|
79
|
+
export function findBodyFailures(events) {
|
|
80
|
+
const found = [];
|
|
81
|
+
for (const event of events) {
|
|
82
|
+
if (event.type !== EventType.NET_REQUEST)
|
|
83
|
+
continue;
|
|
84
|
+
const status = event.data['status'];
|
|
85
|
+
if (typeof status !== 'number' || status < OK_MIN || status >= OK_MAX)
|
|
86
|
+
continue;
|
|
87
|
+
const body = parse(event.data['responseBody']);
|
|
88
|
+
if (body === undefined)
|
|
89
|
+
continue;
|
|
90
|
+
const url = typeof event.data['url'] === 'string' ? event.data['url'] : '';
|
|
91
|
+
const method = typeof event.data['method'] === 'string' ? event.data['method'] : '';
|
|
92
|
+
const where = `${method} ${url} → ${String(status)}`;
|
|
93
|
+
const { failed, total } = itemOutcomes(body);
|
|
94
|
+
if (failed > 0) {
|
|
95
|
+
found.push({
|
|
96
|
+
kind: ContradictionKind.PARTIAL_FAILURE_IN_OK_RESPONSE,
|
|
97
|
+
claim: `the request returned ${String(status)} and the page treated it as done`,
|
|
98
|
+
counter: `its body reports ${String(failed)} of ${String(total)} items FAILED`,
|
|
99
|
+
detail: `${where} — a batch endpoint's status describes the BATCH, not the items; whatever the UI says it did, ${String(failed)} of them did not happen`,
|
|
100
|
+
});
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (reportsFailure(body)) {
|
|
104
|
+
found.push({
|
|
105
|
+
kind: ContradictionKind.PARTIAL_FAILURE_IN_OK_RESPONSE,
|
|
106
|
+
claim: `the request returned ${String(status)} and the page treated it as done`,
|
|
107
|
+
counter: 'its body reports the operation FAILED',
|
|
108
|
+
detail: `${where} — the status line and the payload disagree; the payload is the outcome (a GraphQL error is always a 200)`,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return found;
|
|
113
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ContradictionKind, type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
/**
|
|
3
|
+
* The contradiction hunter.
|
|
4
|
+
*
|
|
5
|
+
* Every other check in Reticle reads ONE channel and asks "did something bad happen there?" — a
|
|
6
|
+
* console error, a 500, a control that did nothing. A human can do that too, just slower.
|
|
7
|
+
*
|
|
8
|
+
* This asks a question a human structurally cannot: do the channels DISAGREE with each other? A
|
|
9
|
+
* person watching an app has exactly one channel open — the screen. The agent holds the DOM, the
|
|
10
|
+
* store, the app's own signals, the console and the network in one causally ordered window, so it
|
|
11
|
+
* can catch the case where the screen says one thing and the network says the opposite.
|
|
12
|
+
*
|
|
13
|
+
* That gap is where false greens live. The archetype ships in both desktop demos: click Archive, the
|
|
14
|
+
* row disappears, the status line reads "archived", and the IPC call rejected into a swallowed
|
|
15
|
+
* `.catch()`. A screenshot agrees. A DOM assertion agrees. A human agrees. Only the disagreement
|
|
16
|
+
* between channels reveals it.
|
|
17
|
+
*
|
|
18
|
+
* Pure: a window of events in, findings out. No session, no IO, no clock.
|
|
19
|
+
*/
|
|
20
|
+
export interface Contradiction {
|
|
21
|
+
kind: ContradictionKind;
|
|
22
|
+
/** What one channel asserted — the optimistic half. */
|
|
23
|
+
claim: string;
|
|
24
|
+
/** What the other channel asserted — the half that contradicts it. */
|
|
25
|
+
counter: string;
|
|
26
|
+
/** Concrete evidence, so the agent can go straight to the call or the control. */
|
|
27
|
+
detail: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ContradictionOptions {
|
|
30
|
+
/** The action that opened this window, when one did. Enables the no-effect check. */
|
|
31
|
+
action?: string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Events from BEFORE the window, used only to LEARN — never reported on. Some disagreements are
|
|
34
|
+
* with something the API stated earlier in the session, which an action-scoped window cannot
|
|
35
|
+
* contain. See `findUnitMismatches` for the measured case this exists for.
|
|
36
|
+
*/
|
|
37
|
+
prior?: readonly ReticleEvent[] | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* DOM mutations observed INSIDE the target's own subtree, as the act tool measured them.
|
|
40
|
+
*
|
|
41
|
+
* The no-effect check used to require a completely empty window, which is a statement about the
|
|
42
|
+
* PAGE rather than about the action — and no real app has a quiet page. Measured on a shipments
|
|
43
|
+
* console with a background event stream: clicking an inert heading produced `domMutatedWithin: 0`
|
|
44
|
+
* and four ambient events (a scroll position, an unrelated store update, a perf sample), so the
|
|
45
|
+
* window was not empty and the dead control went unreported. The user's framing of this is exact:
|
|
46
|
+
* the DOM moving after an action is not evidence that the action moved it.
|
|
47
|
+
*
|
|
48
|
+
* Undefined means the caller did not measure it — the check then falls back to the empty-window
|
|
49
|
+
* test, which is weaker but never wrong in the direction of a false accusation.
|
|
50
|
+
*/
|
|
51
|
+
mutatedWithin?: number | undefined;
|
|
52
|
+
}
|
|
53
|
+
export declare function findContradictions(events: readonly ReticleEvent[], options?: ContradictionOptions): Contradiction[];
|