本文へ移動
cccskills
無料GitHub で公開

verify-optimistic-update

Prove a UI that updates before the server answers puts things back and says so when the request fails, and keeps the change when it succeeds. Use when a like, toggle, rename, reorder, delete or add-to-cart updates instantly, when an optimistic update was added or changed, or when a user reports a change that "saved" but was gone after a reload.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md5.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

An optimistic update is a promise the server can break

Updating the UI before the server answers makes an app feel fast. It also means the UI claims something the server has not agreed to yet. The failure path, where the request fails and the UI has to take the claim back, is the one nobody clicks through, because on a working backend it never happens.

Reticle can make it happen in the running app. Not installed? RETICLE_INSTALL_SOURCE=npx_skill npx @reticlehq/server@latest init, then the install-and-verify skill.

Read this before you start: failing a request needs a browser Reticle owns

reticle_network_mock works in a leased tab (reticle_run({ tool: "reticle_lease", args: { action: "acquire", url } })) or a driven one, and not through the always-on SDK, which answers { ok: false, reason: "no-cdp-provider" }. Without one, do step 4 (the success path) and report the rollback as unknown. Driving the happy path and reporting that rollback works is the one thing you may not do.

Confirm the session can observe first: reticle_session({ action: "list" }). A hidden or throttled tab can accept a click and render nothing.

1. Make the save fail, slowly

reticle_run({ tool: "reticle_network_mock", sessionId, args: {
  mocks: [{ urlContains: "/api/todos", method: "PATCH", status: 500, delayMs: 1500 }],
}})

The delay is what makes the optimistic state observable. Without it the failure can land before anything is on screen, and you cannot tell "rolled back" from "never updated".

2. Act, and prove the optimistic state appears

Get the control's ref with reticle_look({ action: "page", sessionId, mode: "interactive" }), then name the optimistic state before you click:

reticle_act_and_wait({ sessionId, ref: "<rename or toggle>", action: "click", until:
  { kind: "text", contains: "Buy oat milk" }
})

This proves the UI updated before the server answered. It is the claim the next step checks is taken back.

3. Prove it reverts, and says why

Once the request has failed, the new value must be gone, the old one back, and the user told. Name the app's real failure message, scoped to its alert, because any other alert already on the page would satisfy a bare role check:

reticle_assert({ sessionId, timeout_ms: 5000, predicate: { kind: "allOf", predicates: [
  { kind: "net", urlContains: "/api/todos", method: "PATCH", status: 500 },
  { kind: "text", contains: "Buy oat milk", absent: true },
  { kind: "text", contains: "Buy milk" },
  { kind: "text", contains: "Could not save", scope: "[role=alert]" },
  { kind: "console", level: "error", absent: true },
]}})

If the app keeps its state in a registered store, check the store too, because a UI can roll back on screen while the store keeps the optimistic value:

reticle_assert({ sessionId, predicate: { kind: "state", path: "todos.0.title", equals: "Buy milk" } })

4. Remove the mock, and prove success sticks

Clear the mock, then make the same change again from the state the rollback left. The ref from step 2 may be stale after a re-render, and a rename needs its new value entered again, so read the page first:

reticle_run({ tool: "reticle_network_mock", sessionId, args: { clear: true } })
reticle_look({ action: "page", sessionId, mode: "interactive" })

Redo whatever set up the edit (for a rename, reticle_act the field with the new value), then save and name the outcome:

reticle_act_and_wait({ sessionId, ref: "<save or toggle>", action: "click", until: { kind: "allOf", predicates: [
  { kind: "net", urlContains: "/api/todos", method: "PATCH", ok: true },
  { kind: "text", contains: "Buy oat milk" },
]}})

Then reload and prove the server kept it, which is what "saved" means. Use a real reload and wait for the new page, not a navigate to the URL you are already on:

reticle_navigate({ sessionId, reload: true })

It must answer confirmed: true with a sessionId. Assert on that session, which is the reloaded page:

reticle_assert({ sessionId: "<sessionId from the reload>", predicate: { kind: "text", contains: "Buy oat milk" } })

If the reload is not confirmed, report persistence as unknown.

Honesty

Only verified: "yes" is a pass. A verdict taken under a mock is about the mocked condition, so say which endpoint you failed and with what status. Clear every mock before handing back, or the next session sees a backend that fails every save.


Capability reference: curl https://docs.reticle.sh/capabilities.md. Everything else: curl https://docs.reticle.sh/llms.txt.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Test-driven development for behaviour a unit test cannot reach, by writing the expectation against the running app before writing the code. Declare the consequence first, watch it fail, implement, watch it pass. Use when building a user-facing feature, when the user asks for TDD on UI or full-stack work, when a unit test cannot express the outcome that matters, or when you want a red-green loop that runs against the real app instead of mocks.

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

Sweep a whole running web app for what is broken, without writing a script or knowing the codebase. Clicks every reachable control and reports dead buttons, console errors, failed requests, and places where the API and the screen disagree. Use on an unfamiliar codebase, before a release, after a big merge or dependency bump, when the user asks for a smoke test or a health check, or when someone says "just check everything still works".

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

Find out why something in a running web app does not work, when the console is empty and the code looks correct. Reads the click, the request, the store and the console together and returns the file:line to open. Use when a button does nothing, a form will not submit, data will not load, a page renders blank or stale, a modal will not close, or the user says "it's broken" and the code review says it is fine.

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

Check that the UI you actually rendered uses the design system, by reading computed styles in the running app against the project's design tokens. Catches hardcoded hex colors, off-palette backgrounds, invisible or unusable controls, and animations that never ran. Use after building or restyling a component, when a design review is wanted, when a UI looks slightly off but nobody can say why, or when a design system exists and nothing checks whether the code follows it.

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

Drive and verify an Electron or Tauri desktop app from the inside, including the main-process and Rust IPC calls a browser tool cannot see. Use when a desktop app needs testing, when a feature works in the browser but not in the packaged app, when an IPC or invoke call needs proving, when a desktop screenshot or visual diff is wanted, or when you need a headless run of a desktop UI in CI.

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

Find out why the tests pass but the app is broken. Catches false greens: a green suite over a feature that does not work, a mocked API standing in for a real one, an assertion that holds no matter what the app does, a click handler wired to nothing. Use when the suite is green and the user says it is broken, when a test never fails, when coverage looks fine but bugs still ship, or before trusting a passing run you did not watch.

日本語の概要は準備中です。原文の説明を表示しています。

reticlehq/reticle1,2102026年10月12日 更新

reticlehq のスキルをすべて見る

このスキルの問題を報告する