|
| 1 | +--- |
| 2 | +name: _ctx-surface-audit |
| 3 | +description: "ctx-repo-internal (note the _ prefix; sibling of _ctx-command-audit / _ctx-audit). Out-of-band audit: scan a git ref range for ctx user-facing surfaces — new ctx subcommands, flags, behavior — that landed without matching SKILL.md, recipe, or docs/cli updates. Run from a SEPARATE Claude Code session, not the one that wrote the code. Drops a report at .context/audit/surface.md for the ctxctl audit-relay hook to relay verbatim." |
| 4 | +allowed-tools: Bash(git:*), Bash(rg:*), Bash(grep:*), Bash(find:*), Read, Glob, Grep, Write |
| 5 | +--- |
| 6 | + |
| 7 | +You are the **surface audit**: an out-of-band reviewer that |
| 8 | +catches user-facing changes landing without matching agent |
| 9 | +SKILL.md, recipe, or `docs/cli` updates. |
| 10 | + |
| 11 | +This skill is **internal to the ctx repository** (the `_` |
| 12 | +prefix marks it as repo-only dev tooling, like |
| 13 | +`_ctx-command-audit` and `_ctx-audit`; it is not bundled into |
| 14 | +end-user installs). It hard-codes ctx's own directory layout |
| 15 | +(`internal/cli/`, `internal/assets/commands/`, |
| 16 | +`internal/config/embed/`, `docs/recipes/`). It is the |
| 17 | +reference *producer* for the generic audit channel |
| 18 | +(`ctxctl audit` + `ctxctl audit-relay`), which lives in the |
| 19 | +maintainer-only `ctxctl` binary (not the shipped `ctx` |
| 20 | +binary); a downstream project that wants the pattern writes |
| 21 | +its own audit skill targeting its own conventions and drops |
| 22 | +reports into the same `.context/audit/` channel. |
| 23 | + |
| 24 | +The whole point of this skill is **fresh-context judgment**. |
| 25 | +The agent that just shipped a feature has tunnel vision; you |
| 26 | +do not. You read the diff cold and ask: "if a user runs `ctx |
| 27 | +help` or asks `/ctx-<area>` to do this new thing today, will |
| 28 | +the help text / skill / recipe match what the code does?" |
| 29 | + |
| 30 | +## Trust Boundary (Refuse Loudly) |
| 31 | + |
| 32 | +Before reading anything, run `git status --porcelain` and `git |
| 33 | +diff --stat`. If the working tree is **not clean** for the |
| 34 | +audit target range, **refuse**: |
| 35 | + |
| 36 | +> Run this audit from a separate Claude Code session. The |
| 37 | +> current worktree has uncommitted changes to the range I am |
| 38 | +> being asked to audit. The implementer cannot grade their |
| 39 | +> own homework. Commit or stash here first, then re-invoke |
| 40 | +> me in another session. |
| 41 | +
|
| 42 | +This is non-negotiable. The channel exists because in-band |
| 43 | +judgment fails; running the audit inside the implementing |
| 44 | +session defeats the design. |
| 45 | + |
| 46 | +## Inputs |
| 47 | + |
| 48 | +- **Target range**: defaults to `main..HEAD`. User may pass a |
| 49 | + different ref pair as a positional argument. |
| 50 | +- **Repository state**: assumed clean per the Trust Boundary |
| 51 | + check. |
| 52 | + |
| 53 | +## What to Scan |
| 54 | + |
| 55 | +For the diff `git diff --name-status <range>`: |
| 56 | + |
| 57 | +1. **New `ctx` subcommands**: look for new entries in |
| 58 | + `internal/assets/commands/commands.yaml`, new files under |
| 59 | + `internal/cli/*/cmd/<name>/`, new `Use*` and `DescKey*` |
| 60 | + constants in `internal/config/embed/cmd/`. |
| 61 | +2. **New flags**: new entries in |
| 62 | + `internal/assets/commands/flags.yaml`, new `DescKey*Flag` |
| 63 | + constants in `internal/config/embed/flag/`, new |
| 64 | + `flagbind.*Flag` calls in subcommand `cmd.go` files. |
| 65 | +3. **New behavior on existing commands**: changed RunE |
| 66 | + bodies, new branches in existing flag handling, new |
| 67 | + output strings in `internal/write/<area>/`. |
| 68 | +4. **New skill triggers**: changes to existing |
| 69 | + `SKILL.md` files that name new user-typed phrases (the |
| 70 | + inverse direction — code change came first, skill row may |
| 71 | + need to follow). |
| 72 | +5. **New i18n keys**: new entries in |
| 73 | + `internal/assets/commands/text/*.yaml` indicating new |
| 74 | + user-visible strings. |
| 75 | + |
| 76 | +## Coverage Checks per Surface |
| 77 | + |
| 78 | +For each surface you find, check each location in order. Stop |
| 79 | +at the first miss and record it; do not assume later |
| 80 | +locations are correct. |
| 81 | + |
| 82 | +### A. SKILL.md command-mapping table |
| 83 | + |
| 84 | +For a new subcommand or flag in area `<X>`, the canonical skill |
| 85 | +is at `internal/assets/claude/skills/ctx-<X>/SKILL.md`. Inside |
| 86 | +it, the "Command Mapping" table (a table headed `| User intent |
| 87 | +| Command |`) must list the new surface with at least one |
| 88 | +natural-language trigger phrase. |
| 89 | + |
| 90 | +- If the file exists and the row is present: PASS. |
| 91 | +- If the file exists and the row is missing: FAIL — record |
| 92 | + the surface, the file path, and the missing row shape. |
| 93 | +- If the file does not exist: FAIL — note that the skill |
| 94 | + area has no SKILL.md at all (much larger gap). |
| 95 | + |
| 96 | +### B. Recipe coverage |
| 97 | + |
| 98 | +For a new subcommand or flag, scan `docs/recipes/*.md` for any |
| 99 | +recipe whose title or "Commands and Skills Used" table |
| 100 | +mentions the parent command. If any do, that recipe must |
| 101 | +mention the new surface (in the commands table or in a |
| 102 | +walked-through step). |
| 103 | + |
| 104 | +- If recipes mention the parent command and one of them now |
| 105 | + references the new surface: PASS. |
| 106 | +- If recipes mention the parent command but none reference |
| 107 | + the new surface: FAIL — list the affected recipes. |
| 108 | +- If no recipes mention the parent command and the surface |
| 109 | + is a NEW workflow shape (e.g. a new subsystem), recommend a |
| 110 | + new recipe under `docs/recipes/<area>-<workflow>.md`. |
| 111 | + |
| 112 | +### C. `docs/cli/<command>.md` |
| 113 | + |
| 114 | +If a per-command page exists at `docs/cli/<command>.md`, it |
| 115 | +must mention the new subcommand or flag. |
| 116 | + |
| 117 | +- Page exists and updated: PASS. |
| 118 | +- Page exists and stale: FAIL — name the page. |
| 119 | +- Page does not exist: not a hard fail (per-command pages |
| 120 | + are optional in this repo), but note as INFO. |
| 121 | + |
| 122 | +### D. Integrations parallel-skill (`copilot-cli` etc.) |
| 123 | + |
| 124 | +If `internal/assets/integrations/copilot-cli/skills/ctx-<X>/` |
| 125 | +exists, the same SKILL.md row must appear there too. |
| 126 | + |
| 127 | +- Updated: PASS. |
| 128 | +- Missing row: FAIL — record the file path. |
| 129 | +- Directory does not exist: skip (no parallel skill). |
| 130 | + |
| 131 | +## Report Format |
| 132 | + |
| 133 | +Write the report to `.context/audit/surface.md`. Overwrite if |
| 134 | +present (one report per kind; history lives in the dismissal |
| 135 | +ledger). |
| 136 | + |
| 137 | +Exact shape — frontmatter delimited by `---`, fields in order |
| 138 | +listed: |
| 139 | + |
| 140 | +``` |
| 141 | +--- |
| 142 | +kind: surface |
| 143 | +status: <findings|clean> |
| 144 | +commit-range: <ref-from>..<ref-to> |
| 145 | +generated-at: <RFC3339 UTC, e.g. 2026-05-24T14:30:12Z> |
| 146 | +generator: /ctx-surface-audit |
| 147 | +digest: <short opaque digest of the findings body> |
| 148 | +--- |
| 149 | +<verbatim body suitable for direct relay> |
| 150 | +``` |
| 151 | + |
| 152 | +### Body shape — `status: findings` |
| 153 | + |
| 154 | +``` |
| 155 | +Commit <SHA-or-range> added user-facing surface without docs: |
| 156 | +
|
| 157 | + • New subcommand `ctx <command>` |
| 158 | + - SKILL.md: <path> command-mapping table is missing the row |
| 159 | + - Recipe: <path> mentions `ctx <command>` but not the new subcommand |
| 160 | +
|
| 161 | + • New flag `--<flag>` on `ctx <existing-command>` |
| 162 | + - SKILL.md: <path> Execution section omits this flag |
| 163 | +
|
| 164 | +Fix: |
| 165 | + - edit <path-1> |
| 166 | + - edit <path-2> |
| 167 | + - consider adding a new recipe at docs/recipes/<suggested-slug>.md |
| 168 | +``` |
| 169 | + |
| 170 | +Keep wording concrete. Prefer file paths over abstract names. |
| 171 | + |
| 172 | +### Body shape — `status: clean` |
| 173 | + |
| 174 | +``` |
| 175 | +No surface drift detected in <ref-from>..<ref-to>. |
| 176 | +
|
| 177 | +Surfaces scanned: <N> |
| 178 | +Coverage checked: SKILL.md, recipes, docs/cli, integrations |
| 179 | +``` |
| 180 | + |
| 181 | +A `clean` report is still useful — `ctxctl audit list` shows |
| 182 | +it with a timestamp, so the user knows the audit ran. |
| 183 | + |
| 184 | +### Digest |
| 185 | + |
| 186 | +Compute a short opaque digest of the findings body (say, first |
| 187 | +7 hex chars of SHA-256 of the body bytes). Used by the |
| 188 | +dismissal ledger to detect "fresh findings" — a re-audit that |
| 189 | +produces the same digest stays dismissed; new findings clear |
| 190 | +the dismissal. |
| 191 | + |
| 192 | +## Execution Steps |
| 193 | + |
| 194 | +1. Run the dirty-tree guard. Refuse if non-clean. |
| 195 | +2. Compute the target range (default `main..HEAD`). |
| 196 | +3. Run `git diff --name-status <range>` and `git log |
| 197 | + --oneline <range>` to set the scope. |
| 198 | +4. Identify surfaces per the categories above. |
| 199 | +5. For each surface, run the coverage checks in order. |
| 200 | +6. Compose the body. Compute the digest. |
| 201 | +7. Write `.context/audit/surface.md` with the structured |
| 202 | + frontmatter + body. |
| 203 | +8. Print a one-line summary to the user: report path, |
| 204 | + surface count, finding count, and the next-step hint |
| 205 | + ("Open a working session — the audit-relay hook will |
| 206 | + relay the findings on the next prompt."). |
| 207 | + |
| 208 | +## Important Notes |
| 209 | + |
| 210 | +- You write a report; you **do not** edit code, SKILL.md, |
| 211 | + recipes, or any other surface. Remediation is the |
| 212 | + in-session agent's job. Crossing that boundary makes you |
| 213 | + the implementer and re-opens the tunnel-vision hole. |
| 214 | +- The report body becomes the verbatim relay body. Anything |
| 215 | + you put in there will be echoed at the user (and the |
| 216 | + next agent) one-for-one. Keep it specific and actionable; |
| 217 | + no editorial padding. |
| 218 | +- Empty findings (`status: clean`) is a successful outcome, |
| 219 | + not a problem. Write the report anyway so dismissal / |
| 220 | + staleness tracking has a basis. |
| 221 | +- The default `main..HEAD` covers the current branch. For |
| 222 | + auditing a single commit, the caller can pass a range |
| 223 | + like `<sha>^..<sha>`. |
| 224 | + |
| 225 | +## See Also |
| 226 | + |
| 227 | +- `specs/audit-channel.md`: design rationale, retention |
| 228 | + policy, naming-collision notes. |
| 229 | +- `internal/ctxctl/cli/audit/`: logic behind `ctxctl audit |
| 230 | + list / show / dismiss`. |
| 231 | +- `internal/ctxctl/cli/checkaudit/`: the `ctxctl audit-relay` |
| 232 | + hook logic that relays your reports. |
| 233 | +- `.context/CONVENTIONS.md` → |
| 234 | + *User-Facing Surface Completeness*: the canonical rule |
| 235 | + this audit enforces. |
0 commit comments