Skip to main content

fixer

Prove a bug exists on camera, fix it, then prove it's gone on the same camera — a closed loop that returns before/after visual evidence (screenshots, GIF, video) plus a written verdict per issue. Also runs in VERIFY mode — prove an already-shipped change meets its original requirement and return a client-readable verdict. Use when chasing reported bugs or visual regressions, when "is this actually fixed?" needs proof rather than a claim, when a fix has to be shown to a user/client, or when verifying someone's merged PR is genuinely done against its spec. Sibling of walkabout (borrows its recorder) and the self-refining loop (borrows its iterate-until-done).

معلومات المصدر

المستودع
jezweb/fixer
آخر نشاط في المصدر
١٧ يونيو ٢٠٢٦ في ٠٩:٥٢
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
fixer
description
Prove a bug exists on camera, fix it, then prove it's gone on the same camera — a closed loop that returns before/after visual evidence (screenshots, GIF, video) plus a written verdict per issue. Also runs in VERIFY mode — prove an already-shipped change meets its original requirement and return a client-readable verdict. Use when chasing reported bugs or visual regressions, when "is this actually fixed?" needs proof rather than a claim, when a fix has to be shown to a user/client, or when verifying someone's merged PR is genuinely done against its spec. Sibling of walkabout (borrows its recorder) and the self-refining loop (borrows its iterate-until-done).
# fixer — catch it red-handed, then prove it's dead A bug isn't fixed because the code changed and the tests went green. It's fixed when the **same capture that caught it misbehaving** now shows it behaving — same viewport, same steps, same checkpoints, only the result different. fixer is that closed loop, and the deliverable is the **evidence**, not the assertion. The shape, per issue: ``` SCOPE → PROVE-BEFORE → DIAGNOSE → FIX → PROVE-AFTER → PRESENT → (loop) the indictment root cause the acquittal ``` fixer runs in **two modes** that share all the machinery below (the camera, the blind-audit gate, the recorder, the proof gates): - **FIX** (default) — a reported bug. Prove it broken, fix it, prove it fixed. The loop above. - **VERIFY** (acceptance) — an *already-shipped* change (a merged PR, often someone else's work) that someone needs to *trust* is done. There's no "prove broken" half: the source of truth is the **original requirement**, not a bug, and the output is an acceptance verdict + a client-readable ✓, not a fix. See [**Verify mode**](#verify-mode-acceptance--prove-someone-elses-ship-is-done) below. You **own** three things: the **case file** (`templates/case-file.md`, one per issue, the contract everything hangs off), the **before/after assembler** (`templates/compare.mjs`), and the **CDP recorder** (`templates/record-cdp.example.mjs` — bundled so the video leg needs no walkabout install). Everything else you **borrow** — don't rebuild it: | Need | Borrow | |---|---| | Stills + DOM snapshot on any live URL | `playwright-cli` (`/playwright-cli` skill) | | Moving video without shimmer | the bundled `record-cdp` recorder (`templates/record-cdp.example.mjs`) — CDP `Page.startScreencast` → timestamped JPEG frames → ffmpeg; same technique as walkabout, no walkabout dependency. **Never** Playwright `recordVideo` — it writes blink-y or 0-byte output (lived: 0 bytes every run) | | GIF / side-by-side / stacked clip | `ffmpeg` (via `compare.mjs`) | | Candidate bugs | `github` MCP (issues), `google-chat` MCP, app console/network, a `dev-tools:ux-audit` pass | | Iterate fix→reprove until the gate passes | the loop machinery (`run-a-self-refining-loop` / ralph-loop) | | Share the result | `pagedrop` MCP → `xr2.au/<slug>` | `${CLAUDE_PLUGIN_ROOT}/templates/` holds the working files; transplant and adapt them. `${CLAUDE_PLUGIN_ROOT}/docs/pattern.md` is the deep reference — update it and its Adopters list when you learn something. ## 0 — SCOPE: get the candidates Two ways in, both supported: - **Hand-fed** (default): the user names a bug. Open a case file, go to PROVE-BEFORE. - **Scan**: sweep the real sources and propose a ranked candidate list, then **confirm with the user before chasing a batch** — don't burn the loop on low-value noise. ``` github MCP → open issues labelled bug, recent comments, reopened issues google-chat MCP → spaces where the team/clients report problems ("X is broken", screenshots) chrome/playwright → console errors + 5xx/4xx network while walking the app ux-audit → a fresh walkthrough's findings list ``` One case file per confirmed candidate. Rank by user-facing impact × reproducibility. ## 1 — PROVE-BEFORE: the indictment Reproduce it on a **deterministic, re-runnable** capture — because PROVE-AFTER must replay it byte-for-byte. Pin everything that varies: - **Where** — the **live** app for read-only-observable bugs. But when the repro needs a precondition you can't safely stage on prod (an FK-linked row, a a record with a related child row, a one-time token — anything requiring a write), use a **local seeded dev DB** and pin the seed so AFTER replays the same data. Don't assume local can't show "deploy-class" DB failures: local Cloudflare D1 enforces FKs (`PRAGMA foreign_keys = 1`), so FK-constraint bugs DO reproduce locally. - **Viewport(s)** — fixed px. If it's a responsive bug, capture each breakpoint. Lists often render a desktop `<table>` AND hidden mobile cards with the same text — scope locators to `getByRole('table')` or you'll grab the hidden twin. - **Steps** — ordered, role-based locators, each ending at a **labelled checkpoint** (`01-list-loaded`, `02-after-submit`). The labels are the pairing key for AFTER. - **Auth** — either reuse a Playwright `storageState` (gitignore it), or — faster for cookie/token stacks — POST the app's sign-in endpoint via `context.request`: it shares the page cookie jar, so one call logs in and the capture starts on the bug, not the form. Capture at each checkpoint: **screenshot + animated GIF + full video + console + network** — and grab the **failing response BODY**, not just the status; it usually names the mechanism (`500 {"error":"Failed to delete author"}` → an FK constraint, not a permissions bug). Pin the **code location** (`file:line`) you suspect. Cap stills at 1440px before re-reading (`sips -Z 1440`, per the screenshot rule). The worked example + earned gotchas (modal stacking, shadcn `role="dialog"`, ESM resolution) live in `docs/pattern.md` — skim it before your first capture. **The journey is a free bug-scan.** Walking the real path surfaces *adjacent* breakage you weren't hunting — a stray console error, a second control that misbehaves, a modal that opens when it shouldn't. Log it. The one-bug focus is the thing that makes you walk past the other three the camera just caught; capture them as their own candidates instead of dropping them. **If you cannot reproduce it on camera, the verdict is `not reproduced` — stop.** Don't fix blind. A bug you can't film is a bug you can't prove you fixed. ## 2 — DIAGNOSE From the evidence, name the **mechanism** in code, not the symptom. "The list shows stale rows" is a symptom; "the query caches on `projectId` but the cache key omits the filter, so a filter change reuses the prior result set" is a cause. Write it in the case file with `file:line`. A wrong diagnosis makes a green AFTER a lie. **Before you fix, confirm the surface is reachable.** Grep the component/handler you're about to change up to a routed page — fixing an orphan (a component nothing renders, a hook nothing calls) yields a clean AFTER the user never sees. If the only importers are test files, you're about to fix the wrong thing. ## 3 — FIX Smallest change that addresses the root cause. Note the diff in the case file. ## 4 — PROVE-AFTER: the acquittal Re-run the **exact same capture spec** — same viewport, steps, checkpoint labels. Same camera or the comparison is void. Then **pair frame-for-frame** against BEFORE with `compare.mjs`. The after run does double duty: it must also show **nothing adjacent broke** (regression check), so keep a couple of "should-be-unchanged" checkpoints in the spec. ## 5 — PRESENT `compare.mjs` emits per-checkpoint **side-by-side PNGs**, a **before→after GIF/clip**, and a **`compare.html` slider**. Publish via `pagedrop` for a shareable `xr2.au` link. **Two cuts, two audiences.** The evidence has two readers, and they need different things: - **Author / you** — the full technical verdict: claim → mechanism → fix → before/after → any *surfaced* issues the journey caught. - **Stakeholder** (client, QA, non-technical owner) — the lightest cut that shows the delta + ONE plain-English line ("✓ the report now groups by region, matches the brief"). No jargon, no file paths, no caveats they can't action. **Match the stakeholder cut to what changed (and crop tight).** A clip is the default but not always the right one — pick by what the fix actually altered: - **A static delta** (a label, a colour, a layout, a now-present element) → a **cropped before/after still** or the `compare.html` slider, *not* a 10-second clip. A still they absorb at a glance beats a clip they wait through to see a change that was already visible in frame one. - **A delta that only reads in motion** (a transition, an interaction, "it used to jump, now it doesn't") → the **before→after GIF/clip**. The motion *is* the proof. - Either way, **crop to the changed region** — full-screen only when the change is the cross-page layout itself. Everything the stakeholder doesn't weigh dilutes the ✓. This is the [decisions](https://github.com/jezweb/decisions) real-capture fidelity ladder (still < GIF < video; escalate only when the lighter medium can't show it) pointed at the acquittal cut: the camera still captures all media at every checkpoint for the author's record — this only governs which one the stakeholder is handed. **Routing rule (load-bearing).** A clean pass → the stakeholder gets the ✓-cut directly. Anything short of a clean pass (`partially fixed` / `regressed elsewhere` / a gap) → the **author + owner hear first, privately**, and it's fixed before the stakeholder sees anything. Pushing a half-met verdict straight to the client is the trust-burning failure this rule exists to prevent. **Verdict is one of:** `proven fixed` · `not reproduced` · `partially fixed` · `regressed elsewhere`. Only `proven fixed` closes the case, and only with a real BEFORE *and* AFTER on the same spec. ## 6 — LOOP If AFTER still shows the bug (or a new one), back to DIAGNOSE — this is where the self-refining loop earns its keep: iterate fix → reprove until the gate passes or you hit a documented blocker. Then take the next case file. ## Verify mode (acceptance) — prove someone else's ship is done Same camera, different source of truth. Use when an already-merged change claims to satisfy a requirement and someone needs to **trust** it's done — a client, a QA lead, a PM signing off another dev's PR. This is fixer's prove-and-verdict half pointed at a requirement instead of a bug; there is no "prove broken" stage. Inputs: the **change** (PR / commit) **and** its **original requirement** — the ticket, card, or spec, in the words the work was meant to satisfy. If you can't find the requirement, get it before filming. "Looks right" is not acceptance. 1. **Turn the requirement into checkpoints.** Same labelled steps as PROVE-BEFORE, but each checkpoint asserts a *clause of the requirement*, not a bug repro. If the card says "group each region + show the legend", that's two checkpoints. 2. **Run the journey on the merged code** (seed the precondition if the requirement needs data that prod can't safely hold). Capture screenshot + clip + each asserting checkpoint. 3. **Blind-audit against the requirement** — an independent pass told *only* the requirement text, which must find the pixels proving every clause or it FAILs. Same gate as a fix's AFTER; here it guards the acceptance, not the cure. A one-clause-short ship is `partially meets`, not `meets`. 4. **Verdict** — one of: `meets` · `partially meets` · `misses` · `not reachable`. 5. **Route it** per PRESENT's two-cuts rule: `meets` → the stakeholder gets the ✓-clip; anything else → author + owner first, privately, before the stakeholder sees it. **Staging the merged code is the real cost** (lived). To run an *already-merged* change locally without disturbing your working branch: worktree off `main`, share `node_modules` by symlink, copy a seeded DB, run dev on its own port. And for a **data / logging / state** behaviour, the cleanest evidence is to **trigger it through the merged API** (an authenticated request) and screenshot the *rendered* result — far more reliable than driving the UI form, and it still proves both the server behaviour and the rendered wording. Dismiss any onboarding overlay first; it will sit right over your proof. The earned-place test for verify mode: a change is only called "done for the client" with a same-requirement capture on disk that a blind audit passed — never on the dev's "it's merged and green." ## Proof gates (hard — these are the whole point) | Gate | Why | |---|---| | No `proven fixed` without an AFTER capture paired to a real BEFORE | the loop's entire value is the symmetry; a one-sided "looks fixed" is the failure mode it exists to kill | | Identical capture spec both sides | different camera = void comparison, you've proven nothing | | You personally inspect the AFTER frames | aggregate "tests pass" is the start of verification, not the end — read the actual pixels | | AFTER includes unchanged-checkpoint regression guards | a fix that breaks the neighbour isn't a fix | | AFTER is on the user-reachable surface, not an orphan component | a clean AFTER on a component nothing renders proves a fix the user never sees | | VERIFY: no "done for the client" without a same-requirement capture a blind audit passed | "looks done" to the dev is exactly what acceptance evidence exists to replace | | VERIFY: a gap reaches the author before the stakeholder | a half-met verdict handed straight to the client is a trust fire | The earned-place test for this skill: if a session could close a bug as fixed *without* a same-spec before/after pair on disk, fixer wasn't used.
عرض على GitHub