docs: let maintenance clones self-heal and abort without leaving debris

A failed nightly run left edits in the maintenance clone, and every later run
correctly refused to work on a dirty worktree, so one failure stalled the whole
pipeline until morning.

Maintenance task commands now recognise a gitignored .maintenance-clone marker.
In a marked disposable clone they discard leftover debris, return to main, and
continue; in a human working copy they still stop and touch nothing.

Add an explicit abort protocol: revert your own edits, confirm the worktree is
clean, release the claim, and report. Restore the honest skip that the
complete-file rule had squeezed out, since a laundered fix is worse than a
documented skip, and describe how to handle a file that is entirely an
external-data boundary instead of inventing generic JSON contracts.
This commit is contained in:
Bohdan Triapitsyn
2026-08-17 21:49:33 +03:00
parent d9f1c0d44c
commit 344c1b3ce3
6 changed files with 106 additions and 7 deletions
+41 -2
View File
@@ -13,7 +13,20 @@ First, verify the worktree is safe to use:
`git status --porcelain`
If the output is not empty, stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches. Local work in progress must never end up in a maintenance PR.
If the output is not empty, decide which of two situations you are in.
If the repository root contains a `.maintenance-clone` marker file, this working copy is a disposable clone dedicated to unattended maintenance. Nothing in it is human work in progress, so leftover changes are debris from an earlier task that failed to clean up after itself. Recover the clone rather than stopping:
```
git checkout -- .
git clean -fd
git checkout main
git pull
```
Report exactly which files you discarded, then continue with the task. A failed predecessor must not be able to jam the pipeline for every later run.
If the marker file is absent, this is a working copy a person uses. Stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches.
Then run:
@@ -295,7 +308,18 @@ So, before you consider a selected file done:
- A group of findings sharing one root cause counts as one reason, and that root cause is usually worth fixing. If eleven findings in a file all come from one untyped parser, fixing that parser is the point of the batch, not a reason to skip.
- Leaving more than roughly a quarter of a file's findings behind means you have not finished. Either finish them or explain, per group, why the file was a bad selection in the first place.
Skip a finding only when the fix would require unclear behavior changes, or a change so large it would stop the pull request from being reviewable. Difficulty alone is not a reason. If skipped, give the specific reason in the PR body under `## Non-goals`.
Skip a finding when the fix would require unclear behavior changes, when the change would be so large that the pull request stops being reviewable, or when the only way you can see to close it is one of the forbidden patterns. That last case is not a loophole, it is the required outcome: an honest skip is always better than a laundered fix, and choosing the forbidden pattern to satisfy "finish the file" is the worse failure of the two. Ordinary difficulty, on its own, is still not a reason. If skipped, give the specific reason in the PR body under `## Non-goals`.
### When the whole file is an external-data boundary
Some files exist to receive data from outside the program: provider APIs, quota endpoints, extension host messages, configuration on disk. In such a file, most or all findings can share one root cause, and the honest fix is a real parsed boundary with named contracts, which is a substantial piece of work rather than a lint cleanup.
Recognize this early, before editing. Read the file first and ask whether closing its findings means designing a data contract that does not exist yet. If it does, choose one of two outcomes, and never a third:
- Do the work properly for a coherent part of the file: define the contract for one provider, one endpoint, or one message, parse it at its boundary, and leave the rest with a clear explanation of the remaining root cause. A correct partial fix with a named boundary is a good pull request.
- Conclude that the file is a poor batch selection, abort per "Aborting cleanly", and say in your report that the file needs a deliberate data-contract change rather than an unattended cleanup.
What you must not do is invent a generic JSON contract to make the findings disappear. Generic record types, primitive unions, and `unknown`-based aliases over external data are exactly the patterns these rules exist to reject, and reintroducing them under time pressure defeats the purpose of the whole task.
Hard prohibitions. Each of these makes the lint output greener while making the code worse, and each is grounds for rejecting the whole PR:
- Do not disable, downgrade, or ignore anti-slop rules, in configuration or with inline comments.
@@ -311,6 +335,21 @@ Hard prohibitions. Each of these makes the lint output greener while making the
- Do not edit `CHANGELOG.md`, package versions, or release metadata. This is internal maintenance with no user-facing change.
- Do not fix findings outside the selected files.
## Aborting cleanly
You may reach a point where the batch cannot be completed correctly: validation keeps failing, or the only remaining way to close the findings is a pattern this task forbids. Stopping there is the right decision. Stopping there and walking away from a modified working copy is not.
Whatever edits exist in the working copy at that moment are your own, made minutes ago in this session. They are not human work in progress, and nothing is lost by removing them. Leaving them behind jams every scheduled run that follows, because those runs correctly refuse to operate on a dirty worktree.
So when you abort, in this order:
1. Revert every file you modified: `git checkout -- <paths>`, plus `git clean -fd` for files you created. Verify with `git status --porcelain` that the result is empty.
2. Release the claim so the files return to the pool: ``bun run deslop -- release --run <run-id>``.
3. Return to `main`.
4. Report what you attempted, precisely why you stopped, and confirm that both the worktree is clean and the claim is released.
Never leave a partially fixed working copy as a message to the next run. If a file resists a correct fix, that belongs in your report, not on disk.
After edits, run:
`bun run deslop -- check-batch --run <run-id>`
+14 -1
View File
@@ -13,7 +13,20 @@ First, verify the worktree is safe to use:
`git status --porcelain`
If the output is not empty, stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, or switch branches.
If the output is not empty, decide which of two situations you are in.
If the repository root contains a `.maintenance-clone` marker file, this working copy is a disposable clone dedicated to unattended maintenance. Nothing in it is human work in progress, so leftover changes are debris from an earlier task that failed to clean up after itself. Recover the clone rather than stopping:
```
git checkout -- .
git clean -fd
git checkout main
git pull
```
Report exactly which files you discarded, then continue with the task. A failed predecessor must not be able to jam the pipeline for every later run.
If the marker file is absent, this is a working copy a person uses. Stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches.
List the active batches:
+3 -1
View File
@@ -29,7 +29,9 @@ Verify the worktree is clean:
`git status --porcelain`
If the output is not empty, stop immediately and report it. Do not stash, reset, or discard anything.
If the output is not empty and the repository root contains a `.maintenance-clone` marker file, this is a disposable maintenance clone and the changes are debris from an earlier failed task. Recover it with `git checkout -- .`, `git clean -fd`, `git checkout main`, `git pull`, report exactly which files you discarded, and continue.
If the marker file is absent, stop immediately and report it. Do not stash, reset, or discard anything.
Read `AGENTS.md`, and read `.opencode/commands/as-fixes.md` in full, including the sections "What a good fix looks like" and "Hard prohibitions". Those describe the standard the anti-slop PRs were supposed to meet. Your job includes verifying they actually met it.
+31 -2
View File
@@ -13,7 +13,20 @@ First, verify the worktree is safe to use:
`git status --porcelain`
If the output is not empty, stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches. Local work in progress must never end up in a maintenance PR.
If the output is not empty, decide which of two situations you are in.
If the repository root contains a `.maintenance-clone` marker file, this working copy is a disposable clone dedicated to unattended maintenance. Nothing in it is human work in progress, so leftover changes are debris from an earlier task that failed to clean up after itself. Recover the clone rather than stopping:
```
git checkout -- .
git clean -fd
git checkout main
git pull
```
Report exactly which files you discarded, then continue with the task. A failed predecessor must not be able to jam the pipeline for every later run.
If the marker file is absent, this is a working copy a person uses. Stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches.
Then run:
@@ -36,10 +49,26 @@ Workflow:
- Finish each selected file. A file is finished when it has zero React Doctor diagnostics, or when every remaining diagnostic has an individual, specific reason to stay. A half-fixed file will be selected again later and cost a second pull request, a second review, and a second merge over the same code.
- Before considering a file done, re-run `bun run doctor -- file <path>` and read what is left. Leaving more than roughly a quarter of a file's diagnostics behind means you have not finished.
- A group of diagnostics sharing one root cause counts as one reason, and that root cause is usually worth fixing rather than deferring.
- Skip a diagnostic only when the fix would require unclear behavior changes, or a change so large it would stop the pull request from being reviewable. Difficulty alone is not a reason. If skipped, give the specific reason in the PR body under `## Non-goals`.
- Skip a diagnostic when the fix would require unclear behavior changes, when the change would be so large that the pull request stops being reviewable, or when the only way you can see to close it is a change you would not defend in review. An honest skip is always better than a forced fix. Ordinary difficulty, on its own, is still not a reason. If skipped, give the specific reason in the PR body under `## Non-goals`.
- If a whole selected file turns out to need a deliberate architectural change rather than a cleanup, abort per "Aborting cleanly" and report that the file was a poor batch selection.
- Do not suppress React Doctor diagnostics unless there is a clear false positive.
- If a listed diagnostic requires changes outside the selected files, make only the minimal required supporting change. Do not expand the cleanup scope.
## Aborting cleanly
You may reach a point where the batch cannot be completed correctly: validation keeps failing, or the only remaining way to close the findings is a pattern this task forbids. Stopping there is the right decision. Stopping there and walking away from a modified working copy is not.
Whatever edits exist in the working copy at that moment are your own, made minutes ago in this session. They are not human work in progress, and nothing is lost by removing them. Leaving them behind jams every scheduled run that follows, because those runs correctly refuse to operate on a dirty worktree.
So when you abort, in this order:
1. Revert every file you modified: `git checkout -- <paths>`, plus `git clean -fd` for files you created. Verify with `git status --porcelain` that the result is empty.
2. Release the claim so the files return to the pool: ``bun run doctor -- release --run <run-id>``.
3. Return to `main`.
4. Report what you attempted, precisely why you stopped, and confirm that both the worktree is clean and the claim is released.
Never leave a partially fixed working copy as a message to the next run. If a file resists a correct fix, that belongs in your report, not on disk.
After edits, run:
`bun run doctor -- check-batch --run <run-id>`
+14 -1
View File
@@ -13,7 +13,20 @@ First, verify the worktree is safe to use:
`git status --porcelain`
If the output is not empty, stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, or switch branches.
If the output is not empty, decide which of two situations you are in.
If the repository root contains a `.maintenance-clone` marker file, this working copy is a disposable clone dedicated to unattended maintenance. Nothing in it is human work in progress, so leftover changes are debris from an earlier task that failed to clean up after itself. Recover the clone rather than stopping:
```
git checkout -- .
git clean -fd
git checkout main
git pull
```
Report exactly which files you discarded, then continue with the task. A failed predecessor must not be able to jam the pipeline for every later run.
If the marker file is absent, this is a working copy a person uses. Stop immediately and report that the worktree has uncommitted changes. Do not stash, reset, discard, commit, or switch branches.
List the active batches: