Files
command-center/agent/managed-skills/react-prod-state-mismatch-bisection/SKILL.md
T
Frank 8af40c402b chore(agent): commit the machine tier and the doctrine text the checkout was already running
Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and
`merge --ff-only` refuses while tracked paths are dirty. Discard is not available here
(workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed.

- `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already
  byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new
  prose — the commit exists so the trunk merge can proceed.
- `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat
  owns (AGENTS.md § Live-sync tiers).

`ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the
only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the
inert all-zero AWS example id — and they appear inside the two skill pages that teach
that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged
gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal
dies with this landing. No `--no-verify` was used: the gate ran and its verdict is
recorded here.

Refs #61
2026-10-21 01:44:51 -07:00

3.1 KiB

name, description
name description
react-prod-state-mismatch-bisection Diagnose React SPA prod-build state mismatches (state-derived props update but sibling output stays stale) by driving a real browser and bisecting per-render state via throwaway source instrumentation.

Prod React state-mismatch bisection

Use when a built SPA shows an internally inconsistent DOM — e.g. aria-current flips while a sibling conditional slot stays stale, a click handler runs with zero network activity, jsdom tests pass but the prod journey fails. Reasoning from source fails here; only per-render state truth resolves it.

Steps

  1. Drive the real browser, not tests. Throwaway @playwright/test chromium script beside the package that installs it (e.g. tests/), seeded via direct API calls + cookie injection:

    import { chromium } from "@playwright/test";   // resolve from tests/ node_modules
    const ctx = await browser.newContext();
    await ctx.addCookies([{ name, value, domain: "127.0.0.1", path: "/" }]);
    page.on("console", ...); page.on("pageerror", ...); page.on("request", ...);
    

    Run it from that directory; a script at repo root or /tmp hits ERR_MODULE_NOT_FOUND for workspace deps.

  2. Fiber prop probe — call the handler outside React events to split "delegation dead" from "handler wrong", and read the props the fiber holds:

    await page.evaluate(() => {
      const el = document.querySelector('[data-testid^="thing-"]');
      const key = Object.keys(el).find((k) => k.startsWith("__reactProps$"));
      el[key].onClick();          // or .onChange({target:{value:"x"}})
    });
    
  3. If props updated but output is inconsistent, suspect falsy-equality, not React. undefined === undefined yields "true" for el.id === selectedId highlights — a fake "state updated" signal. Dump the slot's raw innerHTML, don't trust the derived attribute.

  4. Instruments beats deduction: insert temporary console.logs in the component source (one in each state-mutating callback, one at render logging the state), rebuild, restart the server, re-run the script. Compare per-render values — the render where the value is undefined instead of the id names the root cause (usually a server payload keyed differently than the client type, e.g. DB row key orgId crossing HTTP where the contract says id).

  5. Also grep every suite teardown for broad DELETE ... LIKE/TRUNCATE on the shared DB when a test flakes only under uncached concurrent runs (turbo run test --force) and passes isolated: parallel vitest files on one DB — the suite that finishes first FK-cascades away the other's live sessions; the symptom is a spurious 401 (or missing row) in the still-running file. Fix by namespacing emails/ids per suite and scoping teardowns to rows the suite created.

Cleanup

Remove instrumentation, move the throwaway script to .AGENTTRASH/, never commit the debug script. Verified on franksign: GET /api/orgs leaked orgId where the client contract was id (fake aria-current true, silent auto-select failure).