Skip to content

Commit f36b19e

Browse files
authored
Merge pull request #104 from ActiveMemory/feat/pad-undo-snapshot
feat: `ctx pad undo`, out-of-band audit channel (`ctxctl`), OS-native memory pressure
2 parents 4e16784 + 58b1c0f commit f36b19e

127 files changed

Lines changed: 9117 additions & 482 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
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.

.context/CONVENTIONS.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,76 @@ variants. Linters in `hack/` enforce the hard rules.
304304
file / preserve existing keys / skip when registered / reject malformed JSON
305305
306306
- Substrate vs. artifact placement: cognitive substrate (consumed and mutated via ctx-mediated paths — `ctx agent`, `ctx decision add`, `/ctx-kb-ingest`, `/ctx-handover`, ceremonies) lives under `.context/`; project artifacts (read and edited directly by humans — `specs/`, `CLAUDE.md`, `GETTING_STARTED.md`, `docs/`) live at the project root; tool config and tool homes (`.ctxrc`, `.claude/`) live at root by dotfile/tool convention. The kb is substrate, not artifact: direct file edits remain possible per Invariant 1, but the skill-mediated path is the discipline. Rationale recorded in DECISIONS.md.
307+
308+
## User-Facing Surface Completeness
309+
310+
When a change adds or alters a user-facing surface — a new
311+
`ctx` subcommand, a new flag, an observable behavior change,
312+
a new exit shape, a new output line — the work is **not
313+
complete** until every one of the following has been updated
314+
in the same commit (or the same stacked PR, with the user's
315+
explicit OK):
316+
317+
- `internal/assets/commands/commands.yaml` and
318+
`examples.yaml` for the subcommand description and example
319+
- `internal/assets/claude/skills/ctx-<area>/SKILL.md` so the
320+
agent knows the surface exists and when to trigger it
321+
- `internal/assets/integrations/copilot-cli/skills/<...>` if
322+
a parallel skill exists for the integration
323+
- `docs/recipes/<related-recipe>.md` for any recipe that
324+
already demonstrates the broader feature; consider a new
325+
recipe if the surface is its own workflow shape
326+
- `docs/cli/<command>.md` if a per-command CLI doc page
327+
exists for this surface
328+
329+
Splitting these into a "Phase 2 / follow-up commit / future
330+
sweep" is **deferral** in the Constitution's sense, no matter
331+
how the phase is labeled. Docs are part of the deliverable,
332+
not a separable improvement. The "I can create a follow-up
333+
task" prohibition applies verbatim.
334+
335+
Acceptable exceptions (state them in the commit body):
336+
337+
- The surface is internal-only (no human user encounters it).
338+
- A recipe / skill genuinely does not exist for this feature
339+
area and writing one is itself a larger separable piece of
340+
work (then file the spec for that piece in the same commit,
341+
do not just defer).
342+
343+
The Self-check before declaring a feature commit complete is:
344+
*"If a user runs `ctx help` or asks `/ctx-<area>` to do this
345+
new thing today, will the help text / skill / recipe match
346+
what the code does?"* If no, the commit is not complete.
347+
348+
## Maintainer-Only Binaries (Layout and Installation)
349+
350+
Maintainer-only binaries — tooling that must never ship to end
351+
users — live in `tools/<name>/` as separate Go modules. The
352+
module path is lexically nested under the main ctx module
353+
(`github.com/ActiveMemory/ctx/tools/<name>`) so the new module
354+
CAN import the parent's `internal/` packages (Go's
355+
internal-import rule is path-lexical, not module-scoped — see
356+
LEARNINGS.md), reusing `rc`, `desc`, `nudge`, `config`
357+
primitives without duplication.
358+
359+
Build and install:
360+
361+
- Built to `dist/<name>` via `make <name>` (keeps the repo
362+
root clean).
363+
- PATH-installed to `/usr/local/bin/<name>` via
364+
`make install-<name>` / `make reinstall-<name>` —
365+
mirroring ctx's `install` / `reinstall` targets so one
366+
binary serves every worktree and repo copy.
367+
- The shipped `ctx` binary's `go.mod` must NOT `require` the
368+
maintainer module, giving a **hard module-graph guarantee**
369+
that the maintainer code can never leak into `ctx`.
370+
371+
Repo-local hooks calling the maintainer binary live in the
372+
gitignored `.claude/settings.local.json`, **not** in the
373+
shipped `internal/assets/claude/hooks/hooks.json`. The hook
374+
command shape is `cd "$CLAUDE_PROJECT_DIR" && <name>
375+
<subcommand>` (PATH binary, project-root cwd so `.context/`
376+
resolves correctly under cwd-anchoring).
377+
378+
`tools/ctxctl/` is the first inhabitant. Future maintainer
379+
binaries follow the same shape.

0 commit comments

Comments
 (0)