instar 1.3.667 → 1.3.668
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/monitoring/AgentWorktreeReaper.d.ts +17 -0
- package/dist/monitoring/AgentWorktreeReaper.d.ts.map +1 -1
- package/dist/monitoring/AgentWorktreeReaper.js +38 -0
- package/dist/monitoring/AgentWorktreeReaper.js.map +1 -1
- package/dist/monitoring/agentWorktreeGit.d.ts +12 -0
- package/dist/monitoring/agentWorktreeGit.d.ts.map +1 -1
- package/dist/monitoring/agentWorktreeGit.js +27 -2
- package/dist/monitoring/agentWorktreeGit.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.668.md +24 -0
- package/upgrades/side-effects/worktree-reaper-untracked-blindspot.md +22 -0
|
@@ -32,6 +32,13 @@ export interface AgentWorktreeReaperConfig {
|
|
|
32
32
|
reapIntervalMs: number;
|
|
33
33
|
/** Bounded blast radius per pass. */
|
|
34
34
|
maxReapsPerPass: number;
|
|
35
|
+
/**
|
|
36
|
+
* Per-path consecutive-removal-failure breaker (No Unbounded Loops standard).
|
|
37
|
+
* After this many consecutive `removeWorktree` failures for the SAME path, the
|
|
38
|
+
* reaper stops attempting it (keeps it as `reclaim-failed`) until restart, so a
|
|
39
|
+
* permanently-unremovable worktree can't be retried forever. 0 disables the brake.
|
|
40
|
+
*/
|
|
41
|
+
maxReclaimFailuresPerPath: number;
|
|
35
42
|
}
|
|
36
43
|
export declare const DEFAULT_AGENT_WORKTREE_REAPER_CONFIG: AgentWorktreeReaperConfig;
|
|
37
44
|
export interface WorktreeInfo {
|
|
@@ -73,6 +80,11 @@ export declare class AgentWorktreeReaper extends EventEmitter {
|
|
|
73
80
|
private running;
|
|
74
81
|
private lastPassAt;
|
|
75
82
|
private reapedLastPass;
|
|
83
|
+
/** Per-path consecutive removal-failure counts (breaker). Keyed by worktree path;
|
|
84
|
+
* cleared on a successful removal of that path. Process-lifetime (resets on restart). */
|
|
85
|
+
private reclaimFailures;
|
|
86
|
+
/** Paths whose breaker has tripped + already emitted (emit-once). */
|
|
87
|
+
private reclaimTripped;
|
|
76
88
|
constructor(deps: AgentWorktreeReaperDeps, cfg?: Partial<AgentWorktreeReaperConfig>);
|
|
77
89
|
start(): void;
|
|
78
90
|
stop(): void;
|
|
@@ -90,6 +102,11 @@ export declare class AgentWorktreeReaper extends EventEmitter {
|
|
|
90
102
|
reaped: string[];
|
|
91
103
|
dryRun: boolean;
|
|
92
104
|
}>;
|
|
105
|
+
/** True when this path's removal has failed >= the configured cap (breaker open).
|
|
106
|
+
* cap 0 disables the brake (never trips). */
|
|
107
|
+
private breakerTripped;
|
|
108
|
+
/** Record one removal failure for a path; emit the breaker-trip ONCE when the cap is reached. */
|
|
109
|
+
private recordReclaimFailure;
|
|
93
110
|
/** Observability snapshot for GET /worktrees/agent-reaper (no side effects). */
|
|
94
111
|
snapshot(): {
|
|
95
112
|
enabled: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentWorktreeReaper.d.ts","sourceRoot":"","sources":["../../src/monitoring/AgentWorktreeReaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentWorktreeReaper.d.ts","sourceRoot":"","sources":["../../src/monitoring/AgentWorktreeReaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED,eAAO,MAAM,oCAAoC,EAAE,yBAMlD,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,eAAe,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,aAAa,EAAE,MAAM,YAAY,EAAE,CAAC;IACpC,sEAAsE;IACtE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,uEAAuE;IACvE,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC;IAC1C;2EACuE;IACvE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,gFAAgF;IAChF,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,mBAAoB,SAAQ,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA4B;IAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,cAAc,CAAK;IAC3B;8FAC0F;IAC1F,OAAO,CAAC,eAAe,CAA6B;IACpD,qEAAqE;IACrE,OAAO,CAAC,cAAc,CAAqB;gBAE/B,IAAI,EAAE,uBAAuB,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC;IAOnF,KAAK,IAAI,IAAI;IAMb,IAAI,IAAI,IAAI;IAIZ,OAAO,KAAK,YAAY,GAEvB;IAED;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,kBAAkB;IAWhD,6EAA6E;IACvE,IAAI,IAAI,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAsD3G;kDAC8C;IAC9C,OAAO,CAAC,cAAc;IAMtB,iGAAiG;IACjG,OAAO,CAAC,oBAAoB;IAU5B,gFAAgF;IAChF,QAAQ,IAAI;QACV,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAC9E,SAAS,EAAE,kBAAkB,EAAE,CAAC;QAChC,WAAW,EAAE,MAAM,CAAC;KACrB;CAiBF"}
|
|
@@ -31,6 +31,7 @@ export const DEFAULT_AGENT_WORKTREE_REAPER_CONFIG = {
|
|
|
31
31
|
dryRun: true,
|
|
32
32
|
reapIntervalMs: 24 * 3600 * 1000,
|
|
33
33
|
maxReapsPerPass: 20,
|
|
34
|
+
maxReclaimFailuresPerPath: 3,
|
|
34
35
|
};
|
|
35
36
|
export class AgentWorktreeReaper extends EventEmitter {
|
|
36
37
|
cfg;
|
|
@@ -40,6 +41,11 @@ export class AgentWorktreeReaper extends EventEmitter {
|
|
|
40
41
|
running = false;
|
|
41
42
|
lastPassAt = 0;
|
|
42
43
|
reapedLastPass = 0;
|
|
44
|
+
/** Per-path consecutive removal-failure counts (breaker). Keyed by worktree path;
|
|
45
|
+
* cleared on a successful removal of that path. Process-lifetime (resets on restart). */
|
|
46
|
+
reclaimFailures = new Map();
|
|
47
|
+
/** Paths whose breaker has tripped + already emitted (emit-once). */
|
|
48
|
+
reclaimTripped = new Set();
|
|
43
49
|
constructor(deps, cfg) {
|
|
44
50
|
super();
|
|
45
51
|
this.deps = deps;
|
|
@@ -106,6 +112,13 @@ export class AgentWorktreeReaper extends EventEmitter {
|
|
|
106
112
|
evaluations.push({ path: info.path, branch: info.branch, verdict: 'keep', reason: 'eval-error' });
|
|
107
113
|
continue;
|
|
108
114
|
}
|
|
115
|
+
// Per-path failure breaker (No Unbounded Loops): a reap-eligible worktree
|
|
116
|
+
// whose removal has failed too many times is no longer attempted — surfaced
|
|
117
|
+
// honestly as keep('reclaim-failed') so the operator sees WHY it persists.
|
|
118
|
+
if (evaln.verdict === 'reap-eligible' && this.breakerTripped(info.path)) {
|
|
119
|
+
evaluations.push({ path: info.path, branch: info.branch, verdict: 'keep', reason: 'reclaim-failed' });
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
109
122
|
evaluations.push(evaln);
|
|
110
123
|
if (evaln.verdict !== 'reap-eligible')
|
|
111
124
|
continue;
|
|
@@ -117,9 +130,16 @@ export class AgentWorktreeReaper extends EventEmitter {
|
|
|
117
130
|
try {
|
|
118
131
|
this.deps.removeWorktree(info.path);
|
|
119
132
|
reaped.push(info.path);
|
|
133
|
+
this.reclaimFailures.delete(info.path); // success → clear the breaker count
|
|
134
|
+
this.reclaimTripped.delete(info.path);
|
|
120
135
|
this.emit('reaped', info);
|
|
121
136
|
}
|
|
122
137
|
catch (err) {
|
|
138
|
+
// @silent-fallback-ok: NOT silent — the removal failure is surfaced via
|
|
139
|
+
// emit('error') AND recorded for the per-path breaker (which itself
|
|
140
|
+
// emit('reclaim-breaker')s once on trip). The worktree is simply kept and
|
|
141
|
+
// retried (bounded by the breaker), the safe direction for a deletion op.
|
|
142
|
+
this.recordReclaimFailure(info.path);
|
|
123
143
|
this.emit('error', err);
|
|
124
144
|
}
|
|
125
145
|
}
|
|
@@ -132,6 +152,24 @@ export class AgentWorktreeReaper extends EventEmitter {
|
|
|
132
152
|
}
|
|
133
153
|
return { ts: this.now(), evaluations, reaped, dryRun: !this.killsEnabled };
|
|
134
154
|
}
|
|
155
|
+
/** True when this path's removal has failed >= the configured cap (breaker open).
|
|
156
|
+
* cap 0 disables the brake (never trips). */
|
|
157
|
+
breakerTripped(path) {
|
|
158
|
+
const cap = this.cfg.maxReclaimFailuresPerPath;
|
|
159
|
+
if (cap <= 0)
|
|
160
|
+
return false;
|
|
161
|
+
return (this.reclaimFailures.get(path) ?? 0) >= cap;
|
|
162
|
+
}
|
|
163
|
+
/** Record one removal failure for a path; emit the breaker-trip ONCE when the cap is reached. */
|
|
164
|
+
recordReclaimFailure(path) {
|
|
165
|
+
const cap = this.cfg.maxReclaimFailuresPerPath;
|
|
166
|
+
const n = (this.reclaimFailures.get(path) ?? 0) + 1;
|
|
167
|
+
this.reclaimFailures.set(path, n);
|
|
168
|
+
if (cap > 0 && n >= cap && !this.reclaimTripped.has(path)) {
|
|
169
|
+
this.reclaimTripped.add(path);
|
|
170
|
+
this.emit('reclaim-breaker', { path, failures: n });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
135
173
|
/** Observability snapshot for GET /worktrees/agent-reaper (no side effects). */
|
|
136
174
|
snapshot() {
|
|
137
175
|
let worktrees = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentWorktreeReaper.js","sourceRoot":"","sources":["../../src/monitoring/AgentWorktreeReaper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentWorktreeReaper.js","sourceRoot":"","sources":["../../src/monitoring/AgentWorktreeReaper.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
* op — `git worktree remove` — goes through SafeGitExecutor.execSync.
|
|
8
8
|
*/
|
|
9
9
|
import type { AgentWorktreeReaperDeps } from './AgentWorktreeReaper.js';
|
|
10
|
+
/**
|
|
11
|
+
* Reaper-specific residue denylist (spec: worktree-reaper-untracked-blindspot).
|
|
12
|
+
* INTENTIONALLY NARROWER than worktreeDirtyCheck's DEFAULT_RESIDUE_DENYLIST: this
|
|
13
|
+
* list gates an irreversible `git worktree remove`, so it contains ONLY paths that
|
|
14
|
+
* are unambiguously never user work. It deliberately EXCLUDES the broad
|
|
15
|
+
* `out/` / `build/` / `coverage/` / `*.log` entries of the shared default — users
|
|
16
|
+
* legitimately hand-author files under those (a `build/deploy.md`, an `analysis.log`),
|
|
17
|
+
* and an untracked one of those on a merged worktree must NEVER be silently reaped.
|
|
18
|
+
* We do NOT mutate DEFAULT_RESIDUE_DENYLIST (it feeds the separate yield-safety
|
|
19
|
+
* config list + other consumers); the reaper carries its own list.
|
|
20
|
+
*/
|
|
21
|
+
export declare const REAPER_RESIDUE_DENYLIST: readonly string[];
|
|
10
22
|
/** Read-only git executor signature (injected so this module is testable). */
|
|
11
23
|
export type ReadGit = (args: string[], cwd: string) => string;
|
|
12
24
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentWorktreeGit.d.ts","sourceRoot":"","sources":["../../src/monitoring/agentWorktreeGit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"agentWorktreeGit.d.ts","sourceRoot":"","sources":["../../src/monitoring/agentWorktreeGit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,uBAAuB,EAAgB,MAAM,0BAA0B,CAAC;AAEtF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAIpD,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;AAgB9D;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAU1G;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;yEACqE;IACrE,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GAAG,uBAAuB,CAqH1B"}
|
|
@@ -10,6 +10,23 @@ import fs from 'node:fs';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { execFileSync } from 'node:child_process';
|
|
12
12
|
import { SafeGitExecutor } from '../core/SafeGitExecutor.js';
|
|
13
|
+
import { classifyPorcelain } from '../core/worktreeDirtyCheck.js';
|
|
14
|
+
/**
|
|
15
|
+
* Reaper-specific residue denylist (spec: worktree-reaper-untracked-blindspot).
|
|
16
|
+
* INTENTIONALLY NARROWER than worktreeDirtyCheck's DEFAULT_RESIDUE_DENYLIST: this
|
|
17
|
+
* list gates an irreversible `git worktree remove`, so it contains ONLY paths that
|
|
18
|
+
* are unambiguously never user work. It deliberately EXCLUDES the broad
|
|
19
|
+
* `out/` / `build/` / `coverage/` / `*.log` entries of the shared default — users
|
|
20
|
+
* legitimately hand-author files under those (a `build/deploy.md`, an `analysis.log`),
|
|
21
|
+
* and an untracked one of those on a merged worktree must NEVER be silently reaped.
|
|
22
|
+
* We do NOT mutate DEFAULT_RESIDUE_DENYLIST (it feeds the separate yield-safety
|
|
23
|
+
* config list + other consumers); the reaper carries its own list.
|
|
24
|
+
*/
|
|
25
|
+
export const REAPER_RESIDUE_DENYLIST = [
|
|
26
|
+
'dist/', 'node_modules/', '.cache/', '.turbo/', '*.tsbuildinfo',
|
|
27
|
+
'.metadata_never_index', // instar-managed Spotlight-exclusion marker — never work
|
|
28
|
+
'.instar/instar-dev-traces/', // instar audit-trace droppings — never work
|
|
29
|
+
];
|
|
13
30
|
const defaultReadGit = (args, cwd) => SafeGitExecutor.readSync(args, {
|
|
14
31
|
cwd,
|
|
15
32
|
encoding: 'utf-8',
|
|
@@ -166,12 +183,20 @@ export function makeAgentWorktreeReaperDeps(opts) {
|
|
|
166
183
|
return out;
|
|
167
184
|
},
|
|
168
185
|
isClean: (p) => {
|
|
186
|
+
// Residue-aware via the PURE classifyPorcelain (NOT the fail-OPEN
|
|
187
|
+
// makeWorktreeDirtyCheck wrapper): a worktree whose only entries are
|
|
188
|
+
// reaper-residue (build artifacts / instar markers) is clean; ANY
|
|
189
|
+
// non-residue change — tracked OR a hand-authored untracked file — is dirty.
|
|
190
|
+
// FAIL-CLOSED on any error: cannot determine cleanliness → treat as dirty
|
|
191
|
+
// (KEEP). This is the deletion-safe direction (spec
|
|
192
|
+
// worktree-reaper-untracked-blindspot, convergence BLOCKER): a transient
|
|
193
|
+
// `git status` failure must never make a worktree look reapable.
|
|
169
194
|
try {
|
|
170
|
-
return readGit(['-C', p, 'status', '--porcelain'], p)
|
|
195
|
+
return !classifyPorcelain(readGit(['-C', p, 'status', '--porcelain'], p), REAPER_RESIDUE_DENYLIST);
|
|
171
196
|
}
|
|
172
197
|
catch {
|
|
173
198
|
return false;
|
|
174
|
-
}
|
|
199
|
+
}
|
|
175
200
|
},
|
|
176
201
|
isMerged: (info) => {
|
|
177
202
|
const base = resolveBaseRef(readGit, repo);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentWorktreeGit.js","sourceRoot":"","sources":["../../src/monitoring/agentWorktreeGit.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"agentWorktreeGit.js","sourceRoot":"","sources":["../../src/monitoring/agentWorktreeGit.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-26T04:26:35.476Z",
|
|
5
|
+
"instarVersion": "1.3.668",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The stale-worktree reaper (`AgentWorktreeReaper`) no longer treats harmless leftover files as "uncommitted work." Its cleanliness check now uses the existing residue-aware `classifyPorcelain` with a NARROW, reaper-specific never-work denylist (`dist/`, `node_modules/`, `.cache/`, `.turbo/`, `*.tsbuildinfo`, `.metadata_never_index`, `.instar/instar-dev-traces/`) — fail-CLOSED on any git error (a transient `git status` failure can never make a worktree look reapable). A new per-path reclaim-failure breaker stops retrying a permanently-unremovable worktree forever (surfaced as `keep('reclaim-failed')`).
|
|
9
|
+
|
|
10
|
+
This fixes unbounded `.worktrees/` growth: on one agent, 246 of 289 worktrees were kept solely because of untracked droppings — overwhelmingly the `.metadata_never_index` Spotlight-exclusion marker that gets dropped into every worktree (so the file added to *reduce* indexing load was *blocking* the cleanup that reduces it). Real work is still always kept: ANY non-residue change — a tracked modification OR a hand-authored untracked file (including under `out/`/`build/`/`coverage/` or a `*.log`, which the narrow list deliberately excludes) — keeps the worktree.
|
|
11
|
+
|
|
12
|
+
## What to Tell Your User
|
|
13
|
+
|
|
14
|
+
If your agent's disk fills up with old throwaway worktrees (or a "machine overloaded" warning turns out to be a background file-indexer churning on a huge worktrees folder), the cleanup can now reclaim merged, idle worktrees whose only leftovers are build artifacts or the agent's own marker files — while never touching anything with real unsaved work. It stays off until you turn it on, and it can show you exactly the list it would remove before it deletes anything.
|
|
15
|
+
|
|
16
|
+
## Summary of New Capabilities
|
|
17
|
+
|
|
18
|
+
- Residue-aware, fail-closed worktree cleanliness check (a narrow never-delete list) so the cleanup reclaims droppings-only worktrees instead of hoarding them.
|
|
19
|
+
- A per-worktree failure breaker so an un-removable worktree is given up on after a few tries instead of being retried forever.
|
|
20
|
+
|
|
21
|
+
## Evidence
|
|
22
|
+
|
|
23
|
+
- `tests/unit/agent-worktree-reaper.test.ts` (31 green): residue-only→clean, narrow-residue→clean, tracked-mod→dirty/KEEP, untracked-source→dirty/KEEP, broad-entry (`build/`,`*.log`,`out/`,`coverage/`)→dirty/KEEP, git-error→fail-CLOSED/KEEP, breaker trip+emit-once+clear-on-success.
|
|
24
|
+
- Convergence (adversarial + lessons-aware + conformance gate) caught and resolved a deletion-safety BLOCKER (fail-open→fail-closed) + 2 MAJORs: `docs/specs/reports/worktree-reaper-untracked-blindspot-convergence.md`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Side-effects review — worktree-reaper-untracked-blindspot
|
|
2
|
+
|
|
3
|
+
Change: the AgentWorktreeReaper's `isClean` now treats reaper-residue-only worktrees (build artifacts + instar markers, esp. `.metadata_never_index`) as clean via the PURE `classifyPorcelain` + a NARROW `REAPER_RESIDUE_DENYLIST`, fail-CLOSED on git error; plus a per-path reclaim-failure breaker. Files: `src/monitoring/agentWorktreeGit.ts`, `src/monitoring/AgentWorktreeReaper.ts`, `tests/unit/agent-worktree-reaper.test.ts`.
|
|
4
|
+
|
|
5
|
+
1. **Over-block (reject legit inputs it shouldn't):** N/A in the gating sense — this LOOSENS an over-conservative KEEP gate. The "over-block" analog (keeping a reclaimable worktree) is the bug being fixed. No new over-block.
|
|
6
|
+
|
|
7
|
+
2. **Under-block (still misses failure modes):** A worktree whose ONLY change is a *non-residue* untracked file (a hand-authored `.ts`/`.md`/`.log`/`build/*` never `git add`ed) is still KEPT — by design (conservative; possibly-precious). The narrow denylist deliberately excludes `out/`/`build/`/`coverage/`/`*.log` so user-authored files there are never silently reaped. Multi-commit squash-merges are still reported unmerged → KEPT (pre-existing `git cherry` conservatism).
|
|
8
|
+
|
|
9
|
+
3. **Level-of-abstraction fit:** Correct layer. `isClean` is the reaper's per-worktree cleanliness signal; residue-awareness belongs exactly there. Reuses the existing tested PURE `classifyPorcelain` rather than a parallel re-implementation.
|
|
10
|
+
|
|
11
|
+
4. **Signal vs authority:** This is a deterministic policy evaluator over an objective git fact (porcelain + denylist), feeding a gate that is ANDed with `isMerged` (git cherry patch-id) + `isInUse`. No brittle string-matcher gains block authority; it REFINES a KEEP gate. Fail direction is the safety crux: **fail-CLOSED** (git error → dirty → KEEP), the opposite of the fail-open `makeWorktreeDirtyCheck` wrapper which would be unsafe for a deletion gate (the convergence BLOCKER).
|
|
12
|
+
|
|
13
|
+
5. **Interactions / shared consumers:** `isClean` (from `makeAgentWorktreeReaperDeps`) is shared by THREE consumers — the reaper (delete), and via `orphanedWorkGit.ts` the `OrphanedWorkSentinel` (preserve work) and any other caller. Widening "clean" to ignore the narrow never-work set is correct for all three (none should treat a marker-only worktree as holding work). `DEFAULT_RESIDUE_DENYLIST` is NOT modified, so the build-session-yield-safety killer's config-sourced list and other consumers are untouched. Tested: marker-only → clean; tracked diff → never hidden.
|
|
14
|
+
|
|
15
|
+
6. **External surfaces:** No new routes/messages. `GET /worktrees/agent-reaper` now reports more `reap-eligible` worktrees (and a new `reclaim-failed` keep reason when the breaker trips). A new `reclaim-breaker` event is emitted (consumed for observability only).
|
|
16
|
+
|
|
17
|
+
7. **Multi-machine posture:** Machine-local BY DESIGN. Worktrees live on one disk; the reaper only ever evaluates its own machine's `.worktrees/`. No replication/proxy/URL surface. (Cross-Machine Coherence: machine-local with reason.)
|
|
18
|
+
|
|
19
|
+
8. **Rollback cost:** Low. `agentWorktreeReaper.enabled: false` fully disables (existing knob); `dryRun: true` classifies without deleting (review the report first); `maxReclaimFailuresPerPath: 0` disables the breaker. The denylist is a code const (revert = one-line). No data migration. A reclaimed worktree's branch + commits remain in git (only the redundant checkout is removed), so even a wrong reap loses no committed work — and non-residue/tracked work is never reaped.
|
|
20
|
+
|
|
21
|
+
## Second-pass review (required — touches a destructive safety gate)
|
|
22
|
+
Convergence ran an adversarial + lessons-aware reviewer (see `docs/specs/reports/worktree-reaper-untracked-blindspot-convergence.md`). They caught a deletion-safety BLOCKER (fail-open→fail-closed), the broad-denylist hazard (→ narrow list), and the undisclosed OrphanedWorkSentinel consumer. ALL addressed in the implementation and pinned by unit tests (residue→clean, non-residue→dirty, broad-entry→dirty, git-error→KEEP, breaker trip+clear; 31 tests green). Concur with the resolved design.
|