@reticlehq/server 2.7.0 → 2.9.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 +14 -5
- package/SKILL.md +130 -778
- package/dist/bridge/bridge.d.ts +23 -0
- package/dist/bridge/bridge.js +80 -2
- package/dist/bridge/bridge.test-harness.d.ts +5 -0
- package/dist/bridge/bridge.test-harness.js +6 -4
- package/dist/capsule/causal-summary.d.ts +36 -1
- package/dist/capsule/causal-summary.js +33 -7
- package/dist/capsule/divergence.js +7 -1
- package/dist/cli/chromium-hint.d.ts +33 -5
- package/dist/cli/chromium-hint.js +82 -12
- package/dist/cli/cli-doctor.js +65 -34
- package/dist/cli/cli-flow-commands.js +8 -8
- package/dist/cli/cli-kill.d.ts +58 -0
- package/dist/cli/cli-kill.js +162 -0
- package/dist/cli/cli-parse.d.ts +16 -1
- package/dist/cli/cli-parse.js +32 -9
- package/dist/cli/cli-port.d.ts +32 -0
- package/dist/cli/cli-port.js +82 -35
- package/dist/cli/cli-verify.d.ts +21 -0
- package/dist/cli/cli-verify.js +47 -3
- package/dist/cli/config-discovery.d.ts +35 -0
- package/dist/cli/config-discovery.js +163 -0
- package/dist/cli/doctor-daemon-line.js +4 -1
- package/dist/cli/doctor-project-line.d.ts +37 -0
- package/dist/cli/doctor-project-line.js +35 -0
- package/dist/cli/doctor-rows.d.ts +51 -0
- package/dist/cli/doctor-rows.js +54 -0
- package/dist/cli/doctor-sessions-line.d.ts +12 -0
- package/dist/cli/doctor-sessions-line.js +69 -0
- package/dist/cli/drive-attach.d.ts +99 -0
- package/dist/cli/drive-attach.js +203 -0
- package/dist/cli/drive-command.d.ts +13 -0
- package/dist/cli/drive-command.js +103 -0
- package/dist/cli/open-note.d.ts +20 -0
- package/dist/cli/open-note.js +37 -0
- package/dist/cli/port-holder.d.ts +10 -0
- package/dist/cli/port-holder.js +26 -2
- package/dist/cli/status-next-action.d.ts +37 -0
- package/dist/cli/status-next-action.js +61 -0
- package/dist/cli.js +119 -39
- package/dist/crawl/crawl-tools.js +12 -2
- package/dist/crawl/crawl.d.ts +13 -0
- package/dist/crawl/crawl.js +50 -2
- package/dist/events/contradictions.d.ts +46 -0
- package/dist/events/contradictions.js +35 -22
- package/dist/events/declared.d.ts +45 -0
- package/dist/events/declared.js +73 -0
- package/dist/events/echo-mismatch.d.ts +8 -2
- package/dist/events/echo-mismatch.js +33 -5
- package/dist/events/event-filters.d.ts +1 -1
- package/dist/events/event-filters.js +7 -4
- package/dist/events/predicate-eval.d.ts +17 -72
- package/dist/events/predicate-eval.js +117 -236
- package/dist/events/predicate-parse.js +31 -3
- package/dist/events/predicate-route.d.ts +32 -0
- package/dist/events/predicate-route.js +102 -0
- package/dist/events/predicate-schema.d.ts +99 -0
- package/dist/events/predicate-schema.js +309 -0
- package/dist/events/predicate.d.ts +8 -0
- package/dist/events/predicate.js +296 -22
- package/dist/flows/annotate-tools.js +3 -0
- package/dist/flows/annotate.js +18 -4
- package/dist/flows/coverage.d.ts +38 -5
- package/dist/flows/coverage.js +30 -4
- package/dist/flows/decision.d.ts +15 -0
- package/dist/flows/decision.js +1 -1
- package/dist/flows/flow-classify.js +1 -1
- package/dist/flows/flow-replay-run.js +8 -1
- package/dist/flows/flow-tools.js +21 -5
- package/dist/flows/heal-run.js +1 -1
- package/dist/flows/replay.js +3 -0
- package/dist/honesty/accepted-write.d.ts +3 -0
- package/dist/honesty/accepted-write.js +8 -3
- package/dist/honesty/already-true.js +15 -0
- package/dist/honesty/blind-spots.js +10 -2
- package/dist/honesty/honesty.d.ts +11 -0
- package/dist/honesty/honesty.js +1 -0
- package/dist/honesty/uncaptured-bodies.d.ts +4 -2
- package/dist/honesty/uncaptured-bodies.js +9 -2
- package/dist/honesty/unread-outcome.d.ts +8 -0
- package/dist/honesty/unread-outcome.js +36 -9
- package/dist/honesty/unsettled.d.ts +49 -0
- package/dist/honesty/unsettled.js +82 -0
- package/dist/honesty/verified.d.ts +36 -3
- package/dist/honesty/verified.js +54 -11
- package/dist/http-server.d.ts +19 -0
- package/dist/http-server.js +202 -4
- package/dist/impact/impact-recorder.d.ts +23 -0
- package/dist/impact/impact-recorder.js +76 -0
- package/dist/impact/impact-store.d.ts +47 -0
- package/dist/impact/impact-store.js +171 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +47 -10
- package/dist/init/agent-rules.d.ts +36 -0
- package/dist/init/agent-rules.js +132 -22
- package/dist/init/astro-patch.d.ts +2 -1
- package/dist/init/astro-patch.js +38 -6
- package/dist/init/capabilities.d.ts +22 -0
- package/dist/init/capabilities.js +76 -0
- package/dist/init/confirm.d.ts +114 -0
- package/dist/init/confirm.js +165 -0
- package/dist/init/connect-steps.d.ts +2 -0
- package/dist/init/connect-steps.js +50 -0
- package/dist/init/cra.js +3 -2
- package/dist/init/csp-check.d.ts +38 -0
- package/dist/init/csp-check.js +92 -0
- package/dist/init/csp-doctor.d.ts +25 -0
- package/dist/init/csp-doctor.js +49 -0
- package/dist/init/cursor.js +6 -9
- package/dist/init/detect.d.ts +8 -0
- package/dist/init/detect.js +33 -3
- package/dist/init/mcp-clients.d.ts +1 -0
- package/dist/init/mcp-clients.js +51 -7
- package/dist/init/mcp.d.ts +15 -0
- package/dist/init/mcp.js +19 -0
- package/dist/init/non-js-project.js +29 -5
- package/dist/init/plan-framework.d.ts +10 -0
- package/dist/init/plan-framework.js +78 -16
- package/dist/init/plan.d.ts +47 -6
- package/dist/init/plan.js +228 -69
- package/dist/init/run.d.ts +24 -2
- package/dist/init/run.js +157 -45
- package/dist/init/slash-command.d.ts +1 -1
- package/dist/init/slash-command.js +54 -6
- package/dist/init/snippets.d.ts +45 -5
- package/dist/init/snippets.js +194 -42
- package/dist/init/vite-config.js +53 -5
- package/dist/input/network-mock-tools.d.ts +19 -0
- package/dist/input/network-mock-tools.js +37 -5
- package/dist/input/scroll-find.d.ts +6 -0
- package/dist/input/scroll-find.js +17 -2
- package/dist/input/scroll-tools.js +4 -0
- package/dist/journal/attach-journal.d.ts +9 -1
- package/dist/journal/attach-journal.js +13 -2
- package/dist/journal/journal-query.d.ts +13 -0
- package/dist/journal/journal-query.js +28 -3
- package/dist/journal/workspace-gitignore.d.ts +10 -0
- package/dist/journal/workspace-gitignore.js +59 -0
- package/dist/license/license.js +1 -1
- package/dist/mcp/mcp-proxy.d.ts +35 -30
- package/dist/mcp/mcp-proxy.js +306 -104
- package/dist/mcp/mcp.d.ts +10 -1
- package/dist/mcp/mcp.js +70 -34
- package/dist/mcp/proxy-handshake.d.ts +82 -1
- package/dist/mcp/proxy-handshake.js +109 -2
- package/dist/mcp/proxy-lifecycle.d.ts +11 -2
- package/dist/mcp/proxy-lifecycle.js +12 -3
- package/dist/mcp/proxy-log.d.ts +63 -0
- package/dist/mcp/proxy-log.js +132 -0
- package/dist/mcp/server-instructions.d.ts +17 -0
- package/dist/mcp/server-instructions.js +56 -0
- package/dist/mcp/shared-params.d.ts +27 -0
- package/dist/mcp/shared-params.js +36 -0
- package/dist/pool/browser-pool.d.ts +22 -2
- package/dist/pool/browser-pool.js +44 -4
- package/dist/project/learned-routes.d.ts +24 -0
- package/dist/project/learned-routes.js +63 -0
- package/dist/project/project-store.d.ts +6 -0
- package/dist/project/project-store.js +25 -1
- package/dist/project/reticle-dir.d.ts +2 -0
- package/dist/project/reticle-dir.js +1 -0
- package/dist/session/connection-memory.d.ts +59 -0
- package/dist/session/connection-memory.js +108 -0
- package/dist/session/dev-command.d.ts +26 -0
- package/dist/session/dev-command.js +89 -0
- package/dist/session/dev-server-probe.d.ts +68 -0
- package/dist/session/dev-server-probe.js +102 -7
- package/dist/session/last-act.d.ts +26 -0
- package/dist/session/last-act.js +35 -1
- package/dist/session/live-control-tools.js +42 -5
- package/dist/session/no-session-diagnosis.d.ts +67 -2
- package/dist/session/no-session-diagnosis.js +236 -27
- package/dist/session/no-session-next-action.d.ts +46 -0
- package/dist/session/no-session-next-action.js +85 -0
- package/dist/session/no-session-watch.d.ts +40 -1
- package/dist/session/no-session-watch.js +174 -8
- package/dist/session/pending-commands.d.ts +12 -0
- package/dist/session/pending-commands.js +13 -1
- package/dist/session/ref-provenance.d.ts +54 -0
- package/dist/session/ref-provenance.js +61 -0
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +4 -0
- package/dist/session/session-manager.js +35 -5
- package/dist/session/session.d.ts +10 -1
- package/dist/session/session.js +146 -5
- package/dist/telemetry/app-instrumented.d.ts +8 -0
- package/dist/telemetry/app-instrumented.js +10 -0
- package/dist/telemetry/automation-hint.d.ts +17 -0
- package/dist/telemetry/automation-hint.js +71 -0
- package/dist/telemetry/bug-found.d.ts +15 -17
- package/dist/telemetry/bug-found.js +52 -21
- package/dist/telemetry/cli-telemetry.js +7 -1
- package/dist/telemetry/daemon-telemetry.js +24 -0
- package/dist/telemetry/feedback.js +1 -1
- package/dist/telemetry/init-telemetry.js +9 -1
- package/dist/telemetry/install-source.d.ts +56 -0
- package/dist/telemetry/install-source.js +74 -0
- package/dist/telemetry/instrumentation-stall.d.ts +50 -0
- package/dist/telemetry/instrumentation-stall.js +90 -0
- package/dist/telemetry/run-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +8 -0
- package/dist/telemetry/session-metrics.js +15 -0
- package/dist/telemetry/telemetry.d.ts +7 -1
- package/dist/telemetry/telemetry.js +26 -2
- package/dist/telemetry/tool-refused.d.ts +19 -0
- package/dist/telemetry/tool-refused.js +55 -0
- package/dist/telemetry/verification-of.js +46 -7
- package/dist/temp-dir.d.ts +27 -0
- package/dist/temp-dir.js +46 -0
- package/dist/tools/act-tools.js +209 -28
- package/dist/tools/assert-grade.d.ts +1 -1
- package/dist/tools/assert-grade.js +27 -5
- package/dist/tools/assert-verdict.js +49 -7
- package/dist/tools/browser-tools.js +10 -0
- package/dist/tools/contract-tools.js +4 -0
- package/dist/tools/dynamic-tools.js +16 -7
- package/dist/tools/error-recovery.d.ts +10 -0
- package/dist/tools/error-recovery.js +73 -9
- package/dist/tools/feedback-invite.js +1 -1
- package/dist/tools/invoke-tool.js +159 -26
- package/dist/tools/lease-hint.d.ts +30 -8
- package/dist/tools/lease-hint.js +65 -14
- package/dist/tools/lease-tools.d.ts +40 -1
- package/dist/tools/lease-tools.js +181 -83
- package/dist/tools/navigate-result.js +1 -1
- package/dist/tools/observe-tools.js +10 -4
- package/dist/tools/observed-nothing.js +1 -1
- package/dist/tools/react-grace.d.ts +52 -0
- package/dist/tools/react-grace.js +90 -0
- package/dist/tools/read-tools.js +67 -5
- package/dist/tools/resolve-target.d.ts +33 -0
- package/dist/tools/resolve-target.js +53 -0
- package/dist/tools/settle-in-flight.d.ts +94 -0
- package/dist/tools/settle-in-flight.js +146 -0
- package/dist/tools/snapshot-delta.d.ts +10 -0
- package/dist/tools/snapshot-delta.js +194 -9
- package/dist/tools/tool-kit.d.ts +8 -0
- package/dist/tools/tool-surface.d.ts +60 -0
- package/dist/tools/tool-surface.js +86 -1
- package/dist/tools/tools.js +61 -8
- package/dist/tools/unadvertised-help.js +9 -6
- package/docs/README.md +55 -11
- package/docs/actions.mdx +120 -0
- package/docs/agent-cheatsheet.md +95 -29
- package/docs/architecture.md +52 -35
- package/docs/benchmarks.md +127 -75
- package/docs/best-practices.mdx +216 -0
- package/docs/capabilities.mdx +534 -0
- package/docs/cli/affected.mdx +53 -0
- package/docs/cli/capsules.mdx +70 -0
- package/docs/cli/cloud.mdx +153 -0
- package/docs/cli/doctor.mdx +109 -0
- package/docs/cli/drive.mdx +74 -0
- package/docs/cli/feedback.mdx +67 -0
- package/docs/cli/gate.mdx +64 -0
- package/docs/cli/help.mdx +94 -0
- package/docs/cli/hunt.mdx +73 -0
- package/docs/cli/identify.mdx +76 -0
- package/docs/cli/init.mdx +121 -0
- package/docs/cli/kill.mdx +91 -0
- package/docs/cli/license.mdx +48 -0
- package/docs/cli/mcp.mdx +61 -0
- package/docs/cli/open.mdx +74 -0
- package/docs/cli/restart.mdx +60 -0
- package/docs/cli/rollback.mdx +35 -0
- package/docs/cli/serve.mdx +69 -0
- package/docs/cli/status.mdx +88 -0
- package/docs/cli/stop.mdx +64 -0
- package/docs/cli/telemetry.mdx +57 -0
- package/docs/cli/update.mdx +52 -0
- package/docs/cli/verify.mdx +76 -0
- package/docs/cli/version.mdx +39 -0
- package/docs/cli/watch.mdx +62 -0
- package/docs/cli.mdx +241 -0
- package/docs/debugging.md +16 -10
- package/docs/deploy-checks.md +45 -12
- package/docs/desktop.mdx +384 -0
- package/docs/docs.json +364 -0
- package/docs/enterprise.md +22 -16
- package/docs/faq.mdx +102 -0
- package/docs/fixtures.md +13 -7
- package/docs/flows.md +29 -23
- package/docs/for-agents.md +71 -0
- package/docs/frameworks.mdx +238 -0
- package/docs/gate-plan.md +48 -42
- package/docs/gates.md +28 -22
- package/docs/getting-started.md +129 -77
- package/docs/human-control.md +24 -18
- package/docs/index.mdx +143 -0
- package/docs/install-agentic.mdx +224 -0
- package/docs/install-manual.mdx +196 -0
- package/docs/instrumentation.mdx +238 -0
- package/docs/integration-patterns.md +41 -35
- package/docs/local-registry.md +19 -13
- package/docs/multi-agent-testing.md +19 -13
- package/docs/packages/babel-plugin.mdx +79 -0
- package/docs/packages/browser.mdx +111 -0
- package/docs/packages/core.mdx +116 -0
- package/docs/packages/electron.mdx +85 -0
- package/docs/packages/eslint-plugin.mdx +86 -0
- package/docs/packages/next.mdx +89 -0
- package/docs/packages/react.mdx +91 -0
- package/docs/packages/server.mdx +98 -0
- package/docs/packages/tauri.mdx +63 -0
- package/docs/packages/test.mdx +119 -0
- package/docs/packages/vite-plugin.mdx +94 -0
- package/docs/packages.mdx +218 -0
- package/docs/platform-integration.md +35 -26
- package/docs/predicates.mdx +248 -0
- package/docs/quickstart.mdx +257 -0
- package/docs/recipes.mdx +282 -0
- package/docs/skill-file.mdx +107 -0
- package/docs/state-management.mdx +199 -0
- package/docs/style.css +14 -0
- package/docs/system-map.md +50 -33
- package/docs/telemetry-contract.md +106 -52
- package/docs/telemetry-events.mdx +475 -0
- package/docs/telemetry.md +63 -55
- package/docs/testing.md +44 -6
- package/docs/token-efficiency.md +37 -27
- package/docs/tools-act-and-wait.mdx +173 -0
- package/docs/tools-act-sequence.mdx +137 -0
- package/docs/tools-act.mdx +95 -0
- package/docs/tools-assert.mdx +129 -0
- package/docs/tools-console.mdx +63 -0
- package/docs/tools-inspect.mdx +88 -0
- package/docs/tools-navigate.mdx +99 -0
- package/docs/tools-network.mdx +119 -0
- package/docs/tools-observe.mdx +145 -0
- package/docs/tools-overview.mdx +160 -0
- package/docs/tools-query.mdx +126 -0
- package/docs/tools-session-and-feedback.mdx +112 -0
- package/docs/tools-sessions.mdx +94 -0
- package/docs/tools-snapshot.mdx +129 -0
- package/docs/tools-state.mdx +104 -0
- package/docs/tools-tools-and-run.mdx +156 -0
- package/docs/tools-wait-for.mdx +85 -0
- package/docs/troubleshooting.mdx +263 -0
- package/docs/usage.md +209 -165
- package/docs/vs-chrome-devtools-mcp.mdx +123 -0
- package/docs/vs-playwright-mcp.mdx +125 -0
- package/docs/vs-screenshots.mdx +137 -0
- package/docs/what-is-reticle.mdx +63 -0
- package/docs/why-reticle.mdx +109 -0
- package/package.json +5 -5
- package/docs/desktop-apps.md +0 -256
- package/docs/matrix/2.5.0/claude-code-machine.json +0 -19
- package/docs/matrix/2.5.0/codex-machine.json +0 -20
- package/docs/matrix/2.5.0/cursor-machine.json +0 -22
- package/docs/matrix/2.5.0/gemini-machine.json +0 -22
- package/docs/matrix/2.5.0/opencode-machine.json +0 -22
- package/docs/matrix/2.5.0/vscode-machine.json +0 -22
- package/docs/matrix/2.5.0/windsurf-machine.json +0 -22
- package/docs/matrix/MATRIX.md +0 -26
- package/docs/matrix/README.md +0 -59
- package/docs/mint.json +0 -61
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle_act_and_wait
|
|
3
|
+
description: Act on an element and wait for a named consequence in one call. This is the tool that produces a verdict, and the one you should reach for by default.
|
|
4
|
+
icon: circle-check
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle_act_and_wait` performs one action on an element and waits for a named consequence, returning a verdict in the same call. Reach for it whenever an action is supposed to cause something: it is one of only two Reticle tools that produce a verdict, the other being [`reticle_assert`](/tools-assert).
|
|
8
|
+
|
|
9
|
+
This is the tool Reticle exists for. It does the act, observe and assert steps in one round trip, and it makes you name the expected consequence **before** the action runs.
|
|
10
|
+
|
|
11
|
+
That ordering is not a convenience. An agent that acts first and then decides what counts as success will always find something that counts. Naming the consequence up front is the difference between a check and a rationalisation.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"ref": "e105",
|
|
18
|
+
"action": "click",
|
|
19
|
+
"until": { "kind": "net", "method": "POST" }
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Real response. The `initiatorStack`, `storageDiffs` and per-event trace detail are trimmed out for length; nothing else is changed:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"verified": "yes",
|
|
28
|
+
"verifiedReason": "proved",
|
|
29
|
+
"because": "assertion held at presence grade over a clean capture with no channel disagreeing",
|
|
30
|
+
"effect": {
|
|
31
|
+
"ok": true,
|
|
32
|
+
"ref": "e105",
|
|
33
|
+
"action": "click",
|
|
34
|
+
"dispatched": true,
|
|
35
|
+
"settled": true,
|
|
36
|
+
"settleReason": null,
|
|
37
|
+
"testid": "login-submit",
|
|
38
|
+
"component": "Login",
|
|
39
|
+
"role": "button",
|
|
40
|
+
"name": "Sign in",
|
|
41
|
+
"effect": { "focusMoved": "e104->null", "domMutatedWithin": 8, "appeared": "Signing in…" },
|
|
42
|
+
"source": { "file": "src/components/Login.tsx", "line": 81, "column": 8 }
|
|
43
|
+
},
|
|
44
|
+
"verdict": {
|
|
45
|
+
"pass": true,
|
|
46
|
+
"evidence": {
|
|
47
|
+
"id": "n2",
|
|
48
|
+
"method": "POST",
|
|
49
|
+
"url": "http://localhost:8787/api/login",
|
|
50
|
+
"status": 200,
|
|
51
|
+
"ok": true,
|
|
52
|
+
"durationMs": 4,
|
|
53
|
+
"initiator": "fetch",
|
|
54
|
+
"statusText": "OK",
|
|
55
|
+
"contentType": "application/json; charset=utf-8",
|
|
56
|
+
"responseSize": 67,
|
|
57
|
+
"requestBody": "{\"email\":\"admin@reticle.dev\",\"password\":\"[REDACTED]\"}",
|
|
58
|
+
"responseBody": "{\"token\":\"[REDACTED]\",\"user\":{\"email\":\"admin@reticle.dev\"}}"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"trace": {
|
|
62
|
+
"window_ms": 31,
|
|
63
|
+
"summary": {
|
|
64
|
+
"total": 21,
|
|
65
|
+
"network": 1,
|
|
66
|
+
"domAdded": 0,
|
|
67
|
+
"domRemoved": 1,
|
|
68
|
+
"domChanged": 6,
|
|
69
|
+
"routeChanges": 0,
|
|
70
|
+
"consoleErrors": 0,
|
|
71
|
+
"animations": 0,
|
|
72
|
+
"signals": 1
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"summary": {
|
|
76
|
+
"net": { "total": 1, "errors": 0 },
|
|
77
|
+
"consoleErrors": 0,
|
|
78
|
+
"statePathsChanged": ["app"],
|
|
79
|
+
"storageKeysChanged": ["reticle.bench.authToken", "reticle.bench.sessionId"],
|
|
80
|
+
"stateDiffs": [
|
|
81
|
+
{ "path": "auth", "from": null, "to": "{\"email\":\"admin@reticle.dev\"}", "atMs": 44403 }
|
|
82
|
+
],
|
|
83
|
+
"signals": ["auth:granted"],
|
|
84
|
+
"layoutShift": 0.016486682891845704,
|
|
85
|
+
"longTasks": 0
|
|
86
|
+
},
|
|
87
|
+
"honesty": {
|
|
88
|
+
"grade": "presence",
|
|
89
|
+
"attribution": "window",
|
|
90
|
+
"coverage": { "pct": 100, "partial": false },
|
|
91
|
+
"integrity": { "clean": true, "issues": [] }
|
|
92
|
+
},
|
|
93
|
+
"since": 44395
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`trace` is a digest of what the app did in the window. When the counts are not enough, pass the top-level `since` cursor to [`reticle_observe`](/tools-observe) for the per-event timeline.
|
|
98
|
+
|
|
99
|
+
## The predicate grammar
|
|
100
|
+
|
|
101
|
+
`until` takes `{ kind, ...fields }`. The kinds:
|
|
102
|
+
|
|
103
|
+
| Kind | Asserts |
|
|
104
|
+
| ------------------------- | -------------------------------------------------------------- |
|
|
105
|
+
| `signal` | The app fired a named signal, the strongest evidence available |
|
|
106
|
+
| `state` | A store path reached a value |
|
|
107
|
+
| `net` | A request matched; `count` asserts an **exact** number |
|
|
108
|
+
| `route` | The route **changed** |
|
|
109
|
+
| `element` | An element appeared; `absent: true` asserts it went away |
|
|
110
|
+
| `text` | Text appeared or, with `absent`, disappeared |
|
|
111
|
+
| `console` | Something logged; `absent: true` asserts a clean console |
|
|
112
|
+
| `animation` | An animation ran or finished |
|
|
113
|
+
| `settled` | The page went quiet |
|
|
114
|
+
| `allOf` / `anyOf` / `not` | Combine the above |
|
|
115
|
+
|
|
116
|
+
### Predicates that catch real bugs
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{ "until": { "kind": "net", "method": "POST", "count": 1 } }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Exactly one request. Double-submit fails this at two, and no screenshot will ever tell you.
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{ "until": { "kind": "console", "absent": true } }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The action completed **and** logged nothing. "It worked but threw a warning" stops passing.
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{ "until": { "kind": "signal", "name": "deploy:created" } }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The app itself declared success. This is the highest grade of evidence, and it requires [instrumenting your app](/instrumentation). Which is the main reason to bother.
|
|
135
|
+
|
|
136
|
+
## Reading `verified`
|
|
137
|
+
|
|
138
|
+
<CardGroup cols={3}>
|
|
139
|
+
<Card title="yes" icon="circle-check">
|
|
140
|
+
The named consequence happened, with evidence attached.
|
|
141
|
+
</Card>
|
|
142
|
+
<Card title="no" icon="circle-xmark">
|
|
143
|
+
It did not. A finding, with a source pointer.
|
|
144
|
+
</Card>
|
|
145
|
+
<Card title="unknown" icon="circle-question">
|
|
146
|
+
Reticle could not tell. **Not a pass.** Report it as unknown.
|
|
147
|
+
</Card>
|
|
148
|
+
</CardGroup>
|
|
149
|
+
|
|
150
|
+
## The `honesty` block
|
|
151
|
+
|
|
152
|
+
`grade` is how strong the evidence was. A fired signal outranks an element appearing. `coverage.partial: true` means Reticle did not observe the whole window. `integrity.clean: false` means something interfered with the capture and the verdict deserves less trust.
|
|
153
|
+
|
|
154
|
+
A verification tool that cannot describe the quality of its own evidence is asking you to take its word for it, which is precisely the problem we started with.
|
|
155
|
+
|
|
156
|
+
## Arguments
|
|
157
|
+
|
|
158
|
+
| Argument | What it does |
|
|
159
|
+
| --- | --- |
|
|
160
|
+
| `ref`, `action`, `args` | As [`reticle_act`](/tools-act) |
|
|
161
|
+
| `until` | The predicate to wait for. Omit it to wait for the page to settle |
|
|
162
|
+
| `predicate` | Alias for `until`, the name `assert` and `wait_for` use |
|
|
163
|
+
| `timeout_ms` | Maximum wait, defaulting to 4000. `0` evaluates the predicate once, no wait |
|
|
164
|
+
| `refuseWhenThrottled` | Throw rather than act on a throttled tab |
|
|
165
|
+
|
|
166
|
+
Omitting `until` waits for network and DOM idle, which is the deterministic replacement for a fixed sleep. To assert a consequence **and** settle, combine them:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"kind": "allOf",
|
|
171
|
+
"predicates": [{ "kind": "signal", "name": "deploy:created" }, { "kind": "settled" }]
|
|
172
|
+
}
|
|
173
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle_act_sequence
|
|
3
|
+
description: Run several actions in order in one round trip. Fill, fill, submit. Instead of paying a full turn for each step.
|
|
4
|
+
icon: layer-group
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle_act_sequence` runs several actions in order in a single round trip. Reach for it whenever a journey needs more than one step, such as fill, fill, submit, and then prove the outcome once with [`reticle_act_and_wait`](/tools-act-and-wait), because a sequence itself produces no verdict.
|
|
8
|
+
|
|
9
|
+
A login is three actions. Driving it one call at a time costs three round trips and three turns of context. `reticle_act_sequence` does it in one.
|
|
10
|
+
|
|
11
|
+
This tool exists because of a measured problem: agents were driving forms one call at a time, over and over. Those repeats were not retries. The calls succeeded and got repeated, because the batching tool was not advertised and so nobody knew it was there.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"steps": [
|
|
18
|
+
{ "ref": "e603", "action": "fill", "args": { "value": "admin@reticle.dev" } },
|
|
19
|
+
{ "ref": "e604", "action": "fill", "args": { "value": "correct-horse-battery-staple" } },
|
|
20
|
+
{ "ref": "e605", "action": "click" }
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Real response. Each `effects[]` entry also carries `targetMatched`, `visible`, `enabled`, `defaultPrevented`, `occluded`, `occludedBy` and `scrolledIntoView`, and each `steps[]` entry also carries `dispatched`, `settled`, `settleReason`, `component`, `role` and `name`. Those are trimmed here for length:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"since": 3915,
|
|
30
|
+
"dispatched": true,
|
|
31
|
+
"result": {
|
|
32
|
+
"ok": true,
|
|
33
|
+
"count": 3,
|
|
34
|
+
"effects": [
|
|
35
|
+
{
|
|
36
|
+
"dispatched": true,
|
|
37
|
+
"focusMoved": "null->e603",
|
|
38
|
+
"valueChanged": false,
|
|
39
|
+
"domMutatedWithin": 0
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"dispatched": true,
|
|
43
|
+
"focusMoved": "e603->e604",
|
|
44
|
+
"valueChanged": true,
|
|
45
|
+
"domMutatedWithin": 9
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"dispatched": true,
|
|
49
|
+
"focusMoved": "e604->null",
|
|
50
|
+
"domMutatedWithin": 15,
|
|
51
|
+
"appeared": "Signing in… | Invalid email or password | Sign in"
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
"steps": [
|
|
55
|
+
{
|
|
56
|
+
"ref": "e603",
|
|
57
|
+
"action": "fill",
|
|
58
|
+
"testid": "login-email",
|
|
59
|
+
"source": { "file": "src/components/Login.tsx", "line": 48 }
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"ref": "e604",
|
|
63
|
+
"action": "fill",
|
|
64
|
+
"testid": "login-password",
|
|
65
|
+
"source": { "file": "src/components/Login.tsx", "line": 59 }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"ref": "e605",
|
|
69
|
+
"action": "click",
|
|
70
|
+
"testid": "login-submit",
|
|
71
|
+
"source": { "file": "src/components/Login.tsx", "line": 81 }
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Read that response again
|
|
79
|
+
|
|
80
|
+
`ok: true`. `count: 3`. Every step dispatched. And the login **failed**, look at `appeared`:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
"appeared": "Signing in… | Invalid email or password | Sign in"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
That password was wrong. The app rejected it. And this tool still reported `ok: true`, correctly, because `ok` means _the three actions were dispatched_, which they were.
|
|
87
|
+
|
|
88
|
+
<Warning>
|
|
89
|
+
This is the whole reason `act` and `act_sequence` do not produce verdicts. `ok: true` is a
|
|
90
|
+
statement about the input, not about the outcome. Follow a sequence with
|
|
91
|
+
[`reticle_act_and_wait`](/tools-act-and-wait) on the final step, or with an
|
|
92
|
+
[`reticle_assert`](/tools-assert), or you have proved nothing.
|
|
93
|
+
</Warning>
|
|
94
|
+
|
|
95
|
+
The honest pattern is: batch the setup, prove the outcome.
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"steps": [
|
|
100
|
+
{ "ref": "e603", "action": "fill", "args": { "value": "admin@reticle.dev" } },
|
|
101
|
+
{ "ref": "e604", "action": "fill", "args": { "value": "correct-password" } }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
then
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{ "ref": "e605", "action": "click", "until": { "kind": "signal", "name": "auth:granted" } }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
which returns the verdict the sequence could not:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"verified": "yes",
|
|
117
|
+
"verifiedReason": "proved",
|
|
118
|
+
"because": "assertion held at signal grade over a clean capture with no channel disagreeing",
|
|
119
|
+
"verdict": {
|
|
120
|
+
"pass": true,
|
|
121
|
+
"evidence": { "name": "auth:granted", "data": { "email": "admin@reticle.dev" } }
|
|
122
|
+
},
|
|
123
|
+
"honesty": { "grade": "signal", "coverage": { "pct": 100, "partial": false } }
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Two calls instead of four, and the last one returns a verdict. Note `grade: "signal"`, the strongest Reticle awards, because the app said so itself.
|
|
128
|
+
|
|
129
|
+
## What each step reports
|
|
130
|
+
|
|
131
|
+
Every step comes back with the same `effect` fields as [`reticle_act`](/tools-act): `valueChanged`, `focusMoved`, `domMutatedWithin`, `occluded`. Plus its `testid`, `component` and `source`. When a sequence goes wrong, that per-step detail tells you which step, and which line of which file.
|
|
132
|
+
|
|
133
|
+
<Note>
|
|
134
|
+
Steps run in order and do not stop on a soft failure, because "the field rejected the value" is
|
|
135
|
+
not an exception. It's a result you need to see. Read `effects[]` rather than assuming `ok: true`
|
|
136
|
+
means all three did what you wanted.
|
|
137
|
+
</Note>
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle_act
|
|
3
|
+
description: Perform an action without checking the result. Useful for setup steps, and dangerous as a final step, because ok means dispatched, not worked.
|
|
4
|
+
icon: hand-pointer
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle_act` clicks, fills, types, selects, drags. It does exactly one thing and makes exactly one promise: the event was dispatched.
|
|
8
|
+
|
|
9
|
+
<Warning>
|
|
10
|
+
`reticle_act` **proves nothing**. If the action is supposed to cause something, use
|
|
11
|
+
[`reticle_act_and_wait`](/tools-act-and-wait) and get the verdict in the same call. A drive that
|
|
12
|
+
ends on `reticle_act` has no result.
|
|
13
|
+
</Warning>
|
|
14
|
+
|
|
15
|
+
## Example
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{ "ref": "e104", "action": "fill", "args": { "value": "reticle" } }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Real response:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"since": 27544,
|
|
26
|
+
"inputMode": "synthetic",
|
|
27
|
+
"inputModeReason": "not-a-pointer-action",
|
|
28
|
+
"dispatched": true,
|
|
29
|
+
"settled": true,
|
|
30
|
+
"settleReason": null,
|
|
31
|
+
"result": {
|
|
32
|
+
"ok": true,
|
|
33
|
+
"ref": "e104",
|
|
34
|
+
"action": "fill",
|
|
35
|
+
"dispatched": true,
|
|
36
|
+
"settled": true,
|
|
37
|
+
"settleReason": null,
|
|
38
|
+
"testid": "login-password",
|
|
39
|
+
"component": "Login",
|
|
40
|
+
"role": "textbox",
|
|
41
|
+
"name": "Password",
|
|
42
|
+
"effect": {
|
|
43
|
+
"focusMoved": "null->e104",
|
|
44
|
+
"valueChanged": true,
|
|
45
|
+
"domMutatedWithin": 9
|
|
46
|
+
},
|
|
47
|
+
"source": { "file": "src/components/Login.tsx", "line": 59, "column": 8 }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
<Note>
|
|
53
|
+
The `effect` block only lists what is worth knowing. Fields sitting at their uninformative default
|
|
54
|
+
are **omitted**, so a clean action collapses to its consequence. An absent `dispatched`,
|
|
55
|
+
`targetMatched`, `visible` or `enabled` means `true`; an absent `occluded`, `scrolledIntoView`,
|
|
56
|
+
`valueChanged` or `defaultPrevented` means `false`; an absent `focusMoved` or `occludedBy` means
|
|
57
|
+
`null`. Do not read a missing field as a failure.
|
|
58
|
+
</Note>
|
|
59
|
+
|
|
60
|
+
## Actions
|
|
61
|
+
|
|
62
|
+
`click` · `dblclick` · `hover` · `focus` · `blur` · `fill` · `type` · `clear` · `select` · `check` · `uncheck` · `submit` · `press` · `upload` · `scrollIntoView` · `drag` · `webmcp`
|
|
63
|
+
|
|
64
|
+
| Action | Arguments |
|
|
65
|
+
| ---------------- | --------------------------------------------------------------- |
|
|
66
|
+
| `fill`, `select` | `{ value }` |
|
|
67
|
+
| `type`, `press` | `{ text }`. For `press`, the key _name_, e.g. `Escape` or `Tab` |
|
|
68
|
+
| `drag` | `{ toRef }`. The ref to drop onto |
|
|
69
|
+
| `upload` | file arguments |
|
|
70
|
+
|
|
71
|
+
## Reading the effect block
|
|
72
|
+
|
|
73
|
+
This is where `act` earns its place even though it proves nothing.
|
|
74
|
+
|
|
75
|
+
- **`valueChanged: true`**. The field actually took the value. `false` on a `fill` usually means the input is controlled and rejected it, or it's readonly.
|
|
76
|
+
- **`focusMoved: "null->e104"`**, focus went where you expected.
|
|
77
|
+
- **`domMutatedWithin: 9`**, something re-rendered within 9ms. A `fill` that mutates nothing often means no handler is attached.
|
|
78
|
+
- **`defaultPrevented`**. A handler called `preventDefault()`, which is why your form didn't submit.
|
|
79
|
+
- **`occluded` / `occludedBy`**. The click landed on something else. This is the answer to at least half of all "the button doesn't work" reports.
|
|
80
|
+
|
|
81
|
+
## `settled: false` is not a failure
|
|
82
|
+
|
|
83
|
+
`settled: true` with `settleReason: null`, as above, means a real frame flushed before Reticle stopped watching. `settled: false` with `settleReason: "timeout"` means the page was still busy. On a `fill` that's normal and uninteresting. On a click you expected to complete something, it's a hint that you wanted `act_and_wait` with an explicit `until`. A settle timeout never fails the tool.
|
|
84
|
+
|
|
85
|
+
## `inputMode` tells you how real the input was
|
|
86
|
+
|
|
87
|
+
`synthetic` means Reticle dispatched events programmatically. `real` means native CDP input, available under `reticle drive`. Synthetic input is fine for the overwhelming majority of apps; a few drag-and-drop and pointer-gesture libraries only respond to the real thing.
|
|
88
|
+
|
|
89
|
+
`inputModeReason` explains any choice Reticle made on your behalf, so it is never silent. `not-a-pointer-action` above means a `fill` has no pointer path to take, not that real input was unavailable. Clicks default to the occlusion-honest synthetic path even when CDP is configured; pass `args.native: true` to force a trusted native click for file pickers and clipboard access.
|
|
90
|
+
|
|
91
|
+
<Warning>
|
|
92
|
+
When the tab is backgrounded, synthetic timers and pointer gestures can silently no-op. Every
|
|
93
|
+
response carries a `warning` when the tab is throttled. Pass `refuseWhenThrottled: true` to make
|
|
94
|
+
Reticle throw instead of pretending it acted.
|
|
95
|
+
</Warning>
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle_assert
|
|
3
|
+
description: Evaluate a predicate against what the app actually did, and get a verdict. Including a clear explanation when it fails.
|
|
4
|
+
icon: gavel
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle_assert` evaluates a predicate against what the app actually did and returns a verdict: `verified` plus `pass`, evidence when it holds, and `expected` versus `observed` when it does not. Reach for it when you want a verdict on something you did not just cause, or on several actions at once.
|
|
8
|
+
|
|
9
|
+
It is the second of the two tools that produce a verdict, the other being [`reticle_act_and_wait`](/tools-act-and-wait). It takes the same predicate grammar and evaluates it against what already happened.
|
|
10
|
+
|
|
11
|
+
## A real failure
|
|
12
|
+
|
|
13
|
+
Failures are more instructive than passes, so here is one. I asserted a route change to `/` on a page that was already at `/`:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{ "predicate": { "kind": "route", "pathname": "/" } }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"verified": "no",
|
|
22
|
+
"verifiedReason": "assertion_failed",
|
|
23
|
+
"because": "the declared consequence did not hold",
|
|
24
|
+
"pass": false,
|
|
25
|
+
"failureReason": "no route change observed",
|
|
26
|
+
"observed": "no route change in the window",
|
|
27
|
+
"expected": "a route change to /",
|
|
28
|
+
"assertion": "route.changed",
|
|
29
|
+
"source": "src/components/Login.tsx:81",
|
|
30
|
+
"buffer": {
|
|
31
|
+
"held": 536,
|
|
32
|
+
"dropped": 11,
|
|
33
|
+
"note": "event buffer evicted older events (age/size cap): a negative result here may be a false negative; the evidence may have expired. Grade sooner or widen the buffer."
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
<Note>
|
|
39
|
+
The route predicate's field is `pathname`. `path` is accepted as an alias and rewritten, but
|
|
40
|
+
`pathname` is what the published schema declares, so it is the one to write.
|
|
41
|
+
</Note>
|
|
42
|
+
|
|
43
|
+
<Warning>
|
|
44
|
+
Read `assertion: "route.changed"` carefully. The `route` predicate asserts that the route
|
|
45
|
+
**changed**, not that it currently equals a value. Asserting the route you are already on will
|
|
46
|
+
always fail. This catches people out, and the response says so in `expected` rather than leaving
|
|
47
|
+
you to work it out.
|
|
48
|
+
</Warning>
|
|
49
|
+
|
|
50
|
+
Note also `expected` and `observed` side by side. A verdict that says only "failed" makes you go digging; this one tells you what it wanted, what it saw, and where in your source the relevant element lives.
|
|
51
|
+
|
|
52
|
+
## A failure that names the real value
|
|
53
|
+
|
|
54
|
+
The same shape on a store read, which is the strongest kind of failure you can get, because it quotes the app's own data back at you:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"predicate": { "kind": "state", "store": "app", "path": "deployments.0.status", "equals": "live" }
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"verified": "no",
|
|
65
|
+
"verifiedReason": "assertion_failed",
|
|
66
|
+
"because": "the declared consequence did not hold",
|
|
67
|
+
"pass": false,
|
|
68
|
+
"failureReason": "state 'deployments.0.status' is \"queued\", expected \"live\"",
|
|
69
|
+
"observed": "deployments.0.status = \"queued\"",
|
|
70
|
+
"expected": "deployments.0.status = \"live\"",
|
|
71
|
+
"assertion": "state.equals",
|
|
72
|
+
"evidence": { "store": "app", "path": "deployments.0.status", "value": "queued" },
|
|
73
|
+
"source": "src/components/Login.tsx:81"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## A pass can still come with a warning
|
|
78
|
+
|
|
79
|
+
A presence-only predicate passes and tells you not to trust it much:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"verified": "yes",
|
|
84
|
+
"pass": true,
|
|
85
|
+
"evidence": [
|
|
86
|
+
{
|
|
87
|
+
"ref": "e606",
|
|
88
|
+
"role": "alert",
|
|
89
|
+
"name": "Invalid email or password",
|
|
90
|
+
"visible": true,
|
|
91
|
+
"source": "src/components/Login.tsx:72",
|
|
92
|
+
"states": ["present", "visible", "enabled"]
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"advice": "This predicate only checks element/text presence, not an observable consequence. A locator healed to the wrong element (or a stale render) can satisfy it while the feature is broken. Prefer a { signal } or { net } assertion (or allOf it with one) so green means the feature actually worked."
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Arguments
|
|
100
|
+
|
|
101
|
+
| Argument | What it does |
|
|
102
|
+
| ------------------------ | ----------------------------------------------------------------- |
|
|
103
|
+
| `predicate` (or `until`) | `{ kind, ...fields }`. See the [predicate reference](/predicates) |
|
|
104
|
+
| `timeout_ms` | If above zero, wait this long before failing. Default `0` |
|
|
105
|
+
| `since` | Cursor from a prior act. Scope to events after that action |
|
|
106
|
+
|
|
107
|
+
## Scope it with `since`
|
|
108
|
+
|
|
109
|
+
By default an assertion already counts only events since your last act, so a signal buffered before the action cannot fake a pass. Pass `since` when you want to set that window explicitly: to scope to one particular earlier action, or to widen it deliberately across several.
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{ "predicate": { "kind": "net", "method": "POST" }, "since": 44395 }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The cursor comes from the preceding `reticle_act` response. Use it whenever you are asserting something an action was supposed to cause.
|
|
116
|
+
|
|
117
|
+
## When to use assert over act_and_wait
|
|
118
|
+
|
|
119
|
+
Use [`reticle_act_and_wait`](/tools-act-and-wait) when you are performing the action. Use `reticle_assert` when:
|
|
120
|
+
|
|
121
|
+
- you are checking a precondition before acting;
|
|
122
|
+
- the state was reached by several actions and you want one verdict over the lot;
|
|
123
|
+
- you want to assert something extra about an action you already ran, using its `since` cursor.
|
|
124
|
+
|
|
125
|
+
<Note>
|
|
126
|
+
`verified: "unknown"` means Reticle could not tell. It is not a pass, and it is not a failure, it
|
|
127
|
+
is a statement that the evidence was insufficient. Report it as unknown rather than rounding it in
|
|
128
|
+
either direction.
|
|
129
|
+
</Note>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reticle_console
|
|
3
|
+
description: The console log, filtered by level, and an empty result that tells you it is a real reading rather than a missing one.
|
|
4
|
+
icon: terminal
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`reticle_console` returns the app's console log, filtered by level, and tells you whether an empty result is a real reading or a missing one. Reach for it as the fast triage read after something goes wrong, and assert `{ "kind": "console", "absent": true }` when you want a clean console to be part of the pass.
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{ "limit": 3 }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Real response from a page with a clean console:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"logs": [],
|
|
18
|
+
"buffer": {
|
|
19
|
+
"held": 535,
|
|
20
|
+
"dropped": 10,
|
|
21
|
+
"note": "event buffer evicted older events (age/size cap): a negative result here may be a false negative; the evidence may have expired. Grade sooner or widen the buffer."
|
|
22
|
+
},
|
|
23
|
+
"observed": true,
|
|
24
|
+
"note": "no console lines; the observation ran and found none, which is a result, not a missing reading",
|
|
25
|
+
"cost": { "bytes": 338, "tokens": 85 }
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## The empty result is the interesting one
|
|
30
|
+
|
|
31
|
+
An empty array is ambiguous in almost every tool that returns one. Did nothing happen, or did the observation not run? Reticle answers both:
|
|
32
|
+
|
|
33
|
+
- **`observed: true`** with that `note`. The observation ran and genuinely found nothing. You may treat a clean console as a fact.
|
|
34
|
+
- **`buffer.dropped: 10`**, older events were evicted. If you are asking about something from a while ago, the honest answer is "not in what I still have", not "it didn't happen".
|
|
35
|
+
|
|
36
|
+
Read both fields together. `observed: true` with a non-zero `dropped` count means _recently_ clean, which is usually what you wanted but is not the same as _always_ clean.
|
|
37
|
+
|
|
38
|
+
## Arguments
|
|
39
|
+
|
|
40
|
+
| Argument | What it does |
|
|
41
|
+
| ----------------- | ---------------------------------------------------- |
|
|
42
|
+
| `level` | `log` · `warn` · `error` · `info` |
|
|
43
|
+
| `limit` | Most recent N. Older matches are dropped and counted |
|
|
44
|
+
| `actionId` | Only lines attributed to one action |
|
|
45
|
+
| `since` / `until` | Cursors from a prior act |
|
|
46
|
+
|
|
47
|
+
## The check worth making by default
|
|
48
|
+
|
|
49
|
+
Plenty of features "work" while quietly throwing. Assert the clean console as part of the action rather than checking afterwards:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{ "ref": "e605", "action": "click", "until": { "kind": "console", "absent": true } }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That fails if the click succeeds _and_ logs an error, which is exactly the case a human reviewer tends to wave through.
|
|
56
|
+
|
|
57
|
+
<Tip>
|
|
58
|
+
`level: "error"` is the fast triage read. If it comes back empty with `observed: true`, stop
|
|
59
|
+
looking at the console and go look at [`reticle_network`](/tools-network) or
|
|
60
|
+
[`reticle_state`](/tools-state) instead. That is a real capture from this fixture:
|
|
61
|
+
`{"logs":[],"observed":true,"cost":{"bytes":337,"tokens":85}}`, eighty-five tokens to rule out a
|
|
62
|
+
whole class of bug.
|
|
63
|
+
</Tip>
|