Skip to content

Commit adc8456

Browse files
drmikecroweclaude
andcommitted
Config, isolation, and verifying in the tree the change actually lands in
Three things this skill relies on but never wrote down: where per-repo settings live, how work is kept out of the user's working tree, and why a green run in an isolated tree is not evidence about the tree the change merges into. `references/setup.md` (new) documents an optional `.old-coder.toml`: `isolation`, `install`, `commit`, `commit_args`, `tracker`, `artifacts`, and `[commands]`. Nothing blocks on it -- absent, everything defaults to `propose` and `isolation = "auto"`. The part worth arguing about is the restrict-only asymmetry. A TRACKED config may tighten permissions and never loosen them: `install = "allow"` in a committed file is ignored, because otherwise cloning a repo would hand its config authority over the machine that cloned it. Grants live only in a gitignored or absolute-path config, where they are the machine owner's statement rather than the repo author's. Alongside it, the permission rule stated once: an operation proceeds if policy permits it AND (it is reversible OR an approver is present). Policy can grant standing permission; it cannot manufacture a human. The consequence matters for unattended runs -- with `propose` and nobody present, skip the operation, record the consequence, and continue. A run that halts on configuration produces neither code nor evidence. Isolation is stated as an invariant rather than a mechanism: do not mutate the user's working tree to do your work, and verify in the tree that will actually receive the merge. The trap is worth the paragraph it gets -- a fresh worktree contains no gitignored content, so the gauntlet frequently cannot run there until dependencies are rebuilt, and the tempting move is to report green from a tree that never ran the suite. The second half of that invariant is the new integration-tree layer. A change can pass every layer in a worktree and break the main tree on merge, because the main tree has ignored files the isolated one lacked: a local `.env`, a built asset, a stale generated module. The recipe applies the diff UNCOMMITTED and reverts -- deliberately not a merge, rebase, or commit, since many repos forbid committing to the landing branch, a worktree holding that branch blocks checkout outright, and landing is the human's call after EVIDENCE, not a verification step. The revert sequence is spelled out because shortening it silently leaves new files behind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 57ead18 commit adc8456

3 files changed

Lines changed: 380 additions & 1 deletion

File tree

skills/old-coder/SKILL.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ implementation files:
5858
reviews after the fact.
5959
- The spec is append-only during the task. If implementation reveals the spec was
6060
wrong, say so explicitly and revise it visibly — never silently drift.
61+
- **Declare the isolation mechanism** (worktree / branch / none, and why) in the
62+
spec, so the human can see and veto it before work starts. Pick it with the
63+
detection chain in `references/setup.md`.
6164

6265
### 2. RED — prove each test can fail
6366

@@ -115,6 +118,7 @@ or a tool is unavailable, record that in the evidence report with the reason.
115118
| Real execution | "passes tests, doesn't run" | actually run the app/CLI/endpoint once on a realistic input, not only the test harness |
116119
| Supply chain & secrets | vulnerable/unnecessary deps, leaked credentials | when the dependency set changed: audit it (pip-audit / npm audit / govulncheck / cargo-audit) and check licenses; scan the diff for secrets; every new dependency must trace back to its SPEC justification. Also eyeball the capability diff: did the change start using network / subprocess / filesystem / env it didn't before? |
117120
| Suite health | flaky or order-dependent tests | run the suite in randomized order (pytest-randomly etc.); repeat suspected flakes. Every EVIDENCE number rests on the suite being deterministic — a flaky suite quietly invalidates the report |
121+
| Integration-tree verification | "green in isolation, broken on merge" | whenever the isolated tree and the tree the change lands in differ by ignored or untracked content, rerun the suite in the landing tree — by **applying the diff uncommitted and reverting**, never by merging, rebasing, or committing there (exact recipe in `references/gauntlet.md`). A green run in a tree that lacks the main tree's `.env`, build outputs, or installed deps is not evidence about the main tree |
118122

119123
Baseline note — on a repo with pre-existing failures, record the baseline
120124
first (which tests already fail, verbatim) and hold the line at zero NEW
@@ -268,7 +272,38 @@ until that file has been read in full and executed; missing or unreadable →
268272
`not performed` finalizes only as a declared downgrade, like an unapproved
269273
spec. On Tier 3 it needs no apology — say so and claim less.
270274

