[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6J3XH106RWDD239KWKSW1TT":3,"skill-same:01M6J3XH106RWDD239KWKSW1TT":150},{"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":28,"publishedAt":58,"linkOnly":59,"markdownContent":60,"markdownBody":61,"frontMatter":62,"refName":63,"commitSha":64,"skillDirectory":65,"forksCount":14,"repositoryHtmlUrl":66,"repositoryHomepageUrl":6,"ownerHtmlUrl":67,"ownerBlogUrl":6,"ownerDescription":68,"updatedAt":69,"install":70,"resources":83},"01M6J3XH106RWDD239KWKSW1TT","audit-code",null,"Iteratively audit code against a plan with GPT + Gemini final gate.\n5-pass parallel static analysis (structure, wiring, backend, frontend,\nsustainability), R2+ ledger-driven suppression, debt capture for\nout-of-scope findings, max 6 rounds with 2-stable-rounds convergence.\nInvoke this for ANY code-correctness review, even a small pasted snippet\nor diff — don't just review it yourself directly; a single read-through\nis not a substitute for the multi-pass GPT+Gemini adjudication this skill\nperforms, and skipping it means the review didn't actually happen.\nTriggers on: \"audit my code\", \"audit my changes\", \"audit my PR\",\n\"check the implementation\", \"review my code\", \"audit code\", \"\u002Faudit-code\",\n\"audit this\", \"verify the implementation\".\nUsage: \u002Faudit-code \u003Cplan-file>              — Audit code against plan (--scope diff default)\nUsage: \u002Faudit-code \u003Cplan-file> --scope plan — Audit only files mentioned in the plan\nUsage: \u002Faudit-code \u003Cplan-file> --scope full — Full repo audit","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\u002F.claude\u002Fskills\u002Faudit-code\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57],"code","audit","audit code","default","debt","invoke","repo audit","static","for","convergence","my","r2","usage","scope","full","structure","max","frontend","files","only","read","repo","parallel","plan","analysis","sustainability","static analysis","gemini","review","2026-11-10 10:12:30",false,"---\nname: audit-code\ndescription: |\n  Iteratively audit code against a plan with GPT + Gemini final gate.\n  5-pass parallel static analysis (structure, wiring, backend, frontend,\n  sustainability), R2+ ledger-driven suppression, debt capture for\n  out-of-scope findings, max 6 rounds with 2-stable-rounds convergence.\n  Invoke this for ANY code-correctness review, even a small pasted snippet\n  or diff — don't just review it yourself directly; a single read-through\n  is not a substitute for the multi-pass GPT+Gemini adjudication this skill\n  performs, and skipping it means the review didn't actually happen.\n  Triggers on: \"audit my code\", \"audit my changes\", \"audit my PR\",\n  \"check the implementation\", \"review my code\", \"audit code\", \"\u002Faudit-code\",\n  \"audit this\", \"verify the implementation\".\n  Usage: \u002Faudit-code \u003Cplan-file>              — Audit code against plan (--scope diff default)\n  Usage: \u002Faudit-code \u003Cplan-file> --scope plan — Audit only files mentioned in the plan\n  Usage: \u002Faudit-code \u003Cplan-file> --scope full — Full repo audit\n---\n\n# Code Audit Loop\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\u002Faudit-code\u002FSKILL.md` in full before continuing — the later steps,\n> including the mandatory final gate, still apply.\n\nMulti-pass code audit with GPT + Gemini final review. Iterates until\nfindings stabilise or max 6 rounds.\n\n**Input**: `$ARGUMENTS` — plan file path (the spec the code is being audited\nagainst). Optional flags: `--scope diff|plan|full`, `--require \u003Cpaths>` (must-read files; any not FULL withholds convergence).\n\n\u003C!-- host-contract: input-acquisition; grammar=path+flags; 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 the conversation. This site is `path+flags`; on empty input, ask which plan to audit and stop — never guess a plan.\nFull contract: `references\u002Finput-acquisition.md`.\n\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---\n\n## Step 0 — Parse Input and Validate\n\nValidate: plan file exists, the helper scripts resolve, and a GPT route is\navailable — `OPENAI_API_KEY` **or** an active Azure profile\n(`AZURE_OPENAI_ENDPOINT`); ask which ROUTE exists, not whether one variable is\nset. Optional: `GEMINI_API_KEY` for Step 7 (falls back to Claude Opus when\nabsent). `AUDIT_DB_URL` for cloud learning (optional).\n\n**If a prerequisite does not resolve, follow `references\u002Fprerequisite-ladder.md`\n— do not proceed as though it did, and do not die mid-flow.** It defines the\nhydrate-then-retry step for absent helper scripts, the labelled adversarial-agent\nsubstitute when the GPT legs have no route, and which of `AUDIT_DEGRADED` \u002F\n`AUDIT_NOT_RUN` to report so a run that did not happen stays distinguishable\nfrom one that passed.\n\nInitialise session ID: `SID=audit-code-$(node -e \"process.stdout.write(Date.now()+'-'+process.pid)\")` — epoch ms plus a PID, so two sessions started in the same second get separate result, stderr and ledger files (a bare `$(date +%s)` gave both the same ones).\n\nKickoff card: `\u002Faudit-code — Starting | Plan: \u003Cpath> | Max 6 rounds | SID: $SID`.\n\n---\n\n## Step 0.5 — Architectural-memory catalogue (--scope=full only)\n\nWhen `--scope=full`, fetch the repo's symbol catalogue from architectural\nmemory (if populated) and inline a \"Symbol catalogue\" section into the\nprompt context — it lets the auditor catch cross-file duplication that\ndiff-scope cannot see.\n\n```bash\n# .audit\u002F is gitignored — a fresh checkout or new linked worktree lacks it, and the redirect fails first.\nmkdir -p .audit\n# 1. Resolve repo identity + active snapshot. Read JSON with node, never jq (not in check-deps).\nnode scripts\u002Fcross-skill.mjs resolve-repo-identity > .audit\u002Frepo-identity.json\nnode scripts\u002Fcross-skill.mjs get-active-refresh-id --repo-uuid \"$(node -p \"require('.\u002F.audit\u002Frepo-identity.json').repoUuid\")\" > .audit\u002Factive-refresh.json\n# 2. Fetch top-N symbols, CARRYING the refresh id forward (ARCH_AUDIT_FULL_TOPN, default 200) — never retype it.\nREFRESH_ID=$(node -p \"require('.\u002F.audit\u002Factive-refresh.json').refreshId\")\nnode scripts\u002Fcross-skill.mjs list-symbols-for-snapshot --json \"{\\\"refreshId\\\":\\\"$REFRESH_ID\\\",\\\"limit\\\":200}\"\n```\n\nFormat the rows as a `## Symbol catalogue (top N by domain)` section\nwith `(domain alphabetical, symbol_name alphabetical)` ordering. Note\ntruncation in the section header if `count == limit`.\n\nStates: `cloud:false` or `refreshId:null` → skip section silently;\n`RPC_ERROR` → skip section, log warning to stderr. Advisory — never fail the run.\n\n---\n\n## Step 1 — Choose Audit Scope\n\nGPT doesn't know what's \"new\" vs pre-existing — it flags everything in\nscope, so choose deliberately:\n\n| Scope mode | When to use | Behaviour |\n|---|---|---|\n| `--scope diff` (**DEFAULT**) | \"audit my recent work\", after implementing a phase | Auto-scopes to changed files with a **dirty-aware base** + unstaged + untracked (see below) |\n| `--scope plan` | Large refactor touching many files; user wants broad view | All files referenced in the plan |\n| `--scope full` | \"audit the entire codebase\" — explicit codebase-wide request | Full repo audit — slowest, catches cross-cutting issues |\n\nDefault is `--scope diff`. Switch only when the user explicitly asks or `git diff` is empty.\n\n**Dirty-aware base**: with no `--base`, the CLI diffs a **dirty** tree against\n`HEAD` (uncommitted work only) and a **clean** one against `HEAD~1` (last\ncommit); it logs `[scope] base resolved to \u003Cref> …`. ⚠ With BOTH committed and\nuncommitted work where the prior commit was already audited (a resumed\nclustered build), pass `--base \u003CclusterStartRef>` (or `--base HEAD`) and scope\nthe Gemini gate's `--diff` to the same range — never rely on the default across\na commit boundary. → `references\u002Fround-recipes.md` §Dirty-aware base — read when\nresuming a clustered\u002Fpartly-audited build.\n\n---\n\n## Step 2 — Run Code Audit\n\n### Round 1\n\n`$SCOPE` is the scope chosen in the table above — `diff` unless the user asked\nfor `plan` or `full`. **Pass it; do not hardcode `diff` here.** This block read\n`--scope diff` literally until 2026-09-06, so a run the user had explicitly asked\nto be `--scope full` executed as a diff audit and reported a clean result over a\nfraction of what was requested — the scope flag this skill's own Usage lines\nadvertise was accepted and then dropped.\n\n```bash\nSCOPE=diff   # or plan \u002F full, per the table above and the user's request\n# PLAN_FILE = the ONE plan path \u002Faudit-code was invoked with, assigned verbatim.\n# Not a glob: an assignment does not expand it, so the CLI would get the pattern itself.\nnode scripts\u002Fopenai-audit.mjs code \"$PLAN_FILE\" --scope \"$SCOPE\" --out .audit\u002F$SID-r1-result.json 2>.audit\u002F$SID-r1-stderr.log\n```\n\n### Round 2+\n\nR2+ mode changes the prompt rubric and enables ledger-driven suppression.\nFull flag contract, smart pass selection, automatic behaviour, and\ntool pre-pass rules: `references\u002Fr2-plus-mode.md`.\n\nDiff base — match R1 (`git status --porcelain` counts UNTRACKED files as dirty;\nnever `git diff --quiet`, which ignores them). Non-empty output → `BASE=HEAD`\n(dirty tree); empty → `BASE=HEAD~1` (clean, last commit). Pass\n`--base`\u002FclusterStartRef instead across an audited commit boundary.\n\n```bash\nBASE=$([ -n \"$(git status --porcelain)\" ] && echo HEAD || echo HEAD~1)\ngit diff --no-textconv --output=.audit\u002F$SID-diff.patch \"$BASE\" -- .\n```\n\nUse `--output`, never a PowerShell `>` (it re-encodes the patch).\n**Include UNTRACKED new files** — `git diff` omits them, so a brand-new file would\nreach the auditor with no `[CHANGED]` annotation. Append each as a new-file diff\nagainst `\u002Fdev\u002Fnull`. **POSIX shell only** (Git Bash on Windows), even on a\nWindows\u002FCopilot host:\n\n```bash\ngit ls-files --others --exclude-standard -z | xargs -0 -r -I{} git diff --no-index --no-color -- \u002Fdev\u002Fnull \"{}\" >> .audit\u002F$SID-diff.patch 2>.audit\u002F$SID-untracked-diff-stderr.log || true\ncat .audit\u002F$SID-untracked-diff-stderr.log   # non-empty = a real failure occurred, not the expected exit\n```\n\n`|| true` absorbs only `git diff --no-index`'s expected exit 1; it writes nothing to\nstderr in that case, so **a non-empty stderr log is a genuine failure — check it\nbefore trusting the patch.** → `references\u002Fround-recipes.md` §untracked-file append\n— read when that log is non-empty.\n\n```bash\n# CHANGED = the exact files you edited this round, comma-separated, no globs:\n# the CLI splits on commas, so a pattern reaches it literally.\nCHANGED=\"scripts\u002Fopenai-audit.mjs,tests\u002Faudit-skill-shell-recipes.test.mjs\"\nFILES=\"$CHANGED\"                            # + any dependent you also want in scope\nPASSES=\"sustainability\"                     # e.g. sustainability,backend — per r2-plus-mode.md\nnode scripts\u002Fopenai-audit.mjs code \"$PLAN_FILE\" --round 2 --ledger .audit\u002F$SID-ledger.json --diff .audit\u002F$SID-diff.patch --changed \"$CHANGED\" --files \"$FILES\" --passes \"$PASSES\" --out .audit\u002F$SID-r2-result.json 2>.audit\u002F$SID-r2-stderr.log\n```\n\n**R2+'s scope is always the diff, not Round 1's `--scope`** — `--files` overrides\n`--scope`, deliberately; do not add `--scope \"$SCOPE\"` to R2+ (it is silently\nignored). → `references\u002Fround-recipes.md` §R2+ scope — read when tempted to widen R2+.\n\n### Automatic waves and rubrics (no flag)\n\n- **Requirements rubric** — when `.requirements\u002Fledger.json` exists every pass gets a\n  `\u003Crequirements_rubric>`. A `[stale]` `[requirements]` stderr line → refresh with\n  `node scripts\u002Frequirements.mjs extract --files \u003C…>` then `reconcile`.\n  → `references\u002Fround-recipes.md` §Requirements rubric — read when that line appears.\n- **Duplication wave (Wave 5)** — a near-duplicate of an indexed symbol becomes a\n  `[Duplication]` finding that **gates convergence like a `quickfix` finding**. JS\u002FTS\n  files only — another language is outside its coverage, never \"clean\". Intentional\n  duplicate → `@duplicate-justification` pragma above the declaration (never under\n  `tests\u002F`, which is not read); a pragma whose target doesn't match raises its own\n  `Orphaned suppression pragma` finding. Opt out with `--passes` omitting\n  `duplication`. → `references\u002Fduplication-wave.md` — read when a `[Duplication]`\n  finding is intentional or a pragma is not honoured.\n\n### Handle results\n\nIf `verdict` is `INCOMPLETE` (passes timed out), offer: re-run with higher\ntimeout, or continue with partial results.\n\nResults card per round: `ROUND N AUDIT — \u003Cverdict> | H:x M:y L:z | Deduped: d | Cost: ~$… | Top: [H1] …`.\n\n---\n\n## Step 3 — Triage (validity × scope × action)\n\n**You are a peer, not a subordinate.** For each finding, record three\northogonal judgements:\n\n| Dimension | Values | Meaning |\n|---|---|---|\n| **validity** | `valid` \u002F `invalid` \u002F `uncertain` | Is the concern real? |\n| **scope** | `in-scope` \u002F `out-of-scope` | Does it cite code this audit targeted? |\n| **action** | `fix-now` \u002F `defer` \u002F `dismiss` \u002F `rebut` | What happens next? |\n\n### Triage rules\n\n- `validity=invalid` → action MUST be `dismiss` or `rebut`\n- `validity=uncertain` → action MUST be `rebut` (GPT deliberation)\n- `validity=valid` + `scope=in-scope` + HIGH\u002FMEDIUM → `fix-now` (unless accepted-permanent debt)\n- `validity=valid` + `scope=out-of-scope` + **load-bearing** → `fix-now` (treat as in-scope — see impact test below)\n- `validity=valid` + `scope=out-of-scope` + **independent** → `defer` eligible (pre-existing debt)\n- `validity=valid` + `scope=in-scope` + LOW → operator choice\n- Only `validity=valid` findings can be deferred\n\n**Scope is decided by impact, not authorship (load-bearing test).** \"My PR\ndidn't touch this line\" is NOT a defer pass. Before any `out-of-scope` finding\nroutes to `defer`, apply the test: *does the correctness or stability of the\nchange I'm shipping depend on the cited code path?*\n\n- **Load-bearing** — the new code calls into, reads state from, or otherwise\n  rides on the cited path → it is in-scope **for the fix\u002Fdefer decision** even\n  if pre-existing. `fix-now`, or explicitly gate the feature on it and say so.\n  **Never silent-defer a load-bearing finding.**\n- **Independent** — the path fails identically with or without this change; the\n  new code does not depend on it → genuine `defer` (pre-existing debt).\n\nA pre-existing finding **in a file you changed** is a yellow flag, not a green\none: you usually touched the file *because* your change now rides on its\nbehaviour. Default such findings to \"prove independence\" rather than to defer.\nPassing tests don't clear this — a green suite only covers exercised paths, not\nthe load-bearing path's failure modes.\n\n**Same-file independence needs more than \"doesn't call it\".** For a finding in a\nfile the diff touches, the independence sentence must truthfully state BOTH (a) the\ncited code shares no column\u002Fconstraint\u002Finvariant with the new code (a shared *table*\nis not enough) and (b) its writes do not run in the SAME transaction instance (a\nshared request\u002Ffile\u002Fsubsystem is not enough). Either unstateable → load-bearing.\n→ `references\u002Ftriage-rubrics.md` §Same-file independence — read when deferring a\nsame-file finding.\n\n**Honest-deferral check.** Every `defer` of a valid finding names (1) the root\ncause, (2) the minimal in-scope fix considered and rejected, (3) the residual risk;\nan out-of-scope `defer` also names the independence (both parts above for same-file).\nCan't write it truthfully → `fix-now`. **Never `defer` because the correct fix is\nmerely larger** — size is not scope, and neither is authorship.\n→ `references\u002Ftriage-rubrics.md` §Honest-deferral check — read when writing a defer.\n\n### Mechanical vs architectural\n\nEach finding has `is_mechanical: true\u002Ffalse` from GPT:\n- **Mechanical**: deterministic fix. Fix immediately, no deliberation.\n- **Architectural**: judgement call. Needs deliberation, resets stability if new.\n\n### Tiered rebuttal (when action=rebut)\n\n| Severity | Deliberation |\n|---|---|\n| HIGH | ALWAYS send to GPT deliberation |\n| MEDIUM | ALWAYS send to GPT deliberation |\n| LOW | Claude decides locally |\n\nOnly send rebuttal if rebut HIGH or MEDIUM findings exist:\n\n```bash\nREBUTTAL_FILE=.claude\u002Ftmp\u002Frebuttal.md   # the rebuttal text you wrote for the disputed finding(s)\nnode scripts\u002Fopenai-audit.mjs rebuttal \"$PLAN_FILE\" \"$REBUTTAL_FILE\" --out .audit\u002F$SID-resolution.json 2>.audit\u002F$SID-rebuttal-stderr.log\n```\n\n### Convergence\n\nQuality threshold: `HIGH == 0 && MEDIUM \u003C= 2 && quickFix == 0`\n\nStability uses `_hash` for exact cross-round matching:\n- New hash not in prior set = genuinely new → resets stability\n- Mechanical-only findings do NOT require stability rounds\n\n| Condition | Action |\n|---|---|\n| Threshold NOT met | Fix → re-audit |\n| Threshold met, new architectural | Fix → re-audit (stability resets) |\n| Threshold met, mechanical only | Fix → re-audit (stability NOT reset) |\n| Summary line ends `— not convergence evidence` (changed lines, an unrecognised file type, or a `--require` subject not read in full) | **Not stable, whatever H\u002FM\u002FL say** — the change was not read (`changed-lines-unread` \u002F `unrecognised-files-unreviewed` \u002F `required-subjects-not-full`). Re-run short files with `--files`; too big alone → report not converged. Unrecognised type: `.auditignore` it or report upstream. Required subject: fix the read, never `.auditignore` it |\n| Threshold met, 0 new, 2\u002F2 stable | **CONVERGED** → Step 6, then REQUIRED Step 7 |\n| Same file\u002Fconcern recurs 3 rounds running | **Pivot**: stop, propose a new design (`references\u002Fpivot-rule.md`) |\n| Round 6, not stable | Run the structural-or-stop card, present it to the operator, then REQUIRED Step 7 |\n\n**Max 6 rounds for code audits, 8 absolute — enforced by `openai-audit.mjs`.** Round 7 exits `4` (`CAPPED`) with\na structural-or-stop card: a stop for a human call, never a retry. At round 6 without convergence run\n`node scripts\u002Faudit-structural-card.mjs --sid \"$SID\" --mode code --plan \"$PLAN_FILE\"` and present the card to the\noperator (STOP \u002F STRUCTURAL \u002F CONTINUE); continuing is their call (`references\u002Fround-cap-and-structural-card.md`).\n\n**Step 7 (Gemini final review) is MANDATORY** after the last audit round,\nregardless of convergence. No-key degradation ladder (`references\u002Fgemini-gate.md`\n— never a silent skip): Gemini → Claude Opus fallback → an **independent\nadversarial review agent** over the code + findings (verdict in the same\nAPPROVE\u002FCONCERNS\u002FREJECT shape) → only when none is available, output\n`FINAL_GATE_SKIPPED` and do not claim full final-gate validation.\n\n---\n\n### Step 3.7 — Detector-first census (cross-cutting findings)\n\n**An audit's instance count is a floor, not a scope** — the *tool* enumerates, not you.\n**Trigger is mechanical**: `affectedFiles.length > 1` (or an explicit `crossCutting: true`\nyou set at triage); single-file findings are exempt. For each cross-cutting finding,\nrecord a **structured** `detector` (`kind`, `pattern`, `globs`, `baseline`,\n`disposition`) on its ledger entry — never a shell command. Dispositions key on\n`\u003Cpath>::\u003Ctrimmed matched line>`, never a line number. **The detector's output IS the\nfix scope** — fix or disposition everything it finds, not only the instances the audit\nnamed. → `references\u002Fdetector-census.md` §Step 3.7 — read when recording a detector\n(schema + key format).\n\n## Step 3.5 — Update Adjudication Ledger\n\nAfter each deliberation round, write ledger entries for every finding before\nproceeding to Step 4. The ledger drives R2+ rulings injection and post-output\nsuppression.\n\nFull writer invocation example + status field semantics: `references\u002Fledger-format.md`.\n\n**Dismissing a finding that carries `_priorRuling`** (kept beside an earlier\nruling, named with its category) needs a concern decision in its triage entry:\nsame concern reworded → `\"sameConcernAs\": \"\u003Cits topicId>\"`; a different defect\nin the same file → `\"newConcern\": true`.\n`write-ledger-entries` refuses a batch with an undecided one (exit 2).\nThree linked dismissals hard-suppress the next raise. See `references\u002Fledger-format.md`.\n\n---\n\n## Step 3.5b — Record Triage Outcomes (closes the adaptive-learning loop)\n\n**Automatic — no manual step.** `write-ledger-entries.mjs` labels the round it just\ntriaged (once every finding has a ruling), and each R2+ `openai-audit.mjs` invocation\nre-checks the prior round idempotently, so the **final** round is labelled too. It\nbridges the ledger → `finding_adjudication_events` + `audit_pass_stats` +\n`audit_findings` + `audit_runs.labeled` (cloud) and `.audit\u002Foutcomes.jsonl` (local\nbandit reward). Best-effort: a failure logs `[finalize] WARN` and the audit proceeds.\n\n**Manual fallback — only if that WARN appeared**, or on **non-Claude-Code \u002F cloud-off\nCI** where the orchestrator path didn't fire (inside `\u002Fcycle` it is fully covered):\n\n```bash\nROUND=2   # the round number just completed\nnode scripts\u002Fwrite-code-outcomes.mjs --result \".audit\u002F$SID-r$ROUND-result.json\" --ledger .audit\u002F$SID-ledger.json --round \"$ROUND\"\n```\n\nBoth paths share `finalizeRoundOutcomes`, so they are idempotent (cloud re-labels; the\nlocal append is marker-guarded). The ledger must already carry per-finding rulings\n(Step 3.5): **`labelled: 0` with a non-zero `total` is a failure to fix, never a pass.**\n\n---\n\n## Step 3.6 — Debt Capture\n\nPersist out-of-scope valid findings to `.audit\u002Ftech-debt.json` so future\naudits suppress them automatically. Eligible candidates: Step 3 triage\nfindings with `action = defer`.\n\n> **A rejected capture is a lost suppression.** An over-cap rationale is rejected and the run exits non-zero: any deferral that fails to land is never suppressed in a future audit — so `9 of 15 captured` is a failure, not a ship.\n> Read the `Rejected entries:` listing, fix what it names, then re-run (capture is idempotent). Do not shorten a rationale to fit the 4000-char limit — the Step 3 honest-deferral requirement above (root cause + rejected minimal fix + residual risk + independence) is the point, and the limit is sized to it.\n\nFull per-reason field requirements, capture flow, sensitivity-scan rules,\nand status card format: `references\u002Fdebt-capture.md`.\n\n---\n\n## Execution order — critical\n\n**Wait for rebuttal BEFORE fixing.**\n\n1. Send rebuttal (if rebut HIGH\u002FMEDIUM findings from triage)\n2. Wait for rebuttal response\n3. Write adjudication ledger (Step 3.5)\n4. Record triage outcomes — automatic next-round (Step 3.5b); manual CLI only for the final\u002F1-round case\n5. Capture deferrable debt (Step 3.6)\n6. Fix ALL findings together (Step 4)\n7. Run tests\n8. Verification audit (Step 5) — debt suppression runs automatically\n\n---\n\n## Step 4 — Fix Findings\n\nALL HIGH must be fixed. MEDIUM until ≤2 remain. LOW if mechanical.\n\n> **Read `finding.verification` before you triage on `finding.severity`.**\n> The deterministic existence gate resolves every \"file\u002Fmodule X is missing\"\n> claim against the real repo inventory and attaches a sibling `verification`\n> object. `finding.severity` is the model's ORIGINAL claim and is deliberately\n> never rewritten — so a **`verification.verification === 'refuted'`** finding\n> still reads `HIGH` in `findings[]` while the audit verdict has already\n> discounted it to `verdictSeverity: 'LOW'`.\n>\n> - `refuted` — **do not fix.** The cited file exists; the claim is a\n>   `--scope diff` context artefact. Fixing it means editing a file that was\n>   never missing. The stderr log names these: `[verify-gate] … REFUTED`.\n> - `confirmed` \u002F `requires_verification` — triage normally at `severity`.\n>   A `requires_verification` on a list claim may say \"N of M cited path(s) DO\n>   exist\" — the claim is partly false; verify the rest before acting.\n>\n> Triage on `effectiveSeverity(finding)` from\n> [`finding-verification.mjs`](https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fscripts\u002Flib\u002Faudit\u002Ffinding-verification.mjs),\n> never on a hand-rolled copy of the rule.\n\n**Track which files you modify** — you'll need this for `--changed` in Step 5.\nCard: `FIXING — N findings | Auto-fixed (mechanical): a | Per recommendation: b | Compromises: c | Skipped (LOW): d | Files modified: …`;\nthen list each fix: `[ID] description → file:lines`.\n\nAfter fixing, update ledger entries to `remediationState: 'fixed'` for\nfixed items.\n\n### Step 4.5 — Prove every new guard in BOTH directions\n\nFor each finding fixed **with a new test, assertion or contract**: a green suite\ndoes not distinguish \"the fix worked\" from \"the check stopped looking\". Only\nrevert-and-watch-it-go-red does, and it costs seconds.\n\n1. Revert the fix (the fix only — not the test).\n2. Run → **confirm RED**, and read the failure text: it must name the actual\n   defect, not fail for an unrelated reason.\n3. Where the fix closes **independent** failure modes, revert them **one at a\n   time**. Two defects on one line mask each other — that is how a container\n   health check shipped broken for months, each bug making the other invisible.\n4. Restore → confirm GREEN. Record that you ran it, and what the red said.\n\nA before\u002Fafter observation of a pre-existing defect is **not** a negative control.\nAn \"expect empty\" assertion needs a vacuous-pass guard (one assertion proving the\nprobe can find something it must find). When the check itself fails, suspect the\ninstrument first. A guard worth keeping past this session gets the\n`examples\u002Fcontract-test-scaffold.md` skeleton (disposition + retirement fields).\n→ `references\u002Fverification-discipline.md` §3, §5.\n\n---\n\n## Step 5 — Verify and Loop (R2+ Mode)\n\nAfter fixes, re-audit using R2+ mode (back to Step 2):\n\n1. Collect files modified during Step 4 → `--changed`\n2. Compute scope: changed + importers → `--files`\n3. Regenerate the diff with Step 2's Round 2+ recipe exactly — dirty-aware `BASE`,\n   the untracked-file append, and the stderr-log check\n4. Build `--passes` from file types\n5. Run R2+ audit with `--round \u003CN> --ledger --diff --changed --files`\n\nTrack finding churn using `_hash` fields: resolved \u002F recurring \u002F new.\nCard: `ROUND N → ROUND N+1 (R2+ mode) | H:x M:y L:z | New: n | Suppressed: s | Stable: k\u002F2`.\n\n### Step 5.0b — Re-run every detector at FULL scope (blocks convergence)\n\n```bash\nnode scripts\u002Flib\u002Faudit\u002Fdetector.mjs .audit\u002F$SID-ledger.json\n```\n\nExit 0 = every detector reached zero and every match is dispositioned; exit 1 =\nblocked; exit 2 = the ledger could not be read, which is \"no census happened\"\nand never a pass.\n\n**At each detector's own `globs`, NOT the round's changed files** — a diff-scoped\nre-run misses both the unfixed class members and any occurrence the fix itself just\nwrote. Convergence requires `blocked === false`; `baseline` reports progress, never\nthe pass condition. A detector that errors here is reported `errored` in Step 6's\ncensus, never folded into \"reached zero\". → `references\u002Fdetector-census.md` §Step 5.0b\n— read when a detector result is disputed.\n\n### Step 5.1 — Debt Resolution Prompt\n\nAfter verification, reopened debt topics with no matching finding this round\nare candidates for resolution. Full prompt + resolver invocation:\n`references\u002Fdebt-capture.md`.\n\n---\n\n## Step 6 — Convergence Report (Pre-Final)\n\n**Named states, per pass\u002Fwave\u002Fcapability, not a bare \"ran\".** Attempted-but-\nfailed is a different thing from never-attempted (`references\u002Fverification-discipline.md`\n§7):\n\n| State | Meaning |\n|---|---|\n| `completed` | finished without error, applicable to the resolved scope — decoupled from finding count: a `completed` pass stays `completed` at 0, 1, or many findings |\n| `errored` | started, did not complete (exception, timeout, non-2xx from a provider) |\n| `ineligible` | does not apply to this repo's resolved language\u002Fscope (e.g. a frontend-specific pass on a backend-only diff) |\n| `unavailable` | a concrete missing prerequisite — e.g. `AUDIT_DB_URL` unset for the architectural-memory catalogue |\n| `not-reached` | the round's control flow did not get to this pass\u002Fwave before stopping (rare — see below) |\n| `uncovered` | **file-level, from the result's `_coverage`, never from a pass:** changed files the audit did not (fully) examine — an unrecognised file type, an unreadable file, a deleted source file, a partial (head-cut or windowed) read. NOT `ineligible`: `ineligible` is an EXPECTED scope exclusion, and labelling a C# diff that way is exactly how twelve `.cs` files went unaudited under an APPROVE |\n\n**Per-round record.** `arch-memory` is resolved once by Step 0.5 and carried into\nevery round's census (`ineligible` under `--scope=diff`). The five passes and three\nmechanical waves are seeded `pending` at each round's start; on an aborted round every\nuntouched row finalizes `not-reached` (never left `pending`) — it signals a killed\nprocess or hard timeout. Render the current round's rows plus `arch-memory`.\n→ `references\u002Fconvergence-report.md` §per-round execution record — read when a row's\nstate is ambiguous.\n\nReport card: `CONVERGED[ (\u003Ccount> \u003Ckind> · … — see census)] — Round N | Final: H:x M:y L:z | Rounds | Time | Cost | Files changed | Remaining (accepted): [Mn]…`,\nthen a `CENSUS` block — one `\u003Cidentifier>  \u003Cstate>  (\u003Creason>)` row per pass, wave,\n`arch-memory` and `file coverage`. → `references\u002Fconvergence-report.md` §example\nreport card — read before printing a report with a non-`completed` row.\n\n**A wave row over a change it could not read says so.** The four JS\u002FTS-only waves (`orphan-introduced`, `event-wiring-symmetry`,\n`duplication`, `adjacency`) report `ineligible (0 of N changed files are js\u002Fts; nothing was examined)` — never `completed`,\n`ANALYZED_CLEAN`, `clean` or `not-triggered` — when none of the changed files is one they can read; a partial one adds\n`examined k of n`. The tool pre-pass likewise names each project's state (`ok` \u002F `failed` \u002F `timeout` \u002F `deadline_exceeded` \u002F\n`ambiguous_project` \u002F `no_project` \u002F `skipped_budget` \u002F `no_tool`) in `_coverage.tools`; none of them is a clean lint.\n\nIdentifiers are the real ones — `structure`\u002F`wiring`\u002F`backend`\u002F`frontend`\u002F\n`sustainability` (`scripts\u002Flib\u002Fprompt-seeds.mjs`), `quickfix`\u002F`duplication`\u002F\n`adjacency` (`scripts\u002Flib\u002Faudit-shadow.mjs`'s `MECHANICAL_WAVES`) — not\ninvented labels. Every non-`completed` row carries a concrete reason in parentheses.\n\n**The `file coverage` row is rendered from the round's `_coverage` (`node -p` the result JSON; its `status`, `gate` and the\none-line suffix the summary already printed).** `complete` → `completed`; `partial` → `uncovered` with the suffix as its\nreason; `none`\u002F`incomplete` → the round is already `INCOMPLETE` (exit 3) and must not be reported as converged at all.\nCopy the suffix, never paraphrase it: it names the files.\n\n**A round with any non-`completed` row cannot print a bare `CONVERGED`.**\nThe suffix names **every kind present, with its own count** — never hardcode one\nkind; a round with only `ineligible` rows names them `ineligible`, never \"errored\".\n\nSave convergence snapshot to `docs\u002Fplans\u002F\u003Cname>-audit-summary.md`.\n\nDo not close the loop in Step 6 — completion requires Step 7.\n\n### Step 6.5 — Regenerate Telemetry Dashboard (advisory, source-repo only)\n\n**Source-repo-gated** — run ONLY when\n`package.json.name === \"claude-engineering-skills\"`; skip silently elsewhere. Never\nblocks the audit. Print the `file:\u002F\u002F…\u002Fdashboard\u002Ftelemetry.html` link; never stage it.\n\n```bash\nnode scripts\u002Fbuild-dashboard.mjs telemetry 2>&1 || true\n```\n\n→ `references\u002Fconvergence-report.md` §Step 6.5 — read when running it in a consumer.\n\n### Step 6.5b — Solo author-model control (background, toggle-gated)\n\n**Source-repo-gated** — run ONLY when `package.json.name === \"claude-engineering-skills\"`\n(skip silently in consumers). Fire it **in the background, non-blocking** (it takes\nminutes; it must NEVER delay or gate the audit result). It self-gates on the\n`arm-eval` shadow toggle and is incremental, so firing it unconditionally is safe;\na failure is logged and ignored.\n\n```bash\nnode scripts\u002Fsolo-control-audit.mjs run --model claude-sonnet-5\nnode scripts\u002Fsolo-control-audit.mjs run --model claude-fable-5\n# run each backgrounded \u002F in its own terminal — they're independent, not chained\n```\n\n→ `references\u002Fconvergence-report.md` §Step 6.5b — read when asked why it runs.\n\n### Step 6.6 — Recommended next (à-la-carte advisor)\n\nSuggest the FEW additional lenses that fit THIS change, grounded in the final-round\naudit result:\n\n```bash\nFINAL_ROUND=2   # the last round actually run\nnode scripts\u002Fcross-skill.mjs recommend-skills --findings \".audit\u002F$SID-r$FINAL_ROUND-result.json\" --just-ran audit-code --format human\n```\n\nPrint the card verbatim if non-empty; **if it's empty, say nothing** (silence is\ncorrect, not a failure). A nudge, never a gate. → `references\u002Fconvergence-report.md`\n§Step 6.6 — read when explaining a recommendation.\n\n### Step 6.7 — Cross-surface honesty clause (GREEN ≠ REALIZED)\n\nWhen the change introduces a user-visible DYNAMIC value that duplicates or re-derives\none another surface shows (or a `derived-state-parity` finding was raised), a green\naudit does not prove they agree at runtime: do not close it on \"looks correct\" —\nrequire a shared SSoT, a parity assertion, or a declared `data-engine-claim` surface.\n→ `references\u002Fconvergence-report.md` §Step 6.7 — read when that pattern appears.\n\n---\n\n## Step 7 — Gemini Independent Review (MANDATORY)\n\n> **Coverage rides into the review automatically.** The transcript builder projects each round's `_coverage` (every file\n> short of full coverage, capped, plus a digest of the full ledger), and the review envelope opens with an **Audit Coverage**\n> note naming what was NOT examined. Do not summarise it away in `--summary`; if the note is present the reviewer was told,\n> and an APPROVE over it is an APPROVE of the examined files only. A coverage gap is not itself release-blocking.\n\nRun the final reviewer — the newest Gemini Pro by default (`latest-pro`, resolved at runtime; override with `FINAL_REVIEW_MODEL`) as the final gate. Falls back to Claude Opus when\n`GEMINI_API_KEY` is absent.\n\n**Build the transcript first** — the reviewer reads a file no earlier step\nwrites. Never hand-assemble the JSON:\n\n```bash\nnode scripts\u002Fbuild-audit-transcript.mjs --sid $SID --changed \"$CHANGED\"\n```\n\nIt discovers every `.audit\u002F$SID-r\u003CN>-result.json`, folds in\n`.audit\u002F$SID-ledger.json` as the deliberation trail, and writes\n`.audit\u002F$SID-transcript.json`. **`--changed` is the reviewer's scope filter** —\npass the same list you gave the R1 audit; without it out-of-scope findings stop\nbeing dropped and the builder warns on stderr.\n\nRead the cloud run id from the LAST round's result, passing the path as an argument\n(never a literal inside `-e`) — **`--run-id` arms the verdict write-back to\n`audit_runs`; without it the verdict is persisted nowhere:**\n\n```bash\nROUND=2   # the last round actually run\nRUN_ID=$(node -e \"const fs=require('fs'); try { process.stdout.write(JSON.parse(fs.readFileSync(process.argv[1],'utf8'))._cloudRunId||''); } catch { process.stdout.write(''); }\" \".audit\u002F$SID-r$ROUND-result.json\")\n```\n\nIf `gemini-review.mjs` warns that cloud is on but `--run-id` is absent, the extraction\nfailed — don't ignore it. → `references\u002Fconvergence-report.md` §Step 7 RUN_ID — read\nwhen `RUN_ID` is unexpectedly empty.\n\nIf `RUN_ID` is non-empty:\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript.json --out .audit\u002F$SID-gemini-result.json --run-id \"$RUN_ID\" 2>.audit\u002F$SID-gemini-stderr.log\n```\n\nOtherwise (cloud genuinely off — `RUN_ID` empty):\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript.json --out .audit\u002F$SID-gemini-result.json 2>.audit\u002F$SID-gemini-stderr.log\n```\n\nAdd `--round 1` to the first run. **Hard cap: 2 final-review rounds** —\n`gemini-review.mjs` refuses `--round 3`; never loop past it.\n\n**Act on `gateDisposition`, not the verdict word.** The result JSON (and the\nstdout summary `Gate: …`) carries a code-computed `gateDisposition`; `verdict`\nstays the reviewer's own word:\n\n| `gateDisposition` | Action |\n|---|---|\n| `approve` | Done → final report. |\n| `approve_with_debt` | Done — also for `CONCERNS`\u002F`CONCERNS_REMAINING`. Every remaining finding is `release_blocking: false`: capture them (below), list them in the report. Do **not** re-run the reviewer and do **not** ask the user to override. |\n| `blocked` | `gateDispositionDetail.reasons` names why (a release-blocking finding, a HIGH `wrongly_dismissed`, `REJECT`, or coverage gate). Round 1 → Step 7.1: fix the blocking items, rebuild the transcript, run round 2. Round 2 → present the named blocking items to the user; there is no round 3. |\n\nRound 2 takes the round-1 result as structured memory — its findings are\nsettled, and a re-raise is dropped in code unless marked `is_reopened`:\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript-v2.json --round 2 --prior .audit\u002F$SID-gemini-result.json --out .audit\u002F$SID-gemini-result-v2.json 2>.audit\u002F$SID-gemini-stderr-v2.log\n```\n\nCapture non-blocking findings as debt from the result that closed the gate\n(`-v2` after round 2; release-blocking ones are never captured; `--dry-run`\npreviews):\n\n```bash\nnode scripts\u002Fdebt-auto-capture.mjs --final-review .audit\u002F$SID-gemini-result.json --run $SID\n```\n\nOptional observation-only shadow reviewer (`FINAL_REVIEW_SHADOW`) — never gates.\n→ `references\u002Fconvergence-report.md` §shadow A\u002FB reviewer — read when it is set.\n\nFull transcript-building, verdict routing, Step 7.1 deliberation protocol,\nand category-error handling: `references\u002Fgemini-gate.md`.\n\n---\n\n## UX Rules\n\n1. Status card after every phase (compact format above)\n2. Never dump raw JSON — parse and summarise\n3. Show every fix with file + line reference\n4. Cost tracking: `cost ≈ (input × 2.5 + output × 10) \u002F 1M`\n5. Batch all user decisions into one prompt\n6. Progress: show pass timings from stderr\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\u002Fround-recipes.md` | Step 1–2 detail — dirty-aware base rationale, diff-recipe stderr handling, R2+ scope rule, requirements rubric. | Resuming a partly-audited clustered build, OR the untracked-diff stderr log is non-empty, OR a `[stale]` requirements line appeared. |\n| `references\u002Fduplication-wave.md` | Duplication wave (Wave 5) — what it scans, the @duplicate-justification pragma, test-dir and orphan rules. | A `[Duplication]` finding is intentional, OR a pragma is not being honoured. |\n| `references\u002Fr2-plus-mode.md` | R2+ audit mode — ledger rulings, diff annotations, smart pass selection, suppression. | Round ≥ 2 AND need to choose passes OR troubleshoot suppression. |\n| `references\u002Ftriage-rubrics.md` | Step 3 rubrics in full — same-file independence (column\u002Fconstraint + transaction) and the honest-deferral check. | Step 3 — about to defer a finding, especially one in a file the diff touches. |\n| `references\u002Fdetector-census.md` | Detector-first census — the ledger detector schema, disposition keys, and why Step 5.0b re-runs at full scope. | Step 3.7 — a finding spans more than one file, OR Step 5.0b — a detector result is disputed. |\n| `references\u002Fledger-format.md` | Adjudication ledger schema + writer invocation example for each finding outcome. | Step 3.5 — about to write ledger entries, OR diagnosing R2+ suppression misbehaviour. |\n| `references\u002Fdebt-capture.md` | Phase D debt ledger — persist out-of-scope valid findings so they don't re-surface. | Step 3.6 — candidate deferrals present, OR Step 5.1 — debt resolution prompt firing, OR periodically to cluster\u002Fresolve the accumulated backlog (see its \"Periodic Debt Health\" section). |\n| `references\u002Fconvergence-report.md` | Step 6–7 detail — census bookkeeping, example report card, source-repo steps, cross-surface clause, RUN_ID history. | Step 6 — printing a report with a non-`completed` row, OR Step 7 — `RUN_ID` is empty or `FINAL_REVIEW_SHADOW` is set. |\n| `references\u002Fgemini-gate.md` | Step 7 Gemini independent review protocol — transcript, verdict handling, re-review loop. | Step 7 starting, OR Gemini returned CONCERNS\u002FREJECT and need deliberation rules. |\n| `references\u002Fround-cap-and-structural-card.md` | Enforced GPT round cap (plan 3\u002F5, code 6\u002F8), exit 4 CAPPED, and the structural-or-stop card read at the cap. | A round exited 4, OR the audit reached round 6 without converging. |\n| `references\u002Fprerequisite-ladder.md` | Step 0 prerequisite ladder — absent helper bundle or auditor route, and reporting a run that did not happen. | Step 0 — a prerequisite did not resolve (helper scripts missing, no GPT route), OR about to report a run that degraded or did not happen. |\n| `references\u002Fpivot-rule.md` | Pivot rule - findings recurring in one file or concern for 3 consecutive rounds mean rethink the design, not loop. | Step 3 - same file or concern accepted in 3 consecutive rounds. |\n| `references\u002Fverification-discipline.md` | Verification discipline — pinned citations, figure provenance, two-direction proof, attribution, consumer-side checks. | Step 4.5 — a finding was fixed WITH a new test or guard and it must be proven red-then-green, OR authoring a contract test from a one-off check. ALSO Step 6 — about to emit the convergence report's pass\u002Fwave census, to apply §7's named-state rule. |\n| `examples\u002Fcontract-test-scaffold.md` | Contract-test scaffold — subject probe, negative control, vacuous-pass guard, disposition, retirement. | Step 4.5 — promoting a one-off check into a permanent contract test. |\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 \u002Faudit-code —\n","# Code Audit Loop\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\u002Faudit-code\u002FSKILL.md` in full before continuing — the later steps,\n> including the mandatory final gate, still apply.\n\nMulti-pass code audit with GPT + Gemini final review. Iterates until\nfindings stabilise or max 6 rounds.\n\n**Input**: `$ARGUMENTS` — plan file path (the spec the code is being audited\nagainst). Optional flags: `--scope diff|plan|full`, `--require \u003Cpaths>` (must-read files; any not FULL withholds convergence).\n\n\u003C!-- host-contract: input-acquisition; grammar=path+flags; 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 the conversation. This site is `path+flags`; on empty input, ask which plan to audit and stop — never guess a plan.\nFull contract: `references\u002Finput-acquisition.md`.\n\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---\n\n## Step 0 — Parse Input and Validate\n\nValidate: plan file exists, the helper scripts resolve, and a GPT route is\navailable — `OPENAI_API_KEY` **or** an active Azure profile\n(`AZURE_OPENAI_ENDPOINT`); ask which ROUTE exists, not whether one variable is\nset. Optional: `GEMINI_API_KEY` for Step 7 (falls back to Claude Opus when\nabsent). `AUDIT_DB_URL` for cloud learning (optional).\n\n**If a prerequisite does not resolve, follow `references\u002Fprerequisite-ladder.md`\n— do not proceed as though it did, and do not die mid-flow.** It defines the\nhydrate-then-retry step for absent helper scripts, the labelled adversarial-agent\nsubstitute when the GPT legs have no route, and which of `AUDIT_DEGRADED` \u002F\n`AUDIT_NOT_RUN` to report so a run that did not happen stays distinguishable\nfrom one that passed.\n\nInitialise session ID: `SID=audit-code-$(node -e \"process.stdout.write(Date.now()+'-'+process.pid)\")` — epoch ms plus a PID, so two sessions started in the same second get separate result, stderr and ledger files (a bare `$(date +%s)` gave both the same ones).\n\nKickoff card: `\u002Faudit-code — Starting | Plan: \u003Cpath> | Max 6 rounds | SID: $SID`.\n\n---\n\n## Step 0.5 — Architectural-memory catalogue (--scope=full only)\n\nWhen `--scope=full`, fetch the repo's symbol catalogue from architectural\nmemory (if populated) and inline a \"Symbol catalogue\" section into the\nprompt context — it lets the auditor catch cross-file duplication that\ndiff-scope cannot see.\n\n```bash\n# .audit\u002F is gitignored — a fresh checkout or new linked worktree lacks it, and the redirect fails first.\nmkdir -p .audit\n# 1. Resolve repo identity + active snapshot. Read JSON with node, never jq (not in check-deps).\nnode scripts\u002Fcross-skill.mjs resolve-repo-identity > .audit\u002Frepo-identity.json\nnode scripts\u002Fcross-skill.mjs get-active-refresh-id --repo-uuid \"$(node -p \"require('.\u002F.audit\u002Frepo-identity.json').repoUuid\")\" > .audit\u002Factive-refresh.json\n# 2. Fetch top-N symbols, CARRYING the refresh id forward (ARCH_AUDIT_FULL_TOPN, default 200) — never retype it.\nREFRESH_ID=$(node -p \"require('.\u002F.audit\u002Factive-refresh.json').refreshId\")\nnode scripts\u002Fcross-skill.mjs list-symbols-for-snapshot --json \"{\\\"refreshId\\\":\\\"$REFRESH_ID\\\",\\\"limit\\\":200}\"\n```\n\nFormat the rows as a `## Symbol catalogue (top N by domain)` section\nwith `(domain alphabetical, symbol_name alphabetical)` ordering. Note\ntruncation in the section header if `count == limit`.\n\nStates: `cloud:false` or `refreshId:null` → skip section silently;\n`RPC_ERROR` → skip section, log warning to stderr. Advisory — never fail the run.\n\n---\n\n## Step 1 — Choose Audit Scope\n\nGPT doesn't know what's \"new\" vs pre-existing — it flags everything in\nscope, so choose deliberately:\n\n| Scope mode | When to use | Behaviour |\n|---|---|---|\n| `--scope diff` (**DEFAULT**) | \"audit my recent work\", after implementing a phase | Auto-scopes to changed files with a **dirty-aware base** + unstaged + untracked (see below) |\n| `--scope plan` | Large refactor touching many files; user wants broad view | All files referenced in the plan |\n| `--scope full` | \"audit the entire codebase\" — explicit codebase-wide request | Full repo audit — slowest, catches cross-cutting issues |\n\nDefault is `--scope diff`. Switch only when the user explicitly asks or `git diff` is empty.\n\n**Dirty-aware base**: with no `--base`, the CLI diffs a **dirty** tree against\n`HEAD` (uncommitted work only) and a **clean** one against `HEAD~1` (last\ncommit); it logs `[scope] base resolved to \u003Cref> …`. ⚠ With BOTH committed and\nuncommitted work where the prior commit was already audited (a resumed\nclustered build), pass `--base \u003CclusterStartRef>` (or `--base HEAD`) and scope\nthe Gemini gate's `--diff` to the same range — never rely on the default across\na commit boundary. → `references\u002Fround-recipes.md` §Dirty-aware base — read when\nresuming a clustered\u002Fpartly-audited build.\n\n---\n\n## Step 2 — Run Code Audit\n\n### Round 1\n\n`$SCOPE` is the scope chosen in the table above — `diff` unless the user asked\nfor `plan` or `full`. **Pass it; do not hardcode `diff` here.** This block read\n`--scope diff` literally until 2026-09-06, so a run the user had explicitly asked\nto be `--scope full` executed as a diff audit and reported a clean result over a\nfraction of what was requested — the scope flag this skill's own Usage lines\nadvertise was accepted and then dropped.\n\n```bash\nSCOPE=diff   # or plan \u002F full, per the table above and the user's request\n# PLAN_FILE = the ONE plan path \u002Faudit-code was invoked with, assigned verbatim.\n# Not a glob: an assignment does not expand it, so the CLI would get the pattern itself.\nnode scripts\u002Fopenai-audit.mjs code \"$PLAN_FILE\" --scope \"$SCOPE\" --out .audit\u002F$SID-r1-result.json 2>.audit\u002F$SID-r1-stderr.log\n```\n\n### Round 2+\n\nR2+ mode changes the prompt rubric and enables ledger-driven suppression.\nFull flag contract, smart pass selection, automatic behaviour, and\ntool pre-pass rules: `references\u002Fr2-plus-mode.md`.\n\nDiff base — match R1 (`git status --porcelain` counts UNTRACKED files as dirty;\nnever `git diff --quiet`, which ignores them). Non-empty output → `BASE=HEAD`\n(dirty tree); empty → `BASE=HEAD~1` (clean, last commit). Pass\n`--base`\u002FclusterStartRef instead across an audited commit boundary.\n\n```bash\nBASE=$([ -n \"$(git status --porcelain)\" ] && echo HEAD || echo HEAD~1)\ngit diff --no-textconv --output=.audit\u002F$SID-diff.patch \"$BASE\" -- .\n```\n\nUse `--output`, never a PowerShell `>` (it re-encodes the patch).\n**Include UNTRACKED new files** — `git diff` omits them, so a brand-new file would\nreach the auditor with no `[CHANGED]` annotation. Append each as a new-file diff\nagainst `\u002Fdev\u002Fnull`. **POSIX shell only** (Git Bash on Windows), even on a\nWindows\u002FCopilot host:\n\n```bash\ngit ls-files --others --exclude-standard -z | xargs -0 -r -I{} git diff --no-index --no-color -- \u002Fdev\u002Fnull \"{}\" >> .audit\u002F$SID-diff.patch 2>.audit\u002F$SID-untracked-diff-stderr.log || true\ncat .audit\u002F$SID-untracked-diff-stderr.log   # non-empty = a real failure occurred, not the expected exit\n```\n\n`|| true` absorbs only `git diff --no-index`'s expected exit 1; it writes nothing to\nstderr in that case, so **a non-empty stderr log is a genuine failure — check it\nbefore trusting the patch.** → `references\u002Fround-recipes.md` §untracked-file append\n— read when that log is non-empty.\n\n```bash\n# CHANGED = the exact files you edited this round, comma-separated, no globs:\n# the CLI splits on commas, so a pattern reaches it literally.\nCHANGED=\"scripts\u002Fopenai-audit.mjs,tests\u002Faudit-skill-shell-recipes.test.mjs\"\nFILES=\"$CHANGED\"                            # + any dependent you also want in scope\nPASSES=\"sustainability\"                     # e.g. sustainability,backend — per r2-plus-mode.md\nnode scripts\u002Fopenai-audit.mjs code \"$PLAN_FILE\" --round 2 --ledger .audit\u002F$SID-ledger.json --diff .audit\u002F$SID-diff.patch --changed \"$CHANGED\" --files \"$FILES\" --passes \"$PASSES\" --out .audit\u002F$SID-r2-result.json 2>.audit\u002F$SID-r2-stderr.log\n```\n\n**R2+'s scope is always the diff, not Round 1's `--scope`** — `--files` overrides\n`--scope`, deliberately; do not add `--scope \"$SCOPE\"` to R2+ (it is silently\nignored). → `references\u002Fround-recipes.md` §R2+ scope — read when tempted to widen R2+.\n\n### Automatic waves and rubrics (no flag)\n\n- **Requirements rubric** — when `.requirements\u002Fledger.json` exists every pass gets a\n  `\u003Crequirements_rubric>`. A `[stale]` `[requirements]` stderr line → refresh with\n  `node scripts\u002Frequirements.mjs extract --files \u003C…>` then `reconcile`.\n  → `references\u002Fround-recipes.md` §Requirements rubric — read when that line appears.\n- **Duplication wave (Wave 5)** — a near-duplicate of an indexed symbol becomes a\n  `[Duplication]` finding that **gates convergence like a `quickfix` finding**. JS\u002FTS\n  files only — another language is outside its coverage, never \"clean\". Intentional\n  duplicate → `@duplicate-justification` pragma above the declaration (never under\n  `tests\u002F`, which is not read); a pragma whose target doesn't match raises its own\n  `Orphaned suppression pragma` finding. Opt out with `--passes` omitting\n  `duplication`. → `references\u002Fduplication-wave.md` — read when a `[Duplication]`\n  finding is intentional or a pragma is not honoured.\n\n### Handle results\n\nIf `verdict` is `INCOMPLETE` (passes timed out), offer: re-run with higher\ntimeout, or continue with partial results.\n\nResults card per round: `ROUND N AUDIT — \u003Cverdict> | H:x M:y L:z | Deduped: d | Cost: ~$… | Top: [H1] …`.\n\n---\n\n## Step 3 — Triage (validity × scope × action)\n\n**You are a peer, not a subordinate.** For each finding, record three\northogonal judgements:\n\n| Dimension | Values | Meaning |\n|---|---|---|\n| **validity** | `valid` \u002F `invalid` \u002F `uncertain` | Is the concern real? |\n| **scope** | `in-scope` \u002F `out-of-scope` | Does it cite code this audit targeted? |\n| **action** | `fix-now` \u002F `defer` \u002F `dismiss` \u002F `rebut` | What happens next? |\n\n### Triage rules\n\n- `validity=invalid` → action MUST be `dismiss` or `rebut`\n- `validity=uncertain` → action MUST be `rebut` (GPT deliberation)\n- `validity=valid` + `scope=in-scope` + HIGH\u002FMEDIUM → `fix-now` (unless accepted-permanent debt)\n- `validity=valid` + `scope=out-of-scope` + **load-bearing** → `fix-now` (treat as in-scope — see impact test below)\n- `validity=valid` + `scope=out-of-scope` + **independent** → `defer` eligible (pre-existing debt)\n- `validity=valid` + `scope=in-scope` + LOW → operator choice\n- Only `validity=valid` findings can be deferred\n\n**Scope is decided by impact, not authorship (load-bearing test).** \"My PR\ndidn't touch this line\" is NOT a defer pass. Before any `out-of-scope` finding\nroutes to `defer`, apply the test: *does the correctness or stability of the\nchange I'm shipping depend on the cited code path?*\n\n- **Load-bearing** — the new code calls into, reads state from, or otherwise\n  rides on the cited path → it is in-scope **for the fix\u002Fdefer decision** even\n  if pre-existing. `fix-now`, or explicitly gate the feature on it and say so.\n  **Never silent-defer a load-bearing finding.**\n- **Independent** — the path fails identically with or without this change; the\n  new code does not depend on it → genuine `defer` (pre-existing debt).\n\nA pre-existing finding **in a file you changed** is a yellow flag, not a green\none: you usually touched the file *because* your change now rides on its\nbehaviour. Default such findings to \"prove independence\" rather than to defer.\nPassing tests don't clear this — a green suite only covers exercised paths, not\nthe load-bearing path's failure modes.\n\n**Same-file independence needs more than \"doesn't call it\".** For a finding in a\nfile the diff touches, the independence sentence must truthfully state BOTH (a) the\ncited code shares no column\u002Fconstraint\u002Finvariant with the new code (a shared *table*\nis not enough) and (b) its writes do not run in the SAME transaction instance (a\nshared request\u002Ffile\u002Fsubsystem is not enough). Either unstateable → load-bearing.\n→ `references\u002Ftriage-rubrics.md` §Same-file independence — read when deferring a\nsame-file finding.\n\n**Honest-deferral check.** Every `defer` of a valid finding names (1) the root\ncause, (2) the minimal in-scope fix considered and rejected, (3) the residual risk;\nan out-of-scope `defer` also names the independence (both parts above for same-file).\nCan't write it truthfully → `fix-now`. **Never `defer` because the correct fix is\nmerely larger** — size is not scope, and neither is authorship.\n→ `references\u002Ftriage-rubrics.md` §Honest-deferral check — read when writing a defer.\n\n### Mechanical vs architectural\n\nEach finding has `is_mechanical: true\u002Ffalse` from GPT:\n- **Mechanical**: deterministic fix. Fix immediately, no deliberation.\n- **Architectural**: judgement call. Needs deliberation, resets stability if new.\n\n### Tiered rebuttal (when action=rebut)\n\n| Severity | Deliberation |\n|---|---|\n| HIGH | ALWAYS send to GPT deliberation |\n| MEDIUM | ALWAYS send to GPT deliberation |\n| LOW | Claude decides locally |\n\nOnly send rebuttal if rebut HIGH or MEDIUM findings exist:\n\n```bash\nREBUTTAL_FILE=.claude\u002Ftmp\u002Frebuttal.md   # the rebuttal text you wrote for the disputed finding(s)\nnode scripts\u002Fopenai-audit.mjs rebuttal \"$PLAN_FILE\" \"$REBUTTAL_FILE\" --out .audit\u002F$SID-resolution.json 2>.audit\u002F$SID-rebuttal-stderr.log\n```\n\n### Convergence\n\nQuality threshold: `HIGH == 0 && MEDIUM \u003C= 2 && quickFix == 0`\n\nStability uses `_hash` for exact cross-round matching:\n- New hash not in prior set = genuinely new → resets stability\n- Mechanical-only findings do NOT require stability rounds\n\n| Condition | Action |\n|---|---|\n| Threshold NOT met | Fix → re-audit |\n| Threshold met, new architectural | Fix → re-audit (stability resets) |\n| Threshold met, mechanical only | Fix → re-audit (stability NOT reset) |\n| Summary line ends `— not convergence evidence` (changed lines, an unrecognised file type, or a `--require` subject not read in full) | **Not stable, whatever H\u002FM\u002FL say** — the change was not read (`changed-lines-unread` \u002F `unrecognised-files-unreviewed` \u002F `required-subjects-not-full`). Re-run short files with `--files`; too big alone → report not converged. Unrecognised type: `.auditignore` it or report upstream. Required subject: fix the read, never `.auditignore` it |\n| Threshold met, 0 new, 2\u002F2 stable | **CONVERGED** → Step 6, then REQUIRED Step 7 |\n| Same file\u002Fconcern recurs 3 rounds running | **Pivot**: stop, propose a new design (`references\u002Fpivot-rule.md`) |\n| Round 6, not stable | Run the structural-or-stop card, present it to the operator, then REQUIRED Step 7 |\n\n**Max 6 rounds for code audits, 8 absolute — enforced by `openai-audit.mjs`.** Round 7 exits `4` (`CAPPED`) with\na structural-or-stop card: a stop for a human call, never a retry. At round 6 without convergence run\n`node scripts\u002Faudit-structural-card.mjs --sid \"$SID\" --mode code --plan \"$PLAN_FILE\"` and present the card to the\noperator (STOP \u002F STRUCTURAL \u002F CONTINUE); continuing is their call (`references\u002Fround-cap-and-structural-card.md`).\n\n**Step 7 (Gemini final review) is MANDATORY** after the last audit round,\nregardless of convergence. No-key degradation ladder (`references\u002Fgemini-gate.md`\n— never a silent skip): Gemini → Claude Opus fallback → an **independent\nadversarial review agent** over the code + findings (verdict in the same\nAPPROVE\u002FCONCERNS\u002FREJECT shape) → only when none is available, output\n`FINAL_GATE_SKIPPED` and do not claim full final-gate validation.\n\n---\n\n### Step 3.7 — Detector-first census (cross-cutting findings)\n\n**An audit's instance count is a floor, not a scope** — the *tool* enumerates, not you.\n**Trigger is mechanical**: `affectedFiles.length > 1` (or an explicit `crossCutting: true`\nyou set at triage); single-file findings are exempt. For each cross-cutting finding,\nrecord a **structured** `detector` (`kind`, `pattern`, `globs`, `baseline`,\n`disposition`) on its ledger entry — never a shell command. Dispositions key on\n`\u003Cpath>::\u003Ctrimmed matched line>`, never a line number. **The detector's output IS the\nfix scope** — fix or disposition everything it finds, not only the instances the audit\nnamed. → `references\u002Fdetector-census.md` §Step 3.7 — read when recording a detector\n(schema + key format).\n\n## Step 3.5 — Update Adjudication Ledger\n\nAfter each deliberation round, write ledger entries for every finding before\nproceeding to Step 4. The ledger drives R2+ rulings injection and post-output\nsuppression.\n\nFull writer invocation example + status field semantics: `references\u002Fledger-format.md`.\n\n**Dismissing a finding that carries `_priorRuling`** (kept beside an earlier\nruling, named with its category) needs a concern decision in its triage entry:\nsame concern reworded → `\"sameConcernAs\": \"\u003Cits topicId>\"`; a different defect\nin the same file → `\"newConcern\": true`.\n`write-ledger-entries` refuses a batch with an undecided one (exit 2).\nThree linked dismissals hard-suppress the next raise. See `references\u002Fledger-format.md`.\n\n---\n\n## Step 3.5b — Record Triage Outcomes (closes the adaptive-learning loop)\n\n**Automatic — no manual step.** `write-ledger-entries.mjs` labels the round it just\ntriaged (once every finding has a ruling), and each R2+ `openai-audit.mjs` invocation\nre-checks the prior round idempotently, so the **final** round is labelled too. It\nbridges the ledger → `finding_adjudication_events` + `audit_pass_stats` +\n`audit_findings` + `audit_runs.labeled` (cloud) and `.audit\u002Foutcomes.jsonl` (local\nbandit reward). Best-effort: a failure logs `[finalize] WARN` and the audit proceeds.\n\n**Manual fallback — only if that WARN appeared**, or on **non-Claude-Code \u002F cloud-off\nCI** where the orchestrator path didn't fire (inside `\u002Fcycle` it is fully covered):\n\n```bash\nROUND=2   # the round number just completed\nnode scripts\u002Fwrite-code-outcomes.mjs --result \".audit\u002F$SID-r$ROUND-result.json\" --ledger .audit\u002F$SID-ledger.json --round \"$ROUND\"\n```\n\nBoth paths share `finalizeRoundOutcomes`, so they are idempotent (cloud re-labels; the\nlocal append is marker-guarded). The ledger must already carry per-finding rulings\n(Step 3.5): **`labelled: 0` with a non-zero `total` is a failure to fix, never a pass.**\n\n---\n\n## Step 3.6 — Debt Capture\n\nPersist out-of-scope valid findings to `.audit\u002Ftech-debt.json` so future\naudits suppress them automatically. Eligible candidates: Step 3 triage\nfindings with `action = defer`.\n\n> **A rejected capture is a lost suppression.** An over-cap rationale is rejected and the run exits non-zero: any deferral that fails to land is never suppressed in a future audit — so `9 of 15 captured` is a failure, not a ship.\n> Read the `Rejected entries:` listing, fix what it names, then re-run (capture is idempotent). Do not shorten a rationale to fit the 4000-char limit — the Step 3 honest-deferral requirement above (root cause + rejected minimal fix + residual risk + independence) is the point, and the limit is sized to it.\n\nFull per-reason field requirements, capture flow, sensitivity-scan rules,\nand status card format: `references\u002Fdebt-capture.md`.\n\n---\n\n## Execution order — critical\n\n**Wait for rebuttal BEFORE fixing.**\n\n1. Send rebuttal (if rebut HIGH\u002FMEDIUM findings from triage)\n2. Wait for rebuttal response\n3. Write adjudication ledger (Step 3.5)\n4. Record triage outcomes — automatic next-round (Step 3.5b); manual CLI only for the final\u002F1-round case\n5. Capture deferrable debt (Step 3.6)\n6. Fix ALL findings together (Step 4)\n7. Run tests\n8. Verification audit (Step 5) — debt suppression runs automatically\n\n---\n\n## Step 4 — Fix Findings\n\nALL HIGH must be fixed. MEDIUM until ≤2 remain. LOW if mechanical.\n\n> **Read `finding.verification` before you triage on `finding.severity`.**\n> The deterministic existence gate resolves every \"file\u002Fmodule X is missing\"\n> claim against the real repo inventory and attaches a sibling `verification`\n> object. `finding.severity` is the model's ORIGINAL claim and is deliberately\n> never rewritten — so a **`verification.verification === 'refuted'`** finding\n> still reads `HIGH` in `findings[]` while the audit verdict has already\n> discounted it to `verdictSeverity: 'LOW'`.\n>\n> - `refuted` — **do not fix.** The cited file exists; the claim is a\n>   `--scope diff` context artefact. Fixing it means editing a file that was\n>   never missing. The stderr log names these: `[verify-gate] … REFUTED`.\n> - `confirmed` \u002F `requires_verification` — triage normally at `severity`.\n>   A `requires_verification` on a list claim may say \"N of M cited path(s) DO\n>   exist\" — the claim is partly false; verify the rest before acting.\n>\n> Triage on `effectiveSeverity(finding)` from\n> [`finding-verification.mjs`](https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fscripts\u002Flib\u002Faudit\u002Ffinding-verification.mjs),\n> never on a hand-rolled copy of the rule.\n\n**Track which files you modify** — you'll need this for `--changed` in Step 5.\nCard: `FIXING — N findings | Auto-fixed (mechanical): a | Per recommendation: b | Compromises: c | Skipped (LOW): d | Files modified: …`;\nthen list each fix: `[ID] description → file:lines`.\n\nAfter fixing, update ledger entries to `remediationState: 'fixed'` for\nfixed items.\n\n### Step 4.5 — Prove every new guard in BOTH directions\n\nFor each finding fixed **with a new test, assertion or contract**: a green suite\ndoes not distinguish \"the fix worked\" from \"the check stopped looking\". Only\nrevert-and-watch-it-go-red does, and it costs seconds.\n\n1. Revert the fix (the fix only — not the test).\n2. Run → **confirm RED**, and read the failure text: it must name the actual\n   defect, not fail for an unrelated reason.\n3. Where the fix closes **independent** failure modes, revert them **one at a\n   time**. Two defects on one line mask each other — that is how a container\n   health check shipped broken for months, each bug making the other invisible.\n4. Restore → confirm GREEN. Record that you ran it, and what the red said.\n\nA before\u002Fafter observation of a pre-existing defect is **not** a negative control.\nAn \"expect empty\" assertion needs a vacuous-pass guard (one assertion proving the\nprobe can find something it must find). When the check itself fails, suspect the\ninstrument first. A guard worth keeping past this session gets the\n`examples\u002Fcontract-test-scaffold.md` skeleton (disposition + retirement fields).\n→ `references\u002Fverification-discipline.md` §3, §5.\n\n---\n\n## Step 5 — Verify and Loop (R2+ Mode)\n\nAfter fixes, re-audit using R2+ mode (back to Step 2):\n\n1. Collect files modified during Step 4 → `--changed`\n2. Compute scope: changed + importers → `--files`\n3. Regenerate the diff with Step 2's Round 2+ recipe exactly — dirty-aware `BASE`,\n   the untracked-file append, and the stderr-log check\n4. Build `--passes` from file types\n5. Run R2+ audit with `--round \u003CN> --ledger --diff --changed --files`\n\nTrack finding churn using `_hash` fields: resolved \u002F recurring \u002F new.\nCard: `ROUND N → ROUND N+1 (R2+ mode) | H:x M:y L:z | New: n | Suppressed: s | Stable: k\u002F2`.\n\n### Step 5.0b — Re-run every detector at FULL scope (blocks convergence)\n\n```bash\nnode scripts\u002Flib\u002Faudit\u002Fdetector.mjs .audit\u002F$SID-ledger.json\n```\n\nExit 0 = every detector reached zero and every match is dispositioned; exit 1 =\nblocked; exit 2 = the ledger could not be read, which is \"no census happened\"\nand never a pass.\n\n**At each detector's own `globs`, NOT the round's changed files** — a diff-scoped\nre-run misses both the unfixed class members and any occurrence the fix itself just\nwrote. Convergence requires `blocked === false`; `baseline` reports progress, never\nthe pass condition. A detector that errors here is reported `errored` in Step 6's\ncensus, never folded into \"reached zero\". → `references\u002Fdetector-census.md` §Step 5.0b\n— read when a detector result is disputed.\n\n### Step 5.1 — Debt Resolution Prompt\n\nAfter verification, reopened debt topics with no matching finding this round\nare candidates for resolution. Full prompt + resolver invocation:\n`references\u002Fdebt-capture.md`.\n\n---\n\n## Step 6 — Convergence Report (Pre-Final)\n\n**Named states, per pass\u002Fwave\u002Fcapability, not a bare \"ran\".** Attempted-but-\nfailed is a different thing from never-attempted (`references\u002Fverification-discipline.md`\n§7):\n\n| State | Meaning |\n|---|---|\n| `completed` | finished without error, applicable to the resolved scope — decoupled from finding count: a `completed` pass stays `completed` at 0, 1, or many findings |\n| `errored` | started, did not complete (exception, timeout, non-2xx from a provider) |\n| `ineligible` | does not apply to this repo's resolved language\u002Fscope (e.g. a frontend-specific pass on a backend-only diff) |\n| `unavailable` | a concrete missing prerequisite — e.g. `AUDIT_DB_URL` unset for the architectural-memory catalogue |\n| `not-reached` | the round's control flow did not get to this pass\u002Fwave before stopping (rare — see below) |\n| `uncovered` | **file-level, from the result's `_coverage`, never from a pass:** changed files the audit did not (fully) examine — an unrecognised file type, an unreadable file, a deleted source file, a partial (head-cut or windowed) read. NOT `ineligible`: `ineligible` is an EXPECTED scope exclusion, and labelling a C# diff that way is exactly how twelve `.cs` files went unaudited under an APPROVE |\n\n**Per-round record.** `arch-memory` is resolved once by Step 0.5 and carried into\nevery round's census (`ineligible` under `--scope=diff`). The five passes and three\nmechanical waves are seeded `pending` at each round's start; on an aborted round every\nuntouched row finalizes `not-reached` (never left `pending`) — it signals a killed\nprocess or hard timeout. Render the current round's rows plus `arch-memory`.\n→ `references\u002Fconvergence-report.md` §per-round execution record — read when a row's\nstate is ambiguous.\n\nReport card: `CONVERGED[ (\u003Ccount> \u003Ckind> · … — see census)] — Round N | Final: H:x M:y L:z | Rounds | Time | Cost | Files changed | Remaining (accepted): [Mn]…`,\nthen a `CENSUS` block — one `\u003Cidentifier>  \u003Cstate>  (\u003Creason>)` row per pass, wave,\n`arch-memory` and `file coverage`. → `references\u002Fconvergence-report.md` §example\nreport card — read before printing a report with a non-`completed` row.\n\n**A wave row over a change it could not read says so.** The four JS\u002FTS-only waves (`orphan-introduced`, `event-wiring-symmetry`,\n`duplication`, `adjacency`) report `ineligible (0 of N changed files are js\u002Fts; nothing was examined)` — never `completed`,\n`ANALYZED_CLEAN`, `clean` or `not-triggered` — when none of the changed files is one they can read; a partial one adds\n`examined k of n`. The tool pre-pass likewise names each project's state (`ok` \u002F `failed` \u002F `timeout` \u002F `deadline_exceeded` \u002F\n`ambiguous_project` \u002F `no_project` \u002F `skipped_budget` \u002F `no_tool`) in `_coverage.tools`; none of them is a clean lint.\n\nIdentifiers are the real ones — `structure`\u002F`wiring`\u002F`backend`\u002F`frontend`\u002F\n`sustainability` (`scripts\u002Flib\u002Fprompt-seeds.mjs`), `quickfix`\u002F`duplication`\u002F\n`adjacency` (`scripts\u002Flib\u002Faudit-shadow.mjs`'s `MECHANICAL_WAVES`) — not\ninvented labels. Every non-`completed` row carries a concrete reason in parentheses.\n\n**The `file coverage` row is rendered from the round's `_coverage` (`node -p` the result JSON; its `status`, `gate` and the\none-line suffix the summary already printed).** `complete` → `completed`; `partial` → `uncovered` with the suffix as its\nreason; `none`\u002F`incomplete` → the round is already `INCOMPLETE` (exit 3) and must not be reported as converged at all.\nCopy the suffix, never paraphrase it: it names the files.\n\n**A round with any non-`completed` row cannot print a bare `CONVERGED`.**\nThe suffix names **every kind present, with its own count** — never hardcode one\nkind; a round with only `ineligible` rows names them `ineligible`, never \"errored\".\n\nSave convergence snapshot to `docs\u002Fplans\u002F\u003Cname>-audit-summary.md`.\n\nDo not close the loop in Step 6 — completion requires Step 7.\n\n### Step 6.5 — Regenerate Telemetry Dashboard (advisory, source-repo only)\n\n**Source-repo-gated** — run ONLY when\n`package.json.name === \"claude-engineering-skills\"`; skip silently elsewhere. Never\nblocks the audit. Print the `file:\u002F\u002F…\u002Fdashboard\u002Ftelemetry.html` link; never stage it.\n\n```bash\nnode scripts\u002Fbuild-dashboard.mjs telemetry 2>&1 || true\n```\n\n→ `references\u002Fconvergence-report.md` §Step 6.5 — read when running it in a consumer.\n\n### Step 6.5b — Solo author-model control (background, toggle-gated)\n\n**Source-repo-gated** — run ONLY when `package.json.name === \"claude-engineering-skills\"`\n(skip silently in consumers). Fire it **in the background, non-blocking** (it takes\nminutes; it must NEVER delay or gate the audit result). It self-gates on the\n`arm-eval` shadow toggle and is incremental, so firing it unconditionally is safe;\na failure is logged and ignored.\n\n```bash\nnode scripts\u002Fsolo-control-audit.mjs run --model claude-sonnet-5\nnode scripts\u002Fsolo-control-audit.mjs run --model claude-fable-5\n# run each backgrounded \u002F in its own terminal — they're independent, not chained\n```\n\n→ `references\u002Fconvergence-report.md` §Step 6.5b — read when asked why it runs.\n\n### Step 6.6 — Recommended next (à-la-carte advisor)\n\nSuggest the FEW additional lenses that fit THIS change, grounded in the final-round\naudit result:\n\n```bash\nFINAL_ROUND=2   # the last round actually run\nnode scripts\u002Fcross-skill.mjs recommend-skills --findings \".audit\u002F$SID-r$FINAL_ROUND-result.json\" --just-ran audit-code --format human\n```\n\nPrint the card verbatim if non-empty; **if it's empty, say nothing** (silence is\ncorrect, not a failure). A nudge, never a gate. → `references\u002Fconvergence-report.md`\n§Step 6.6 — read when explaining a recommendation.\n\n### Step 6.7 — Cross-surface honesty clause (GREEN ≠ REALIZED)\n\nWhen the change introduces a user-visible DYNAMIC value that duplicates or re-derives\none another surface shows (or a `derived-state-parity` finding was raised), a green\naudit does not prove they agree at runtime: do not close it on \"looks correct\" —\nrequire a shared SSoT, a parity assertion, or a declared `data-engine-claim` surface.\n→ `references\u002Fconvergence-report.md` §Step 6.7 — read when that pattern appears.\n\n---\n\n## Step 7 — Gemini Independent Review (MANDATORY)\n\n> **Coverage rides into the review automatically.** The transcript builder projects each round's `_coverage` (every file\n> short of full coverage, capped, plus a digest of the full ledger), and the review envelope opens with an **Audit Coverage**\n> note naming what was NOT examined. Do not summarise it away in `--summary`; if the note is present the reviewer was told,\n> and an APPROVE over it is an APPROVE of the examined files only. A coverage gap is not itself release-blocking.\n\nRun the final reviewer — the newest Gemini Pro by default (`latest-pro`, resolved at runtime; override with `FINAL_REVIEW_MODEL`) as the final gate. Falls back to Claude Opus when\n`GEMINI_API_KEY` is absent.\n\n**Build the transcript first** — the reviewer reads a file no earlier step\nwrites. Never hand-assemble the JSON:\n\n```bash\nnode scripts\u002Fbuild-audit-transcript.mjs --sid $SID --changed \"$CHANGED\"\n```\n\nIt discovers every `.audit\u002F$SID-r\u003CN>-result.json`, folds in\n`.audit\u002F$SID-ledger.json` as the deliberation trail, and writes\n`.audit\u002F$SID-transcript.json`. **`--changed` is the reviewer's scope filter** —\npass the same list you gave the R1 audit; without it out-of-scope findings stop\nbeing dropped and the builder warns on stderr.\n\nRead the cloud run id from the LAST round's result, passing the path as an argument\n(never a literal inside `-e`) — **`--run-id` arms the verdict write-back to\n`audit_runs`; without it the verdict is persisted nowhere:**\n\n```bash\nROUND=2   # the last round actually run\nRUN_ID=$(node -e \"const fs=require('fs'); try { process.stdout.write(JSON.parse(fs.readFileSync(process.argv[1],'utf8'))._cloudRunId||''); } catch { process.stdout.write(''); }\" \".audit\u002F$SID-r$ROUND-result.json\")\n```\n\nIf `gemini-review.mjs` warns that cloud is on but `--run-id` is absent, the extraction\nfailed — don't ignore it. → `references\u002Fconvergence-report.md` §Step 7 RUN_ID — read\nwhen `RUN_ID` is unexpectedly empty.\n\nIf `RUN_ID` is non-empty:\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript.json --out .audit\u002F$SID-gemini-result.json --run-id \"$RUN_ID\" 2>.audit\u002F$SID-gemini-stderr.log\n```\n\nOtherwise (cloud genuinely off — `RUN_ID` empty):\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript.json --out .audit\u002F$SID-gemini-result.json 2>.audit\u002F$SID-gemini-stderr.log\n```\n\nAdd `--round 1` to the first run. **Hard cap: 2 final-review rounds** —\n`gemini-review.mjs` refuses `--round 3`; never loop past it.\n\n**Act on `gateDisposition`, not the verdict word.** The result JSON (and the\nstdout summary `Gate: …`) carries a code-computed `gateDisposition`; `verdict`\nstays the reviewer's own word:\n\n| `gateDisposition` | Action |\n|---|---|\n| `approve` | Done → final report. |\n| `approve_with_debt` | Done — also for `CONCERNS`\u002F`CONCERNS_REMAINING`. Every remaining finding is `release_blocking: false`: capture them (below), list them in the report. Do **not** re-run the reviewer and do **not** ask the user to override. |\n| `blocked` | `gateDispositionDetail.reasons` names why (a release-blocking finding, a HIGH `wrongly_dismissed`, `REJECT`, or coverage gate). Round 1 → Step 7.1: fix the blocking items, rebuild the transcript, run round 2. Round 2 → present the named blocking items to the user; there is no round 3. |\n\nRound 2 takes the round-1 result as structured memory — its findings are\nsettled, and a re-raise is dropped in code unless marked `is_reopened`:\n\n```bash\nnode scripts\u002Fgemini-review.mjs review \"$PLAN_FILE\" .audit\u002F$SID-transcript-v2.json --round 2 --prior .audit\u002F$SID-gemini-result.json --out .audit\u002F$SID-gemini-result-v2.json 2>.audit\u002F$SID-gemini-stderr-v2.log\n```\n\nCapture non-blocking findings as debt from the result that closed the gate\n(`-v2` after round 2; release-blocking ones are never captured; `--dry-run`\npreviews):\n\n```bash\nnode scripts\u002Fdebt-auto-capture.mjs --final-review .audit\u002F$SID-gemini-result.json --run $SID\n```\n\nOptional observation-only shadow reviewer (`FINAL_REVIEW_SHADOW`) — never gates.\n→ `references\u002Fconvergence-report.md` §shadow A\u002FB reviewer — read when it is set.\n\nFull transcript-building, verdict routing, Step 7.1 deliberation protocol,\nand category-error handling: `references\u002Fgemini-gate.md`.\n\n---\n\n## UX Rules\n\n1. Status card after every phase (compact format above)\n2. Never dump raw JSON — parse and summarise\n3. Show every fix with file + line reference\n4. Cost tracking: `cost ≈ (input × 2.5 + output × 10) \u002F 1M`\n5. Batch all user decisions into one prompt\n6. Progress: show pass timings from stderr\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\u002Fround-recipes.md` | Step 1–2 detail — dirty-aware base rationale, diff-recipe stderr handling, R2+ scope rule, requirements rubric. | Resuming a partly-audited clustered build, OR the untracked-diff stderr log is non-empty, OR a `[stale]` requirements line appeared. |\n| `references\u002Fduplication-wave.md` | Duplication wave (Wave 5) — what it scans, the @duplicate-justification pragma, test-dir and orphan rules. | A `[Duplication]` finding is intentional, OR a pragma is not being honoured. |\n| `references\u002Fr2-plus-mode.md` | R2+ audit mode — ledger rulings, diff annotations, smart pass selection, suppression. | Round ≥ 2 AND need to choose passes OR troubleshoot suppression. |\n| `references\u002Ftriage-rubrics.md` | Step 3 rubrics in full — same-file independence (column\u002Fconstraint + transaction) and the honest-deferral check. | Step 3 — about to defer a finding, especially one in a file the diff touches. |\n| `references\u002Fdetector-census.md` | Detector-first census — the ledger detector schema, disposition keys, and why Step 5.0b re-runs at full scope. | Step 3.7 — a finding spans more than one file, OR Step 5.0b — a detector result is disputed. |\n| `references\u002Fledger-format.md` | Adjudication ledger schema + writer invocation example for each finding outcome. | Step 3.5 — about to write ledger entries, OR diagnosing R2+ suppression misbehaviour. |\n| `references\u002Fdebt-capture.md` | Phase D debt ledger — persist out-of-scope valid findings so they don't re-surface. | Step 3.6 — candidate deferrals present, OR Step 5.1 — debt resolution prompt firing, OR periodically to cluster\u002Fresolve the accumulated backlog (see its \"Periodic Debt Health\" section). |\n| `references\u002Fconvergence-report.md` | Step 6–7 detail — census bookkeeping, example report card, source-repo steps, cross-surface clause, RUN_ID history. | Step 6 — printing a report with a non-`completed` row, OR Step 7 — `RUN_ID` is empty or `FINAL_REVIEW_SHADOW` is set. |\n| `references\u002Fgemini-gate.md` | Step 7 Gemini independent review protocol — transcript, verdict handling, re-review loop. | Step 7 starting, OR Gemini returned CONCERNS\u002FREJECT and need deliberation rules. |\n| `references\u002Fround-cap-and-structural-card.md` | Enforced GPT round cap (plan 3\u002F5, code 6\u002F8), exit 4 CAPPED, and the structural-or-stop card read at the cap. | A round exited 4, OR the audit reached round 6 without converging. |\n| `references\u002Fprerequisite-ladder.md` | Step 0 prerequisite ladder — absent helper bundle or auditor route, and reporting a run that did not happen. | Step 0 — a prerequisite did not resolve (helper scripts missing, no GPT route), OR about to report a run that degraded or did not happen. |\n| `references\u002Fpivot-rule.md` | Pivot rule - findings recurring in one file or concern for 3 consecutive rounds mean rethink the design, not loop. | Step 3 - same file or concern accepted in 3 consecutive rounds. |\n| `references\u002Fverification-discipline.md` | Verification discipline — pinned citations, figure provenance, two-direction proof, attribution, consumer-side checks. | Step 4.5 — a finding was fixed WITH a new test or guard and it must be proven red-then-green, OR authoring a contract test from a one-off check. ALSO Step 6 — about to emit the convergence report's pass\u002Fwave census, to apply §7's named-state rule. |\n| `examples\u002Fcontract-test-scaffold.md` | Contract-test scaffold — subject probe, negative control, vacuous-pass guard, disposition, retirement. | Step 4.5 — promoting a one-off check into a permanent contract test. |\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 \u002Faudit-code —\n",{"name":5,"description":7},"main","938efbef34b7c76f0d112f336d1ac4018224d186",".claude\u002Fskills\u002Faudit-code","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":71,"prompt":81,"zipAvailable":82},[72,75,78],{"tool":73,"command":74},"npx","npx skills add Lbstrydom\u002Fclaude-engineering-skills --skill audit-code",{"tool":76,"command":77},"bunx","bunx skills add Lbstrydom\u002Fclaude-engineering-skills --skill audit-code",{"tool":79,"command":80},"pnpm","pnpm dlx skills add Lbstrydom\u002Fclaude-engineering-skills --skill audit-code","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002FSKILL.md",true,[84,90,94,98,102,106,110,114,118,122,126,130,134,138,142,146],{"path":85,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":88,"sourceHtmlUrl":89},"examples\u002Fcontract-test-scaffold.md","REFERENCE","参考文档",4932,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Fexamples\u002Fcontract-test-scaffold.md",{"path":91,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":92,"sourceHtmlUrl":93},"references\u002Fconvergence-report.md",8502,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fconvergence-report.md",{"path":95,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":96,"sourceHtmlUrl":97},"references\u002Fdebt-capture.md",12829,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fdebt-capture.md",{"path":99,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":100,"sourceHtmlUrl":101},"references\u002Fdetector-census.md",3190,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fdetector-census.md",{"path":103,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":104,"sourceHtmlUrl":105},"references\u002Fduplication-wave.md",2670,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fduplication-wave.md",{"path":107,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":108,"sourceHtmlUrl":109},"references\u002Fgemini-gate.md",18929,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fgemini-gate.md",{"path":111,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":112,"sourceHtmlUrl":113},"references\u002Finput-acquisition.md",4511,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Finput-acquisition.md",{"path":115,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":116,"sourceHtmlUrl":117},"references\u002Fledger-format.md",9788,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fledger-format.md",{"path":119,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":120,"sourceHtmlUrl":121},"references\u002Fpivot-rule.md",2671,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fpivot-rule.md",{"path":123,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":124,"sourceHtmlUrl":125},"references\u002Fprerequisite-ladder.md",6277,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fprerequisite-ladder.md",{"path":127,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":128,"sourceHtmlUrl":129},"references\u002Fr2-plus-mode.md",5890,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fr2-plus-mode.md",{"path":131,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":132,"sourceHtmlUrl":133},"references\u002Fround-cap-and-structural-card.md",5400,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fround-cap-and-structural-card.md",{"path":135,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":136,"sourceHtmlUrl":137},"references\u002Fround-recipes.md",3905,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fround-recipes.md",{"path":139,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":140,"sourceHtmlUrl":141},"references\u002Ftriage-rubrics.md",3235,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Ftriage-rubrics.md",{"path":143,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":144,"sourceHtmlUrl":145},"references\u002Fverification-discipline.md",28260,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fverification-discipline.md",{"path":147,"resourceType":86,"resourceTypeDesc":87,"sizeBytes":148,"sourceHtmlUrl":149},"references\u002Fworktree-preflight.md",3413,"https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Faudit-code\u002Freferences\u002Fworktree-preflight.md",[151,167,178,195,208,242],{"skillNo":152,"name":153,"nameZh":6,"description":154,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":155,"categories":156,"keywords":160,"publishedAt":58},"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",[157],{"categoryNo":158,"categoryName":159,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000037","律师与法务",[161,162,163,164,165,166],"stated absent","STRING","contract","fixture","never","file",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":174,"publishedAt":58},"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",[173],{"categoryNo":158,"categoryName":159,"taxonomyType":26,"taxonomyTypeDesc":27},[175,176,177,163,164,166],"implementation","nonexistent implementation","references",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":187,"publishedAt":58},"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",[184],{"categoryNo":185,"categoryName":186,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",[48,188,189,190,191,192,193,194,164],"document","with","document only with params","check","schema","gate","pattern",{"skillNo":196,"name":197,"nameZh":6,"description":198,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":199,"categories":200,"keywords":204,"publishedAt":58},"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",[201],{"categoryNo":202,"categoryName":203,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[205,191,193,206,207,164,37],"lying skill","fixture skill","self",{"skillNo":209,"name":210,"nameZh":6,"description":211,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":212,"categories":213,"keywords":223,"publishedAt":58},"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",[214,217,220],{"categoryNo":215,"categoryName":216,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":218,"categoryName":219,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":221,"categoryName":222,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师",[224,225,30,226,227,228,229,230,231,232,233,234,165,48,235,236,237,238,239,240,241],"visual audit","visual","mode","design token","click","inspection","lens","design","ci","persona","math","cdp","journey","drift","focus","physics","layout","card",{"skillNo":243,"name":244,"nameZh":6,"description":245,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":246,"categories":247,"keywords":252,"publishedAt":58},"01M6J4569S40ZASFWW698CHBKP","ux-lock","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.","https:\u002F\u002Fgithub.com\u002FLbstrydom\u002Fclaude-engineering-skills\u002Fblob\u002Fmain\u002Fskills\u002Fux-lock\u002FSKILL.md",[248,249,250,251],{"categoryNo":215,"categoryName":216,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":221,"categoryName":222,"taxonomyType":26,"taxonomyTypeDesc":27},{"categoryNo":158,"categoryName":159,"taxonomyType":26,"taxonomyTypeDesc":27},[253,254,255,226,256,257,258,30,52,259,260,261,262,263,264,32,265,266,267,268,46],"ux lock","lock","ux","commit","generate","acceptance","regression","syntax","command","write","fix","e2e test","app","judge","URL","verify plan"]