[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6J4569S40ZASFWW698CHBKP":3,"skill-same:01M6J4569S40ZASFWW698CHBKP":116},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":34,"publishedAt":56,"linkOnly":57,"markdownContent":58,"markdownBody":59,"frontMatter":60,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":14,"repositoryHtmlUrl":64,"repositoryHomepageUrl":6,"ownerHtmlUrl":65,"ownerBlogUrl":6,"ownerDescription":66,"updatedAt":67,"install":68,"resources":81},"01M6J4569S40ZASFWW698CHBKP","ux-lock",null,"Generate Playwright e2e specs. Two modes:\n  1. LOCK mode — pin a fix's DOM contract so it doesn't regress (default).\n  2. VERIFY mode — check that a \u002Fplan plan was actually implemented\n     by parsing its Acceptance Criteria section and driving the live URL.\nVERIFY mode grades a plan against a RUNNING app. To judge the plan document\nitself, before anything is built, that is \u002Faudit-plan.\nTriggers on: \"ux lock\", \"lock ux\", \"lock in the fix\", \"write regression spec\",\n\"generate e2e test for\", \"regression test for commit\", \"lock this fix\",\n\"verify the plan\", \"verify plan implementation\", \"check the plan was built\",\n\"audit frontend implementation\", \"did we ship the plan\".\nFull command syntax: see the Usage section in this skill.","Lbstrydom\u002Fclaude-engineering-skills","Lbstrydom","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F77991486?v=4","01M6J3X4N2T0FTZT1RKFXDVS0K","Louis Strydom","01M6J3X4SXV0BXWDMXPW90D8BK",0,"MIT","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002FSKILL.md",[18,23,26,31],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",{"categoryNo":32,"categoryName":33,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000037","律师与法务",[35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55],"ux lock","lock","ux","write","verify plan","mode","URL","judge","app","default","e2e test","fix","frontend","command","syntax","regression","plan","audit","acceptance","generate","commit","2026-11-10 10:12:30",false,"---\nname: ux-lock\ndescription: |\n  Generate Playwright e2e specs. Two modes:\n    1. LOCK mode — pin a fix's DOM contract so it doesn't regress (default).\n    2. VERIFY mode — check that a \u002Fplan plan was actually implemented\n       by parsing its Acceptance Criteria section and driving the live URL.\n  VERIFY mode grades a plan against a RUNNING app. To judge the plan document\n  itself, before anything is built, that is \u002Faudit-plan.\n  Triggers on: \"ux lock\", \"lock ux\", \"lock in the fix\", \"write regression spec\",\n  \"generate e2e test for\", \"regression test for commit\", \"lock this fix\",\n  \"verify the plan\", \"verify plan implementation\", \"check the plan was built\",\n  \"audit frontend implementation\", \"did we ship the plan\".\n  Full command syntax: see the Usage section in this skill.\n---\n\n# UX Lock — Playwright Spec Generator & Plan Verifier\n\n> **This skill's last line is an end marker naming the skill between em-dashes, after\n> the Reference files table.** If that last line is not in your context (context\n> compaction keeps only the start of a skill), re-read\n> `.claude\u002Fskills\u002Fux-lock\u002FSKILL.md` in full before continuing — the later steps still apply.\n\n> **Worktree preflight** — in a linked git worktree the synced tooling tree\n> `scripts\u002F.claude-skills\u002F` is absent — it is gitignored, so `git worktree add`\n> does not populate it, and every command below that uses it dies on a bare\n> `MODULE_NOT_FOUND`. Run `npm run skills:hydrate` first. If this repo defines\n> no such script, `references\u002Fworktree-preflight.md` holds the entry to add — ask\n> the user first, since it edits their `package.json`.\n\n## Usage\n\n```\nUsage:\n  \u002Fux-lock \u003Ccommit-or-description> [--url \u003Cbase-url>]                     — lock mode\n  \u002Fux-lock verify \u003Cplan.md> [--url \u003Cbase-url>]                            — verify mode\nExamples:\n  \u002Fux-lock \"modal closes before retry\"\n  \u002Fux-lock abc1234\n  \u002Fux-lock \"role=list on wine grid\" --url https:\u002F\u002Fmyapp.railway.app\n  \u002Fux-lock verify docs\u002Fplans\u002F\u003Cname>.md --url https:\u002F\u002Fmyapp.railway.app\n```\n\nTwo modes, one skill. Both drive Playwright against semantic DOM contracts.\n\n- **LOCK mode** (default): generate an e2e spec that pins a fix's DOM contract.\n- **VERIFY mode** (`verify \u003Cplan.md>`): parse the plan's Acceptance Criteria\n  section (from a `\u002Fplan` plan) and run one assertion per criterion\n  against the live URL — producing a pass\u002Ffail grade for the plan.\n\nRead the first word of `$ARGUMENTS`:\n\n\u003C!-- host-contract: input-acquisition; grammar=subcommand; empty=ask-and-stop -->\n\n**Where `$ARGUMENTS` comes from** — orchestrator-supplied input first, else\nthe host's verbatim invocation suffix, else the span of the user's **current**\nmessage naming this skill or its subject. Never inferred from surrounding\nconversation. This site is `subcommand`; on empty input, ask whether to LOCK a fix or VERIFY a plan and stop — the two modes read different inputs and write different artifacts.\nFull contract: `references\u002Finput-acquisition.md`.\n\n\n- `verify` → **Mode: VERIFY**\n- otherwise → **Mode: LOCK**\n\n---\n\n## DOM-contract rule (both modes) — covers LOCATION and assertion\n\nThe spec must **locate and assert** on public DOM contracts, not implementation\ndetails. Avoiding `toHaveClass()` while locating via `page.locator('#id')` still\nships all the brittleness — the rule constrains both halves:\n\n| Good (stable) | Bad (brittle) |\n|---|---|\n| `page.getByRole('button', { name: 'Add bottle' })` | `page.locator('#add-btn')` |\n| `page.getByTestId('cellar-grid')` | `page.locator('.grid-abc')` |\n| Element with `role=\"list\"` exists | Element has class `wine-list-v3` |\n| Modal closes when action button clicked | Internal state variable changes |\n| Button is `aria-disabled` when form invalid | CSS opacity is 0.5 |\n| Navigation to `\u002Fcellar` shows grid | `document.querySelector('.grid-abc')` |\n\n**Selector priority ladder (location)** — take the FIRST rung that works:\n\n1. `page.getByRole(role, { name })` — first choice\n2. `page.getByLabel(...)` \u002F `page.getByPlaceholder(...)` — form controls\n3. `page.getByText(...)` — static user-visible copy\n4. `page.getByTestId(...)` — when no accessible handle exists\n5. CSS `#id` \u002F `.class` — **last resort only**, and it must carry a justification\n   marker on the same line or the line above:\n   `\u002F\u002F selector-policy: structural — \u003Cwhy no semantic handle is possible>`\n   (the reason is mandatory; the run pipeline lints unmarked structural selectors\n   — warn by default, `--strict-selectors` fails the run)\n\n**Rules**:\n- Locate via the ladder above; assert on semantic HTML (`role`, `aria-*`,\n  `data-testid`) — never CSS classes\n- Assert on user-visible behaviour (click → result) — never internal state\n- Assert on accessibility (axe-core) when the fix touched a11y\n- Never import the app's own modules into the spec process — drive the UI\n  (see `references\u002Fscope-and-limitations.md`)\n\n---\n\n## Mode: LOCK\n\n### Step 0 — Understand the fix\n\n1. If a commit hash is provided, read the commit message and diff\n   (substitute the real hash for `$HASH`):\n   ```bash\n   git show $HASH --stat\n   git show $HASH\n   ```\n2. Extract: what was broken, what was fixed, which files changed, which\n   DOM elements are involved.\n3. If a description is provided instead, ask clarifying questions only if\n   the DOM contract is ambiguous.\n\n### Step 1 — Check existing harness\n\n```bash\nls tests\u002Fe2e\u002Fhelpers\u002F        # auth, axe helpers\ncat playwright.config.*       # base URL, projects, timeouts\nls tests\u002Fe2e\u002F*.spec.*         # existing specs for naming convention\n```\n\nIf no Playwright setup exists, offer to bootstrap from the template.\nSee `references\u002Fscope-and-limitations.md` for the bootstrap commands.\n\n### Step 1.5 — Ensure a semantic handle exists\n\nIf the fixed surface exposes no role\u002Flabel\u002Ftestid the ladder can target, the lock\ntask INCLUDES adding one to the app markup — the surface is already being touched\nat fix time. The hook itself has a ladder (accuracy over convenience):\n\n1. **Native semantic HTML \u002F visible label** — when the element genuinely warrants\n   it (clickable `div` → `button`; unlabelled input gains a `\u003Clabel>`). A real\n   accessibility improvement — verify with the spec's axe assertion.\n2. **`data-testid`** — the default otherwise. Genuinely behaviour-neutral.\n3. **`role` \u002F `aria-label`** — ONLY when it accurately describes the element's\n   function. Wrong ARIA is worse for screen-reader users than none; never add it\n   purely to make a test targetable — that's what `data-testid` is for.\n\n### Step 2 — Generate the spec\n\nUse the template + fix-type assertion map in\n`references\u002Flock-mode-spec-generation.md`. One file per fix, named\n`tests\u002Fe2e\u002F\u003Cticket-or-round>-\u003Cdescription>.spec.js`.\n\n### Step 2.5 — Prove the spec RED before you record it\n\n**A spec that has never failed is not a lock.** You have the fix and the spec in\nhand right now; this is the only moment the proof is cheap.\n\n1. Revert the fix (`git stash` the fix hunk, or restore the pre-fix file).\n2. Run the spec → **confirm RED**, and read the failure: it must fail *because\n   the fixed behaviour is absent*, not because the page 404'd, the selector was\n   wrong, or the app failed to boot.\n3. Restore the fix → confirm GREEN.\n4. Note the red output in the spec's header comment.\n\nA spec can pass before the fix too, when its assertion cannot tell the guarded\noutcome from an incidental one. → `references\u002Fhistory-and-evidence.md` §Step 2.5 —\nread when a spec's RED\u002FGREEN result is ambiguous.\n\n**Watch for the spec that goes red for the wrong reason** — that is the same\nfailure wearing the opposite mask, and it is why step 2 says read the text.\n\n→ `references\u002Fverification-discipline.md` §3.\n\n### Step 3 — Run + record (deterministic — ONE call)\n\nThe spec is authored (Step 2). Execution and recording are now a single\ndeterministic call — the runner runs `npx playwright test`, parses the JSON\nreport from a file (never stdout), and writes BOTH the `regression_specs` and\n`regression_spec_runs` rows itself. This replaces the old model-remembered\nsequence (run → hand-parse → `record-regression-spec` → `record-regression-spec-run`)\nthat left the tables empty whenever a step was skipped or mis-parsed:\n\n```bash\nSPEC=tests\u002Fe2e\u002F*.spec.js\nCOMMIT=$(git rev-parse HEAD)\nnode scripts\u002Fux-lock-run.mjs spec --spec \"$SPEC\" --commit \"$COMMIT\" --run-context manual --source-kind manual --strict-selectors\n```\n\n→ `references\u002Fhistory-and-evidence.md` §Step 3 — read when `regression_spec_runs`\nlooks empty or under-attributed in the store.\n\nPass `--strict-selectors` for newly generated specs (recommended — a spec you\njust authored has no excuse for unmarked structural selectors; the flag fails\nthe run instead of warning). Omit it only when re-running legacy suites.\n\n- **Auto-registers** the spec (upsert by `repo_id` + `spec_path`, supplying the\n  required `source_kind` + a derived `description`) and records this run's\n  pass\u002Ffail + duration. `--no-register` skips registration (records nothing).\n- **Exit code reflects test pass\u002Ffail** — non-zero means the spec failed, so you\n  (and `\u002Fship`\u002FCI) see it. A *failing* run is still recorded as `passed:false`\n  (not silently dropped).\n- **Graceful**: cloud off → runs + prints, skips recording with a hint;\n  Playwright missing → exit 5 (install hint); malformed report → hard error.\n- No hand-parsing, no shell-quoting of free text (the runner owns the writes).\n\nIf the spec itself fails for environment reasons, debug: base URL via\n`E2E_BASE_URL` (the runner sets it from `--url`); auth via `E2E_BEARER_TOKEN`;\ntiming via `await page.waitForSelector(...)`. `source_kind` selection +\nmulti-spec (`--specs`) details: `references\u002Flock-mode-spec-generation.md`.\n\n### Step 5 — Report\n\n```\n═══════════════════════════════════════\n  REGRESSION SPEC — Created\n  File: tests\u002Fe2e\u002F\u003Cname>.spec.js\n  Assertions: \u003Cn>\n  Passes: ✓ chromium-desktop, ✓ chromium-mobile\n  Recorded: spec-id \u003Cuuid> (source: \u003CsourceKind>)\n═══════════════════════════════════════\n```\n\nOmit the `Recorded:` line when cloud mode is off.\n\n---\n\n## Mode: VERIFY\n\nGrade a `\u002Fplan` plan against its live implementation. Each\ncriterion in the Acceptance Criteria section becomes one Playwright `test()`;\nper-criterion outcomes are recorded with a stable `criterion_hash` for\ntime-series tracking across verify runs.\n\n### Step V0 — Parse the plan\n\nRead the plan at the path in `$ARGUMENTS` (first positional after\n\n\u003C!-- host-contract: input-acquisition; grammar=subcommand; empty=ask-and-stop -->\n_This site: `subcommand` — verify requires a plan path; ask for it and stop rather than grading the app against a guessed plan._\n\n`verify`). Parse the Acceptance Criteria section using `scripts\u002Flib\u002Fplan-criteria-parser.mjs`.\n\nIf `found = false` → plan has no Acceptance Criteria; offer to add one.\nIf `errors.length > 0` → print + stop (malformed criteria).\n\nRegister the plan → capture `planId`.\n\n### Step V1 — Resolve base URL\n\nPriority: `--url` flag → `E2E_BASE_URL` → `PERSONA_TEST_APP_URL` → ask.\n\n### Step V2 — Generate one spec, N tests\n\nCreate `tests\u002Fe2e\u002Fverify-\u003Cplan-slug>.spec.js` with one `test()` per\ncriterion, using the translation-rules table.\n\nFull template + translation rules + persistence protocol:\n`references\u002Fverify-mode-generation.md`.\n\n### Step V3–V5 — Run + record (deterministic — ONE call)\n\nAfter authoring the verify spec (one `test()` per criterion, each carrying its\n`criterion_hash` as an annotation — see the reference), run + record in one\ndeterministic call. The runner runs the spec, maps each test result back to its\ncriterion via the `criterion_hash` annotation, and writes the\n`plan_verification_runs` + `plan_verification_items` rows itself — replacing the\nold model-remembered run → parse → `record-plan-verify-run` →\n`record-plan-verify-items` sequence:\n\n```bash\nCOMMIT=$(git rev-parse HEAD)\nnode scripts\u002Fux-lock-run.mjs verify --plan docs\u002Fplans\u002F*.md --spec tests\u002Fe2e\u002Fverify-*.spec.js --plan-id PLAN_UUID --commit \"$COMMIT\" --url BASE_URL --strict-selectors\n```\n\n(`--strict-selectors`: verify specs are newly generated, so the selector-policy\nlint fails rather than warns on an unmarked structural selector. Note V3\nregisters the SPEC row via cross-skill; this call owns only the RUN rows.)\n\n- **Every criterion is accounted for** (plan §2.3): a criterion with no matching\n  test → `passed:false` (\"no matching test result\"); multiple results for one\n  hash → fail if ANY failed; a test with no expected criterion (orphan) is\n  logged + counted but NOT inserted (the items table is strictly\n  per-expected-criterion).\n- The `criterion_hash` is recomputed from the plan by the runner (via\n  `plan-criteria-parser.mjs`), so it matches the authored spec's annotation\n  exactly. Pass `--plan-id` (the `plans` row UUID) or the run is not recorded.\n- **Graceful**: cloud off → runs + prints, skips recording; Playwright missing →\n  exit 5. **Verify is a report, not a blocker** — it exits 0 even when criteria\n  fail; a non-zero exit means the spec could not RUN (PW missing \u002F fatal), not\n  that a criterion failed. Exit 4 (`error.code: PERSIST_FAILED`) means it RAN\n  but its run or criterion rows were NOT recorded.\n- **Nothing gates on this today** — `\u002Fship` never queries `plan_satisfaction`\n  as a gate; do not tell the user a failing verify blocks shipping.\n  → `references\u002Fhistory-and-evidence.md` §Steps V3–V5 — read when asked whether\n  verify gates `\u002Fship`, or before claiming it does.\n\nThe verify-spec template MUST emit each test with\n`{ annotation: [{ type: 'criterion_hash', description: '\u003Chash>' }] }` — naming\nthe test by prose is NOT enough (the hash can't be recovered from a title).\nFull template + translation rules: `references\u002Fverify-mode-generation.md`.\n\n### Step V6 — Report\n\nEmit the satisfaction summary with pass\u002Ffail\u002F**skipped** counts per severity +\nthe list of failing P0 criteria. **A skipped P0\u002FP1 is neither a pass nor a\nfailure and must be rendered as its own line — never silently dropped**, since\nit is invisible to the `\u002Fship` gate by design (the store correctly excludes\nskipped items from `failing_p0_criteria`) and this report is the only place\nit can surface. Status rubric is a full precedence table, not three\nindependent conditions: `PLAN_NOT_SHIPPED` (any P0 failed) →\n`PLAN_PARTIAL` (any P0\u002FP1 skipped, or any P1 failed) → `PLAN_SATISFIED` (all\nP0+P1 evaluated and passing). Full template + precedence table:\n`references\u002Fverify-mode-generation.md`.\n\n### Failure policy\n\nVerify exits 0 even on fail — it's a report, not a blocker. The result is\nreadable via `cross-skill.mjs plan-satisfaction --plan-id \u003Cid>`\n(`failing_p0_criteria`), but no step reads it to gate a ship today (see the\n\"Nothing gates on this today\" rule above).\n\n---\n\n## When to use this skill\n\n- **After \u002Faudit-code convergence**: lock in the fixes before moving on\n- **After a \u002Fpersona-test P0 fix**: prevent recurrence\n- **After any production bug fix**: before closing the issue\n- **Before a major refactor**: baseline the current behaviour\n- **After \u002Fplan implementation**: `verify` mode grades the implementation\n\n---\n\n## Integration with other skills\n\n- **\u002Faudit-code** converges → **\u002Fux-lock** locks in fixes\n- **\u002Fpersona-test** finds P0 → fix → **\u002Fux-lock** prevents recurrence\n- **\u002Fship** warns if recent fixes lack regression specs\n- **\u002Fplan** produces Acceptance Criteria → **\u002Fux-lock verify** grades implementation\n\n---\n\n## Scope + limitations\n\nWorks for web apps served via URL. Limited for Obsidian\u002FElectron apps,\nCLI tools, and anti-bot-protected URLs. Full guidance:\n`references\u002Fscope-and-limitations.md`.\n\n---\n\n## Reference files\n\nThis skill's canonical flow is above. The files below cover specialised\nsituations — read them only when the trigger applies.\n\n| File | Summary | Read when |\n|---|---|---|\n| `references\u002Finput-acquisition.md` | Where a skill's arguments come from on any host, and what to do when there are none. | Reading $ARGUMENTS on a host that does not substitute it, or deciding what empty input means at a site. |\n| `references\u002Flock-mode-spec-generation.md` | LOCK mode — full Playwright spec template + fix-type assertion map + persistence recipe. | Mode: LOCK, about to write the spec body OR register it. |\n| `references\u002Fverify-mode-generation.md` | VERIFY mode — criterion parser wiring, translation rules, per-criterion run+record protocol. | Mode: VERIFY, Steps V0–V6 (parsing, generating, running, recording). |\n| `references\u002Fscope-and-limitations.md` | Where \u002Fux-lock works well, where it doesn't (Obsidian\u002FElectron), and fallback strategies. | Target is an Obsidian plugin \u002F Electron app \u002F CLI \u002F anti-bot-protected URL, OR bootstrapping Playwright harness from scratch, OR user is on Windows and Playwright MCP tools aren't appearing. |\n| `references\u002Fverification-discipline.md` | Verification discipline — pinned citations, figure provenance, two-direction proof, attribution, consumer-side checks. | Step 2.5 — the spec is written and must be proven RED against the un-fixed code before it is run and recorded. ALSO Step V6 — about to emit the VERIFY report, to apply §7's skipped-criteria rule. |\n| `references\u002Fhistory-and-evidence.md` | The measured cases behind Step 2.5's RED proof, the Step 3 store diagnosis, and why nothing gates on verify today. | Step 2.5 RED\u002FGREEN is ambiguous, OR the store's spec-run rows look empty, OR asked whether verify gates `\u002Fship`. |\n| `references\u002Fworktree-preflight.md` | Worktree preflight remedy — the skills:hydrate npm script to add when a linked worktree lacks the tooling tree. | A command dies with `MODULE_NOT_FOUND` in a linked worktree AND this repo has no `skills:hydrate` script. |\n\n— end of \u002Fux-lock —\n","# UX Lock — Playwright Spec Generator & Plan Verifier\n\n> **This skill's last line is an end marker naming the skill between em-dashes, after\n> the Reference files table.** If that last line is not in your context (context\n> compaction keeps only the start of a skill), re-read\n> `.claude\u002Fskills\u002Fux-lock\u002FSKILL.md` in full before continuing — the later steps still apply.\n\n> **Worktree preflight** — in a linked git worktree the synced tooling tree\n> `scripts\u002F.claude-skills\u002F` is absent — it is gitignored, so `git worktree add`\n> does not populate it, and every command below that uses it dies on a bare\n> `MODULE_NOT_FOUND`. Run `npm run skills:hydrate` first. If this repo defines\n> no such script, `references\u002Fworktree-preflight.md` holds the entry to add — ask\n> the user first, since it edits their `package.json`.\n\n## Usage\n\n```\nUsage:\n  \u002Fux-lock \u003Ccommit-or-description> [--url \u003Cbase-url>]                     — lock mode\n  \u002Fux-lock verify \u003Cplan.md> [--url \u003Cbase-url>]                            — verify mode\nExamples:\n  \u002Fux-lock \"modal closes before retry\"\n  \u002Fux-lock abc1234\n  \u002Fux-lock \"role=list on wine grid\" --url https:\u002F\u002Fmyapp.railway.app\n  \u002Fux-lock verify docs\u002Fplans\u002F\u003Cname>.md --url https:\u002F\u002Fmyapp.railway.app\n```\n\nTwo modes, one skill. Both drive Playwright against semantic DOM contracts.\n\n- **LOCK mode** (default): generate an e2e spec that pins a fix's DOM contract.\n- **VERIFY mode** (`verify \u003Cplan.md>`): parse the plan's Acceptance Criteria\n  section (from a `\u002Fplan` plan) and run one assertion per criterion\n  against the live URL — producing a pass\u002Ffail grade for the plan.\n\nRead the first word of `$ARGUMENTS`:\n\n\u003C!-- host-contract: input-acquisition; grammar=subcommand; empty=ask-and-stop -->\n\n**Where `$ARGUMENTS` comes from** — orchestrator-supplied input first, else\nthe host's verbatim invocation suffix, else the span of the user's **current**\nmessage naming this skill or its subject. Never inferred from surrounding\nconversation. This site is `subcommand`; on empty input, ask whether to LOCK a fix or VERIFY a plan and stop — the two modes read different inputs and write different artifacts.\nFull contract: `references\u002Finput-acquisition.md`.\n\n\n- `verify` → **Mode: VERIFY**\n- otherwise → **Mode: LOCK**\n\n---\n\n## DOM-contract rule (both modes) — covers LOCATION and assertion\n\nThe spec must **locate and assert** on public DOM contracts, not implementation\ndetails. Avoiding `toHaveClass()` while locating via `page.locator('#id')` still\nships all the brittleness — the rule constrains both halves:\n\n| Good (stable) | Bad (brittle) |\n|---|---|\n| `page.getByRole('button', { name: 'Add bottle' })` | `page.locator('#add-btn')` |\n| `page.getByTestId('cellar-grid')` | `page.locator('.grid-abc')` |\n| Element with `role=\"list\"` exists | Element has class `wine-list-v3` |\n| Modal closes when action button clicked | Internal state variable changes |\n| Button is `aria-disabled` when form invalid | CSS opacity is 0.5 |\n| Navigation to `\u002Fcellar` shows grid | `document.querySelector('.grid-abc')` |\n\n**Selector priority ladder (location)** — take the FIRST rung that works:\n\n1. `page.getByRole(role, { name })` — first choice\n2. `page.getByLabel(...)` \u002F `page.getByPlaceholder(...)` — form controls\n3. `page.getByText(...)` — static user-visible copy\n4. `page.getByTestId(...)` — when no accessible handle exists\n5. CSS `#id` \u002F `.class` — **last resort only**, and it must carry a justification\n   marker on the same line or the line above:\n   `\u002F\u002F selector-policy: structural — \u003Cwhy no semantic handle is possible>`\n   (the reason is mandatory; the run pipeline lints unmarked structural selectors\n   — warn by default, `--strict-selectors` fails the run)\n\n**Rules**:\n- Locate via the ladder above; assert on semantic HTML (`role`, `aria-*`,\n  `data-testid`) — never CSS classes\n- Assert on user-visible behaviour (click → result) — never internal state\n- Assert on accessibility (axe-core) when the fix touched a11y\n- Never import the app's own modules into the spec process — drive the UI\n  (see `references\u002Fscope-and-limitations.md`)\n\n---\n\n## Mode: LOCK\n\n### Step 0 — Understand the fix\n\n1. If a commit hash is provided, read the commit message and diff\n   (substitute the real hash for `$HASH`):\n   ```bash\n   git show $HASH --stat\n   git show $HASH\n   ```\n2. Extract: what was broken, what was fixed, which files changed, which\n   DOM elements are involved.\n3. If a description is provided instead, ask clarifying questions only if\n   the DOM contract is ambiguous.\n\n### Step 1 — Check existing harness\n\n```bash\nls tests\u002Fe2e\u002Fhelpers\u002F        # auth, axe helpers\ncat playwright.config.*       # base URL, projects, timeouts\nls tests\u002Fe2e\u002F*.spec.*         # existing specs for naming convention\n```\n\nIf no Playwright setup exists, offer to bootstrap from the template.\nSee `references\u002Fscope-and-limitations.md` for the bootstrap commands.\n\n### Step 1.5 — Ensure a semantic handle exists\n\nIf the fixed surface exposes no role\u002Flabel\u002Ftestid the ladder can target, the lock\ntask INCLUDES adding one to the app markup — the surface is already being touched\nat fix time. The hook itself has a ladder (accuracy over convenience):\n\n1. **Native semantic HTML \u002F visible label** — when the element genuinely warrants\n   it (clickable `div` → `button`; unlabelled input gains a `\u003Clabel>`). A real\n   accessibility improvement — verify with the spec's axe assertion.\n2. **`data-testid`** — the default otherwise. Genuinely behaviour-neutral.\n3. **`role` \u002F `aria-label`** — ONLY when it accurately describes the element's\n   function. Wrong ARIA is worse for screen-reader users than none; never add it\n   purely to make a test targetable — that's what `data-testid` is for.\n\n### Step 2 — Generate the spec\n\nUse the template + fix-type assertion map in\n`references\u002Flock-mode-spec-generation.md`. One file per fix, named\n`tests\u002Fe2e\u002F\u003Cticket-or-round>-\u003Cdescription>.spec.js`.\n\n### Step 2.5 — Prove the spec RED before you record it\n\n**A spec that has never failed is not a lock.** You have the fix and the spec in\nhand right now; this is the only moment the proof is cheap.\n\n1. Revert the fix (`git stash` the fix hunk, or restore the pre-fix file).\n2. Run the spec → **confirm RED**, and read the failure: it must fail *because\n   the fixed behaviour is absent*, not because the page 404'd, the selector was\n   wrong, or the app failed to boot.\n3. Restore the fix → confirm GREEN.\n4. Note the red output in the spec's header comment.\n\nA spec can pass before the fix too, when its assertion cannot tell the guarded\noutcome from an incidental one. → `references\u002Fhistory-and-evidence.md` §Step 2.5 —\nread when a spec's RED\u002FGREEN result is ambiguous.\n\n**Watch for the spec that goes red for the wrong reason** — that is the same\nfailure wearing the opposite mask, and it is why step 2 says read the text.\n\n→ `references\u002Fverification-discipline.md` §3.\n\n### Step 3 — Run + record (deterministic — ONE call)\n\nThe spec is authored (Step 2). Execution and recording are now a single\ndeterministic call — the runner runs `npx playwright test`, parses the JSON\nreport from a file (never stdout), and writes BOTH the `regression_specs` and\n`regression_spec_runs` rows itself. This replaces the old model-remembered\nsequence (run → hand-parse → `record-regression-spec` → `record-regression-spec-run`)\nthat left the tables empty whenever a step was skipped or mis-parsed:\n\n```bash\nSPEC=tests\u002Fe2e\u002F*.spec.js\nCOMMIT=$(git rev-parse HEAD)\nnode scripts\u002Fux-lock-run.mjs spec --spec \"$SPEC\" --commit \"$COMMIT\" --run-context manual --source-kind manual --strict-selectors\n```\n\n→ `references\u002Fhistory-and-evidence.md` §Step 3 — read when `regression_spec_runs`\nlooks empty or under-attributed in the store.\n\nPass `--strict-selectors` for newly generated specs (recommended — a spec you\njust authored has no excuse for unmarked structural selectors; the flag fails\nthe run instead of warning). Omit it only when re-running legacy suites.\n\n- **Auto-registers** the spec (upsert by `repo_id` + `spec_path`, supplying the\n  required `source_kind` + a derived `description`) and records this run's\n  pass\u002Ffail + duration. `--no-register` skips registration (records nothing).\n- **Exit code reflects test pass\u002Ffail** — non-zero means the spec failed, so you\n  (and `\u002Fship`\u002FCI) see it. A *failing* run is still recorded as `passed:false`\n  (not silently dropped).\n- **Graceful**: cloud off → runs + prints, skips recording with a hint;\n  Playwright missing → exit 5 (install hint); malformed report → hard error.\n- No hand-parsing, no shell-quoting of free text (the runner owns the writes).\n\nIf the spec itself fails for environment reasons, debug: base URL via\n`E2E_BASE_URL` (the runner sets it from `--url`); auth via `E2E_BEARER_TOKEN`;\ntiming via `await page.waitForSelector(...)`. `source_kind` selection +\nmulti-spec (`--specs`) details: `references\u002Flock-mode-spec-generation.md`.\n\n### Step 5 — Report\n\n```\n═══════════════════════════════════════\n  REGRESSION SPEC — Created\n  File: tests\u002Fe2e\u002F\u003Cname>.spec.js\n  Assertions: \u003Cn>\n  Passes: ✓ chromium-desktop, ✓ chromium-mobile\n  Recorded: spec-id \u003Cuuid> (source: \u003CsourceKind>)\n═══════════════════════════════════════\n```\n\nOmit the `Recorded:` line when cloud mode is off.\n\n---\n\n## Mode: VERIFY\n\nGrade a `\u002Fplan` plan against its live implementation. Each\ncriterion in the Acceptance Criteria section becomes one Playwright `test()`;\nper-criterion outcomes are recorded with a stable `criterion_hash` for\ntime-series tracking across verify runs.\n\n### Step V0 — Parse the plan\n\nRead the plan at the path in `$ARGUMENTS` (first positional after\n\n\u003C!-- host-contract: input-acquisition; grammar=subcommand; empty=ask-and-stop -->\n_This site: `subcommand` — verify requires a plan path; ask for it and stop rather than grading the app against a guessed plan._\n\n`verify`). Parse the Acceptance Criteria section using `scripts\u002Flib\u002Fplan-criteria-parser.mjs`.\n\nIf `found = false` → plan has no Acceptance Criteria; offer to add one.\nIf `errors.length > 0` → print + stop (malformed criteria).\n\nRegister the plan → capture `planId`.\n\n### Step V1 — Resolve base URL\n\nPriority: `--url` flag → `E2E_BASE_URL` → `PERSONA_TEST_APP_URL` → ask.\n\n### Step V2 — Generate one spec, N tests\n\nCreate `tests\u002Fe2e\u002Fverify-\u003Cplan-slug>.spec.js` with one `test()` per\ncriterion, using the translation-rules table.\n\nFull template + translation rules + persistence protocol:\n`references\u002Fverify-mode-generation.md`.\n\n### Step V3–V5 — Run + record (deterministic — ONE call)\n\nAfter authoring the verify spec (one `test()` per criterion, each carrying its\n`criterion_hash` as an annotation — see the reference), run + record in one\ndeterministic call. The runner runs the spec, maps each test result back to its\ncriterion via the `criterion_hash` annotation, and writes the\n`plan_verification_runs` + `plan_verification_items` rows itself — replacing the\nold model-remembered run → parse → `record-plan-verify-run` →\n`record-plan-verify-items` sequence:\n\n```bash\nCOMMIT=$(git rev-parse HEAD)\nnode scripts\u002Fux-lock-run.mjs verify --plan docs\u002Fplans\u002F*.md --spec tests\u002Fe2e\u002Fverify-*.spec.js --plan-id PLAN_UUID --commit \"$COMMIT\" --url BASE_URL --strict-selectors\n```\n\n(`--strict-selectors`: verify specs are newly generated, so the selector-policy\nlint fails rather than warns on an unmarked structural selector. Note V3\nregisters the SPEC row via cross-skill; this call owns only the RUN rows.)\n\n- **Every criterion is accounted for** (plan §2.3): a criterion with no matching\n  test → `passed:false` (\"no matching test result\"); multiple results for one\n  hash → fail if ANY failed; a test with no expected criterion (orphan) is\n  logged + counted but NOT inserted (the items table is strictly\n  per-expected-criterion).\n- The `criterion_hash` is recomputed from the plan by the runner (via\n  `plan-criteria-parser.mjs`), so it matches the authored spec's annotation\n  exactly. Pass `--plan-id` (the `plans` row UUID) or the run is not recorded.\n- **Graceful**: cloud off → runs + prints, skips recording; Playwright missing →\n  exit 5. **Verify is a report, not a blocker** — it exits 0 even when criteria\n  fail; a non-zero exit means the spec could not RUN (PW missing \u002F fatal), not\n  that a criterion failed. Exit 4 (`error.code: PERSIST_FAILED`) means it RAN\n  but its run or criterion rows were NOT recorded.\n- **Nothing gates on this today** — `\u002Fship` never queries `plan_satisfaction`\n  as a gate; do not tell the user a failing verify blocks shipping.\n  → `references\u002Fhistory-and-evidence.md` §Steps V3–V5 — read when asked whether\n  verify gates `\u002Fship`, or before claiming it does.\n\nThe verify-spec template MUST emit each test with\n`{ annotation: [{ type: 'criterion_hash', description: '\u003Chash>' }] }` — naming\nthe test by prose is NOT enough (the hash can't be recovered from a title).\nFull template + translation rules: `references\u002Fverify-mode-generation.md`.\n\n### Step V6 — Report\n\nEmit the satisfaction summary with pass\u002Ffail\u002F**skipped** counts per severity +\nthe list of failing P0 criteria. **A skipped P0\u002FP1 is neither a pass nor a\nfailure and must be rendered as its own line — never silently dropped**, since\nit is invisible to the `\u002Fship` gate by design (the store correctly excludes\nskipped items from `failing_p0_criteria`) and this report is the only place\nit can surface. Status rubric is a full precedence table, not three\nindependent conditions: `PLAN_NOT_SHIPPED` (any P0 failed) →\n`PLAN_PARTIAL` (any P0\u002FP1 skipped, or any P1 failed) → `PLAN_SATISFIED` (all\nP0+P1 evaluated and passing). Full template + precedence table:\n`references\u002Fverify-mode-generation.md`.\n\n### Failure policy\n\nVerify exits 0 even on fail — it's a report, not a blocker. The result is\nreadable via `cross-skill.mjs plan-satisfaction --plan-id \u003Cid>`\n(`failing_p0_criteria`), but no step reads it to gate a ship today (see the\n\"Nothing gates on this today\" rule above).\n\n---\n\n## When to use this skill\n\n- **After \u002Faudit-code convergence**: lock in the fixes before moving on\n- **After a \u002Fpersona-test P0 fix**: prevent recurrence\n- **After any production bug fix**: before closing the issue\n- **Before a major refactor**: baseline the current behaviour\n- **After \u002Fplan implementation**: `verify` mode grades the implementation\n\n---\n\n## Integration with other skills\n\n- **\u002Faudit-code** converges → **\u002Fux-lock** locks in fixes\n- **\u002Fpersona-test** finds P0 → fix → **\u002Fux-lock** prevents recurrence\n- **\u002Fship** warns if recent fixes lack regression specs\n- **\u002Fplan** produces Acceptance Criteria → **\u002Fux-lock verify** grades implementation\n\n---\n\n## Scope + limitations\n\nWorks for web apps served via URL. Limited for Obsidian\u002FElectron apps,\nCLI tools, and anti-bot-protected URLs. Full guidance:\n`references\u002Fscope-and-limitations.md`.\n\n---\n\n## Reference files\n\nThis skill's canonical flow is above. The files below cover specialised\nsituations — read them only when the trigger applies.\n\n| File | Summary | Read when |\n|---|---|---|\n| `references\u002Finput-acquisition.md` | Where a skill's arguments come from on any host, and what to do when there are none. | Reading $ARGUMENTS on a host that does not substitute it, or deciding what empty input means at a site. |\n| `references\u002Flock-mode-spec-generation.md` | LOCK mode — full Playwright spec template + fix-type assertion map + persistence recipe. | Mode: LOCK, about to write the spec body OR register it. |\n| `references\u002Fverify-mode-generation.md` | VERIFY mode — criterion parser wiring, translation rules, per-criterion run+record protocol. | Mode: VERIFY, Steps V0–V6 (parsing, generating, running, recording). |\n| `references\u002Fscope-and-limitations.md` | Where \u002Fux-lock works well, where it doesn't (Obsidian\u002FElectron), and fallback strategies. | Target is an Obsidian plugin \u002F Electron app \u002F CLI \u002F anti-bot-protected URL, OR bootstrapping Playwright harness from scratch, OR user is on Windows and Playwright MCP tools aren't appearing. |\n| `references\u002Fverification-discipline.md` | Verification discipline — pinned citations, figure provenance, two-direction proof, attribution, consumer-side checks. | Step 2.5 — the spec is written and must be proven RED against the un-fixed code before it is run and recorded. ALSO Step V6 — about to emit the VERIFY report, to apply §7's skipped-criteria rule. |\n| `references\u002Fhistory-and-evidence.md` | The measured cases behind Step 2.5's RED proof, the Step 3 store diagnosis, and why nothing gates on verify today. | Step 2.5 RED\u002FGREEN is ambiguous, OR the store's spec-run rows look empty, OR asked whether verify gates `\u002Fship`. |\n| `references\u002Fworktree-preflight.md` | Worktree preflight remedy — the skills:hydrate npm script to add when a linked worktree lacks the tooling tree. | A command dies with `MODULE_NOT_FOUND` in a linked worktree AND this repo has no `skills:hydrate` script. |\n\n— end of \u002Fux-lock —\n",{"name":5,"description":7},"main","938efbef34b7c76f0d112f336d1ac4018224d186","skills\u002Fux-lock","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills","https:\u002F\u002Fgithub.com\u002FLbstrydom","Studying M.Sc Computer Science at Heriot Watt","2026-11-10 15:13:10",{"source":8,"skillName":5,"commands":69,"prompt":79,"zipAvailable":80},[70,73,76],{"tool":71,"command":72},"npx","npx skills add Lbstrydom\u002Fclaude-engineering-skills --skill ux-lock",{"tool":74,"command":75},"bunx","bunx skills add Lbstrydom\u002Fclaude-engineering-skills --skill ux-lock",{"tool":77,"command":78},"pnpm","pnpm dlx skills add Lbstrydom\u002Fclaude-engineering-skills --skill ux-lock","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002FSKILL.md",true,[82,88,92,96,100,104,108,112],{"path":83,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":86,"sourceHtmlUrl":87},"gate-contract.json","REFERENCE","参考文档",9938,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Fgate-contract.json",{"path":89,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":90,"sourceHtmlUrl":91},"references\u002Fhistory-and-evidence.md",2304,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Fhistory-and-evidence.md",{"path":93,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":94,"sourceHtmlUrl":95},"references\u002Finput-acquisition.md",4511,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Finput-acquisition.md",{"path":97,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":98,"sourceHtmlUrl":99},"references\u002Flock-mode-spec-generation.md",5854,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Flock-mode-spec-generation.md",{"path":101,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":102,"sourceHtmlUrl":103},"references\u002Fscope-and-limitations.md",8328,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Fscope-and-limitations.md",{"path":105,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":106,"sourceHtmlUrl":107},"references\u002Fverification-discipline.md",28340,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Fverification-discipline.md",{"path":109,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":110,"sourceHtmlUrl":111},"references\u002Fverify-mode-generation.md",12289,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Fverify-mode-generation.md",{"path":113,"resourceType":84,"resourceTypeDesc":85,"sizeBytes":114,"sourceHtmlUrl":115},"references\u002Fworktree-preflight.md",3413,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002Freferences\u002Fworktree-preflight.md",[117,131,142,160,174,203],{"skillNo":118,"name":119,"nameZh":6,"description":120,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":121,"categories":122,"keywords":124,"publishedAt":56},"01M6J45X4FDB2AD5BGS4R4QY8X","stated-absent","Negative fixture — the contract's stated string never appears in this file.","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fgate-honesty\u002Fnegative\u002Fstated-absent\u002Fskills\u002Fstated-absent\u002FSKILL.md",[123],{"categoryNo":32,"categoryName":33,"taxonomyType":29,"taxonomyTypeDesc":30},[125,126,127,128,129,130],"stated absent","file","never","fixture","contract","STRING",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":138,"publishedAt":56},"01M6J45TAX2PPHETZ5TJZG20QQ","nonexistent-implementation","Negative fixture — contract references an implementation file that does not exist.","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fgate-honesty\u002Fnegative\u002Fnonexistent-implementation\u002Fskills\u002Fnonexistent-implementation\u002FSKILL.md",[137],{"categoryNo":32,"categoryName":33,"taxonomyType":29,"taxonomyTypeDesc":30},[139,140,126,141,128,129],"implementation","nonexistent implementation","references",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":151,"publishedAt":56},"01M6J45P5GN52YFMZ81T7NN1VF","document-only-with-params","Negative fixture — a document-only gate illegally carries params (schema must refuse this fake-check pattern).","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fgate-honesty\u002Fnegative\u002Fdocument-only-with-params\u002Fskills\u002Fdocument-only-with-params\u002FSKILL.md",[148],{"categoryNo":149,"categoryName":150,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[152,153,154,155,156,157,158,159,128],"only","document","with","document only with params","check","schema","gate","pattern",{"skillNo":161,"name":162,"nameZh":6,"description":163,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":164,"categories":165,"keywords":169,"publishedAt":56},"01M6J45J1CCZ7AXDGQKBA9VC8M","lying-skill","Fixture skill for the gate-honesty self-check — every gate here is deliberately dishonest.","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Ftests\u002Ffixtures\u002Fgate-honesty\u002Flying-skill\u002Fskills\u002Flying-skill\u002FSKILL.md",[166],{"categoryNo":167,"categoryName":168,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[170,156,158,171,172,128,173],"lying skill","fixture skill","self","for",{"skillNo":175,"name":176,"nameZh":6,"description":177,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":178,"categories":179,"keywords":185,"publishedAt":56},"01M6J45CW0DNN7K2W39E3PQHEY","visual-audit","Math-first, deterministic visual\u002Fpaint inspection — the 4th UX lens, complementing\npersona-test (journey), click-test (page), and nav-audit (system). Drives Playwright +\ncomputed styles + bounding boxes + CDP forced-pseudo-state to audit declared-token\nconformance, light\u002Fdark theme parity, layout physics, and affordance signifiers. A VLM\nis advisory-only and never gates. CI gate is drift-only on the changed contracted surface.\nTriggers on: \"visual audit\", \"check styling consistency\", \"theme parity\", \"dark mode parity\",\n\"design token drift\", \"paint audit\", \"button\u002Fcard consistency\", \"focus ring audit\",\n\"\u002Fvisual-audit\".","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-audit\u002FSKILL.md",[180,181,184],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":182,"categoryName":183,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},[52,186,187,188,189,190,40,191,127,192,193,194,195,196,197,152,198,199,200,201,202],"visual audit","visual","inspection","lens","design token","click","layout","physics","focus","drift","journey","cdp","card","math","persona","ci","design",{"skillNo":204,"name":205,"nameZh":6,"description":206,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":207,"categories":208,"keywords":209,"publishedAt":56},"01M6J44ZKH8DYSX1VAFSXP4AGB","skills","Quick reference for every available skill in this repo — name, one-line\npurpose, triggers, usage examples — without having to open each\nindividual SKILL.md document.\nTriggers on: \"\u002Fskills\", \"list skills\", \"what skills do you have\",\n\"show all skills\", \"skill cheatsheet\", \"skills help\",\n\"show me the skills\", \"what can you do\".\nUsage:\n  \u002Fskills                           — Compact reference table for all skills\n  \u002Fskills \u003Cname>                    — Full detail for one skill (e.g. \u002Fskills explain)\n  \u002Fskills --search \"\u003Cterm>\"         — Filter by name\u002Fdescription match","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fskills\u002FSKILL.md",[],[210,211,212,213,214,215,216,217,218,219,153,220,221,222,223,224,225,226,227,173,228],"show","usage","you","quick","filter","triggers","detail","compact","do","true","repo","explain","cheatsheet","show me","open","search","quick reference","by name","can"]