commit as part of the loop, and announce it when unasked
The loop gains a seventh step. Work was being committed all session on a verbal instruction, which means it was a property of one conversation rather than of the harness: a fresh session would have left everything in the working tree and reported success. Why automatic: a commit is one `git revert` from undone, and work that only ever existed in the working tree is not recoverable — this session already lost uncommitted work to a `git checkout` while signing was broken. Why announced: the safety argument covers the loss, not the surprise, so a session that did not ask for this gets one prominent line before the first commit and the off switch, once. Ownership split so nothing is stated twice: conventions.md "Git" owns what one commit contains — now one *revertible* unit rather than one feature, which is the human's correction to the "never bundle two passes" reading — and CLAUDE.md §4 owns when a commit happens. ADR-0052 records both, including that no gate can check this: no script can see whether a sentence was said. Docs 6 files, +72/-6 lines. No code, no counters moved.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# The feature loop
|
||||
|
||||
Six steps, in order: **Clarify → Plan → Implement → Verify → Document → Report.**
|
||||
Seven steps, in order: **Clarify → Plan → Implement → Verify → Document → Commit → Report.**
|
||||
`CLAUDE.md` holds the rules; this file holds the procedure.
|
||||
|
||||
Scale, do not skip. A one-sentence request gets one line of plan and a short report — and still gets
|
||||
@@ -135,7 +135,41 @@ grep -rn '<old form>' docs CLAUDE.md HARNESS.md ideas reference .claude scripts
|
||||
a sentence that is merely now untrue, or a concept renamed in one place — that sweep is the author's,
|
||||
and skipping it is how a doc ends up contradicting the file it points at.
|
||||
|
||||
## 6. Report
|
||||
## 6. Commit
|
||||
|
||||
Not optional and not asked for: the work is committed before the report, every time. `CLAUDE.md` §4
|
||||
holds the rule; this is how.
|
||||
|
||||
**The notice, if this session did not ask for automatic commits.** Before the first commit only, on
|
||||
its own line, visible:
|
||||
|
||||
```
|
||||
**Committing this to git** — and every later batch of changes in this session. Say "stop committing"
|
||||
and I will leave the tree dirty instead.
|
||||
```
|
||||
|
||||
Once said, it is not repeated. If the human asked for automatic commits — in this session or by
|
||||
having put the rule here — skip the notice entirely; repeating a notice for something already agreed
|
||||
is noise that trains them to skim the next one.
|
||||
|
||||
**What goes in one commit.** The changes that would be reverted together (`conventions.md` "Git").
|
||||
Bundle freely inside one unit: code with its test, its `state.md` row and its ADR are one commit
|
||||
because reverting the code without the doc leaves a lie. Split when a second pass is independently
|
||||
revertible — a fix to something you noticed afterwards, or a doc correction that was already wrong
|
||||
before this change. "Which of these would I want to undo alone?" answers it faster than any rule.
|
||||
|
||||
**How.**
|
||||
|
||||
- `git status` first: an unexpected file is a stop condition, not something to sweep into `git add -A`.
|
||||
- Stage what the change touched, then check `git diff --cached --stat` against the plan's file list.
|
||||
- The pre-commit hook runs `verify.sh`, so a red gate blocks the commit. That is the design — fix the
|
||||
gate or the code, do not reach for `--no-verify`.
|
||||
- Subject imperative, under 72 characters. Body says *why*, plus the numbers the change earned
|
||||
(LOC, counters, a benchmark) since `git log` is the map when no agent is available.
|
||||
- Never `git push`. Publishing is the human's; committing is bookkeeping.
|
||||
- Scratch files, `ideas/`, `reference/` and anything under the scratchpad stay out.
|
||||
|
||||
## 7. Report
|
||||
|
||||
Short — one line each, no prose unless a conflict or a stop condition needs explaining. Drop the lines
|
||||
that are genuinely n/a rather than padding them.
|
||||
@@ -145,6 +179,7 @@ Did: what now works, in the user's terms
|
||||
Evidence: the command you ran and its result
|
||||
Diff: files touched, ±LOC
|
||||
Propagated: content / code / templates / docs — each done or n/a, with content files named
|
||||
Committed: the commit subjects this produced, one line each
|
||||
Earned: counters after this change; anything now due for extraction
|
||||
Skipped: what you deliberately did not do, and the latent items you logged
|
||||
Conflicts: hard ones surfaced and how they were settled, soft ones deviated from, or "none"
|
||||
@@ -171,3 +206,6 @@ Swept: the old form you grepped for after a rename, or "n/a"
|
||||
| Made a field optional, left the ADR mandating it | Contradicted, not stale | Supersede the ADR |
|
||||
| Treated a one-sentence request as a narrow change | Articulation size is not blast radius | Walk the propagation table |
|
||||
| Splitting the difference between request and policy | A compromise nobody chose | Surface it; the human picks |
|
||||
| Ending a turn with the work only in the working tree | The one copy is the one that gets lost | Commit before reporting |
|
||||
| One commit per file, or per doc touched | Shredding a single revertible unit | Bundle what would be undone together |
|
||||
| Committing without ever saying you would | Consent assumed, not given | The notice, once, before the first one |
|
||||
|
||||
Reference in New Issue
Block a user