271-
## Setup
275+
## Setup and configuration
276+
277+
Optional per-repo config lives in `.old-coder.toml``isolation`, `install`,
278+
`commit`, `commit_args`, `tracker`, `artifacts`, `[commands]`. **Never block on
279+
it.** Absent, use restrictive defaults (permission keys = `propose`,
280+
`isolation` = `auto`, `artifacts` = `.old-coder`) and mention
281+
`references/setup.md` once. It is gitignored by default so *grants* stay local;
282+
a **tracked** copy is honored only where it tightens (`propose` yes, `allow` and
283+
`isolation = "none"` ignored) — otherwise cloning a repo would hand its config
284+
authority over your machine.
285+
286+
**Use the project's configured or detected commands**, not the ecosystem tables
287+
in `references/gauntlet.md` — those are fallbacks for when nothing is found. A
288+
guessed command produces confident, wrong evidence, which is the one failure
289+
mode this skill exists to prevent.
290+
291+
The permission rule, once: **an operation proceeds if policy permits it AND (it
292+
is reversible OR an approver is present).** Policy can grant standing
293+
permission; it cannot manufacture a human. Writing tests and running the
294+
gauntlet are reversible and proceed unattended. Installs, commits, and tracker
295+
posts are not: they need the matching key set to `allow`, or an in-task
296+
approval. **With `propose` and no approver present, skip the operation, record
297+
the consequence in EVIDENCE, and continue** — never block on a human who is not
298+
there. A run that halts on configuration produces neither code nor evidence.
299+
300+
**Isolation.** The invariant, not the mechanism: *do not mutate the user's
301+
working tree to do your work, and verify in the tree that will actually receive
302+
the merge.* Branch or worktree — pick with the detection chain in
303+
`references/setup.md`, declare it in the SPEC. The trap: **a fresh worktree
304+
contains no gitignored content**, so the gauntlet often cannot run there until
305+
dependencies are rebuilt. Rebuild, or fall back to a branch and record why.
306+
Never report green from a tree that never ran the suite.
272307

273308
If the project has no test runner, no linter, or no type checking, set up the
274309
minimal standard toolchain for the language **first** (see

skills/old-coder/references/gauntlet.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,53 @@ re-runnable by the human, which a scratch-directory script is not.
143143
remain) and run the suite once more to confirm green.
144144
5. Report as: "manual mutation: N/N killed".
145145

146+
## Integration-tree verification
147+
148+
> A green run in an isolated tree is not evidence about the tree the change
149+
> lands in, whenever the two differ by ignored or untracked content. Re-run the
150+
> suite there before claiming done.
151+
152+
The failure this prevents is concrete: a change passes every layer in a
153+
worktree and breaks the main tree on merge, because the main tree contains
154+
ignored files the isolated one lacked — a local `.env`, a built asset, a
155+
stale generated module, a differently-resolved `node_modules`.
156+
157+
Applies **whenever the two trees differ by ignored or untracked content**, which
158+
is nearly always for a worktree and never for a plain branch in the same tree.
159+
When it does not apply, say why in EVIDENCE (`n-a: branch isolation, same
160+
tree`); do not leave the row blank.
161+
162+
**Do not merge, rebase, or commit into the integration tree.** That reading is
163+
the dangerous one: many repos forbid committing to the landing branch outright,
164+
and where a worktree already holds the branch, the main checkout cannot check it
165+
out at all. It also violates this skill's own invariant — *do not mutate the
166+
user's working tree to do your work*. Verifying in a tree is not the same as
167+
landing in it, and landing is the human's call, after EVIDENCE.
168+
169+
The default technique applies the diff **uncommitted** and reverts:
170+
171+
```sh
172+
cd <integration tree>
173+
git status --porcelain > /tmp/before.txt # the tree must be clean first; if not, stop
174+
git diff <base>..<tip> | git apply - # apply, do not merge
175+
<test command> > "$LOGS/integration.log" 2>&1
176+
git checkout -- . # revert tracked changes, always
177+
git clean -nd # list what the diff added; remove those paths
178+
git status --porcelain # must match /tmp/before.txt
179+
```
180+
181+
Three things that go wrong if you shorten it: `git checkout -- .` does not
182+
remove **new files** the diff added, so a diff that adds a module leaves it
183+
behind — hence the `git clean -nd` review step, listed before deleting rather
184+
than `-f` blind. A dirty starting tree makes the revert ambiguous, so check
185+
first and stop rather than guess. And `git apply` failing partway leaves the
186+
tree half-patched: treat a non-zero exit as "revert now and report", not as
187+
something to fix forward.
188+
189+
Report both results — the isolated run and the integration run — as separate
190+
numbers, never merged into one, and state which technique produced the
191+
integration number.
192+
146193
## Gauntlet entry point
147194

148195
Persist one command that runs every layer in sequence and fails on the first

0 commit comments

Comments
 (0)