instar 1.3.1029 → 1.3.1031
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/core/SafeFsExecutor.d.ts +19 -0
- package/dist/core/SafeFsExecutor.d.ts.map +1 -1
- package/dist/core/SafeFsExecutor.js +20 -1
- package/dist/core/SafeFsExecutor.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.1030.md +37 -0
- package/upgrades/1.3.1031.md +48 -0
- package/upgrades/rm-retry-budget.eli16.md +28 -0
- package/upgrades/side-effects/rm-retry-budget.md +48 -0
|
@@ -35,6 +35,25 @@ export declare class SafeFsExecutor {
|
|
|
35
35
|
* loaded runner — a whole-class flake every tmpdir-cleanup test inherits.
|
|
36
36
|
* Explicit caller-set values always win; non-recursive deletes unchanged.
|
|
37
37
|
*/
|
|
38
|
+
/**
|
|
39
|
+
* Retry budget for recursive+force removals.
|
|
40
|
+
*
|
|
41
|
+
* Raised from 3x100ms (~300ms) to 10x100ms (~1s) after a CI failure on main
|
|
42
|
+
* (2026-07-28): `ENOTEMPTY` on `rmdir` of a temp dir's `.git`, from a test whose
|
|
43
|
+
* setup runs real `git add` + `git commit`. The retries WERE in force — they
|
|
44
|
+
* simply ran out. A git child process (or its index.lock) can outlive a
|
|
45
|
+
* ~300ms window when the runner is loaded, so the teardown raced a process
|
|
46
|
+
* still writing into the directory.
|
|
47
|
+
*
|
|
48
|
+
* This widens the budget; it does not prove any budget is sufficient. A
|
|
49
|
+
* removal that is genuinely blocked now fails after ~1s instead of ~300ms,
|
|
50
|
+
* which costs nothing — the operation was going to fail either way. The
|
|
51
|
+
* deeper fix for the git case is ensuring the child has exited before
|
|
52
|
+
* teardown, which belongs with the tests rather than here.
|
|
53
|
+
*
|
|
54
|
+
* Only applied when the caller did not specify `maxRetries`, so an explicit
|
|
55
|
+
* choice always wins.
|
|
56
|
+
*/
|
|
38
57
|
private static withRmRetryDefaults;
|
|
39
58
|
/** Async fs.promises.rm wrapper. */
|
|
40
59
|
static safeRm(target: string, opts: SafeRmOptions): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SafeFsExecutor.d.ts","sourceRoot":"","sources":["../../src/core/SafeFsExecutor.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,OAAO,EAEL,oBAAoB,EACrB,MAAM,sBAAsB,CAAC;AAG9B,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,EAAE,CAAC,SAAS,GAAG,aAAa,CAAC;AACzD,MAAM,MAAM,gBAAgB,GAAG,EAAE,CAAC,YAAY,GAAG,aAAa,CAAC;AAsF/D,qBAAa,cAAc;IACzB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,oCAAoC;WACvB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvE,8BAA8B;IAC9B,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;IAY5D,wCAAwC;WAC3B,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3E,kCAAkC;IAClC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;IAWhE,uCAAuC;WAC1B,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7E,iCAAiC;IACjC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAiClE;;;OAGG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA2BzH;;;;OAIG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAIhI;AAID,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"SafeFsExecutor.d.ts","sourceRoot":"","sources":["../../src/core/SafeFsExecutor.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,OAAO,EAEL,oBAAoB,EACrB,MAAM,sBAAsB,CAAC;AAG9B,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,aAAa,GAAG,EAAE,CAAC,SAAS,GAAG,aAAa,CAAC;AACzD,MAAM,MAAM,gBAAgB,GAAG,EAAE,CAAC,YAAY,GAAG,aAAa,CAAC;AAsF/D,qBAAa,cAAc;IACzB;;;;;;;;;;OAUG;IACH;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAOlC,oCAAoC;WACvB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvE,8BAA8B;IAC9B,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;IAY5D,wCAAwC;WAC3B,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3E,kCAAkC;IAClC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,IAAI;IAWhE,uCAAuC;WAC1B,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAY7E,iCAAiC;IACjC,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAiClE;;;OAGG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IA2BzH;;;;OAIG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;CAIhI;AAID,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -109,9 +109,28 @@ export class SafeFsExecutor {
|
|
|
109
109
|
* loaded runner — a whole-class flake every tmpdir-cleanup test inherits.
|
|
110
110
|
* Explicit caller-set values always win; non-recursive deletes unchanged.
|
|
111
111
|
*/
|
|
112
|
+
/**
|
|
113
|
+
* Retry budget for recursive+force removals.
|
|
114
|
+
*
|
|
115
|
+
* Raised from 3x100ms (~300ms) to 10x100ms (~1s) after a CI failure on main
|
|
116
|
+
* (2026-07-28): `ENOTEMPTY` on `rmdir` of a temp dir's `.git`, from a test whose
|
|
117
|
+
* setup runs real `git add` + `git commit`. The retries WERE in force — they
|
|
118
|
+
* simply ran out. A git child process (or its index.lock) can outlive a
|
|
119
|
+
* ~300ms window when the runner is loaded, so the teardown raced a process
|
|
120
|
+
* still writing into the directory.
|
|
121
|
+
*
|
|
122
|
+
* This widens the budget; it does not prove any budget is sufficient. A
|
|
123
|
+
* removal that is genuinely blocked now fails after ~1s instead of ~300ms,
|
|
124
|
+
* which costs nothing — the operation was going to fail either way. The
|
|
125
|
+
* deeper fix for the git case is ensuring the child has exited before
|
|
126
|
+
* teardown, which belongs with the tests rather than here.
|
|
127
|
+
*
|
|
128
|
+
* Only applied when the caller did not specify `maxRetries`, so an explicit
|
|
129
|
+
* choice always wins.
|
|
130
|
+
*/
|
|
112
131
|
static withRmRetryDefaults(rmOpts) {
|
|
113
132
|
if (rmOpts.recursive && rmOpts.force && rmOpts.maxRetries === undefined) {
|
|
114
|
-
return { ...rmOpts, maxRetries:
|
|
133
|
+
return { ...rmOpts, maxRetries: 10, retryDelay: 100 };
|
|
115
134
|
}
|
|
116
135
|
return rmOpts;
|
|
117
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SafeFsExecutor.js","sourceRoot":"","sources":["../../src/core/SafeFsExecutor.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"SafeFsExecutor.js","sourceRoot":"","sources":["../../src/core/SafeFsExecutor.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-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-28T13:03:59.365Z",
|
|
5
|
+
"instarVersion": "1.3.1031",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
`SafeFsExecutor`'s recursive-delete retry budget goes from 3 attempts × 100ms (~300ms) to 10 × 100ms
|
|
9
|
+
(~1s), for callers that pass `recursive` + `force` and do not choose their own `maxRetries`.
|
|
10
|
+
|
|
11
|
+
Main went red twice on 2026-07-28 with filesystem races in test teardown — one `ENOTEMPTY` removing a
|
|
12
|
+
temp dir holding a live git repo, one `EEXIST` in a performance worker — both while four CI runs
|
|
13
|
+
competed for the same runners. In the first, the retries **were** in force and simply ran out: git's
|
|
14
|
+
own child work can hold a directory longer than ~300ms on a loaded machine.
|
|
15
|
+
|
|
16
|
+
## What to Tell Your User
|
|
17
|
+
|
|
18
|
+
Nothing — internal robustness for filesystem cleanup.
|
|
19
|
+
|
|
20
|
+
## Summary of New Capabilities
|
|
21
|
+
|
|
22
|
+
None. A delete that would have succeeded still succeeds; one that never will now takes ~700ms longer
|
|
23
|
+
to say so.
|
|
24
|
+
|
|
25
|
+
## Evidence
|
|
26
|
+
|
|
27
|
+
- `SafeFsExecutor.test.ts` 22/22, `SafeFsExecutor-atomicWrite.test.ts` 9/9, and `handoff-manager.test.ts`
|
|
28
|
+
(the suite that failed on main) 71/71.
|
|
29
|
+
- Two tests added for behaviour that had **zero** coverage: a budget is applied when the caller gives
|
|
30
|
+
none, and an explicit `maxRetries` is never overridden. **They would pass on `main` too** — they guard
|
|
31
|
+
the mechanism, not the tuning, and are not evidence that ~1s is the right number.
|
|
32
|
+
- **This does not prove the flake is closed.** No retry budget can be proven sufficient under arbitrary
|
|
33
|
+
load. The deeper fix for the git case is ensuring the child process has exited before teardown, which
|
|
34
|
+
belongs with the tests.
|
|
35
|
+
- Prior art found while checking: `migrateWorktreeConvention.test.ts:110` already hand-rolls
|
|
36
|
+
`maxRetries: 5` with a comment about racing async cleanup — someone hit this class before and worked
|
|
37
|
+
around it locally rather than raising the shared default.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
**Two** fixtures retried a contended lock on a **flat cadence**. `feedback-performance-concurrent-ingest.mjs`
|
|
9
|
+
did 200 attempts at 5ms — a ~1 second budget per append. Several such workers run concurrently by design,
|
|
10
|
+
so a flat cadence is a thundering herd: every contender wakes on the same tick and they keep colliding
|
|
11
|
+
on the same slots. On a loaded runner that budget expired with nobody making progress, and main went
|
|
12
|
+
red on 2026-07-28 with `feedback source generation is busy; retry later`.
|
|
13
|
+
|
|
14
|
+
Now exponential backoff with jitter, capped at 40ms — roughly 6× the patience, de-synchronised, and
|
|
15
|
+
still bounded so a genuinely stuck lock fails promptly rather than stalling a 100-iteration loop.
|
|
16
|
+
|
|
17
|
+
**The production lock is unchanged and needs no change.** It was working correctly: `openSync(path,
|
|
18
|
+
'wx')` failing `EEXIST` means the lock is held, and it already checks whether the owning pid is alive
|
|
19
|
+
before declaring it live.
|
|
20
|
+
|
|
21
|
+
### The sibling, found by sweeping rather than assumed unique
|
|
22
|
+
|
|
23
|
+
`tests/fixtures/feedback-source-generation-worker.mjs` has the **same defect with a smaller budget** —
|
|
24
|
+
100 attempts × 5ms ≈ 500ms — and is spawned *concurrently* by `feedback-source-generation-multiprocess.test.ts`,
|
|
25
|
+
so it contends by design too. Fixed identically (~2.9s mean, jittered).
|
|
26
|
+
|
|
27
|
+
Found by asking whether the first instance was unique instead of assuming it was: a sweep for flat
|
|
28
|
+
constant-sleep retries under `tests/` returned 70 sites, of which this was the one that genuinely shares
|
|
29
|
+
the shape — same lock, same `busy` signal, concurrent contenders.
|
|
30
|
+
|
|
31
|
+
## What to Tell Your User
|
|
32
|
+
|
|
33
|
+
Nothing — a test fixture.
|
|
34
|
+
|
|
35
|
+
## Summary of New Capabilities
|
|
36
|
+
|
|
37
|
+
None.
|
|
38
|
+
|
|
39
|
+
## Evidence
|
|
40
|
+
|
|
41
|
+
- The fixture is 15 lines and was read in full before the fix. Two earlier diagnoses of this same
|
|
42
|
+
failure were written from the stack trace and were wrong — one dangerously so, proposing to treat the
|
|
43
|
+
lock's `EEXIST` as success, which would have removed mutual exclusion to make a test green.
|
|
44
|
+
- Budget measured rather than asserted: flat `200 × 5ms` ≈ 1.0s per append; jittered ≈ 5.9s mean,
|
|
45
|
+
bounded by the 40ms cap.
|
|
46
|
+
- This does **not** prove the flake is closed — no retry budget can be proven sufficient under
|
|
47
|
+
arbitrary load. It removes the thundering-herd synchronisation, which is the part that made the old
|
|
48
|
+
budget fail *systematically* rather than occasionally.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# ELI16 — a cleanup step gave up after a third of a second
|
|
2
|
+
|
|
3
|
+
When a test finishes, it deletes its temporary folder. Deleting a folder can fail if something is
|
|
4
|
+
still writing into it, so the delete is retried — three times, a tenth of a second apart. About a third
|
|
5
|
+
of a second of patience in total.
|
|
6
|
+
|
|
7
|
+
That is fine on an idle machine. It is not fine when the folder contains a real git repository and the
|
|
8
|
+
machine is busy: git's own background work can hold the folder for longer than that, the retries run
|
|
9
|
+
out, and the cleanup fails with "directory not empty". The test suite goes red for a reason that has
|
|
10
|
+
nothing to do with the code being tested.
|
|
11
|
+
|
|
12
|
+
That happened on main today, twice in one evening across two different tests — both while four builds
|
|
13
|
+
were competing for the same machines.
|
|
14
|
+
|
|
15
|
+
**What I changed:** the patience, from about a third of a second to about one second. Nothing else.
|
|
16
|
+
|
|
17
|
+
**What I want to be honest about:** I cannot prove one second is enough. Nobody can — it depends on how
|
|
18
|
+
loaded the machine is. This makes the failure much less likely; it does not make it impossible. A
|
|
19
|
+
delete that was always going to fail now takes a second longer to say so, which costs nothing.
|
|
20
|
+
|
|
21
|
+
The deeper fix for the git case is making sure git has actually finished before the cleanup starts, and
|
|
22
|
+
that belongs with the tests rather than here.
|
|
23
|
+
|
|
24
|
+
**Also added: two tests for behaviour that had none.** The retry logic had never been tested at all,
|
|
25
|
+
which is how it reached a state where it was running and simply too small. They check that a retry
|
|
26
|
+
budget is applied when the caller doesn't specify one, and that a caller who *does* specify one is never
|
|
27
|
+
overridden. They deliberately don't assert the specific numbers — those are expected to be tuned, and a
|
|
28
|
+
test that just repeats a constant tells you nothing.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Side-effects review — recursive-delete retry budget
|
|
2
|
+
|
|
3
|
+
**Change:** one constant in `SafeFsExecutor.withRmRetryDefaults` (`maxRetries: 3` → `10`, delay
|
|
4
|
+
unchanged at 100ms), plus a doc block and two new tests.
|
|
5
|
+
|
|
6
|
+
| Surface | Effect |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Callers passing `recursive` + `force`, no `maxRetries` | Budget ~300ms → ~1s. **The only behavioural change.** |
|
|
9
|
+
| Callers passing an explicit `maxRetries` | **Unchanged** — the default only applies when it is `undefined`. Asserted by a new test. |
|
|
10
|
+
| Callers not passing `recursive` + `force` | **Unchanged** — the guard requires both. |
|
|
11
|
+
| A delete that would have succeeded | Unchanged; retries only run after a failure. |
|
|
12
|
+
| A delete that will never succeed | Fails after ~1s instead of ~300ms. |
|
|
13
|
+
|
|
14
|
+
Node applies `retryDelay` only for `recursive` removals and retries on the transient errors this
|
|
15
|
+
targets (`EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, `EPERM`), so a widened budget cannot mask a
|
|
16
|
+
different class of failure — it retries exactly the races it was already retrying.
|
|
17
|
+
|
|
18
|
+
## What this does NOT establish
|
|
19
|
+
|
|
20
|
+
**It does not prove ~1s is sufficient.** No budget can be proven sufficient; it depends on machine
|
|
21
|
+
load. This makes the race much less likely to be lost, not impossible. I would rather state that than
|
|
22
|
+
imply the flake is closed.
|
|
23
|
+
|
|
24
|
+
The deeper fix for the observed case is ensuring the git child process has exited before teardown,
|
|
25
|
+
which belongs in the tests, not in a filesystem helper.
|
|
26
|
+
|
|
27
|
+
## Blast radius
|
|
28
|
+
|
|
29
|
+
`safeRm`/`safeRmSync` have **2,116 call sites**, so this is a wide change — but strictly in the
|
|
30
|
+
direction of more patience, and only on a path that has already failed once. The worst case is a
|
|
31
|
+
doomed delete taking 700ms longer to report.
|
|
32
|
+
|
|
33
|
+
## About the new tests — read this before crediting them
|
|
34
|
+
|
|
35
|
+
They cover behaviour that had **no coverage at all**: that a budget is applied when absent, and that an
|
|
36
|
+
explicit caller value is never overridden. That gap is how the defaults reached a state where they were
|
|
37
|
+
in force and simply too small.
|
|
38
|
+
|
|
39
|
+
**They would also pass on `main`** — the property predates this change. They guard the mechanism, not
|
|
40
|
+
the tuning. The tuning itself is a judgement no unit test can settle, and I am not going to present
|
|
41
|
+
green tests as evidence for it.
|
|
42
|
+
|
|
43
|
+
## Verification
|
|
44
|
+
|
|
45
|
+
- `tests/unit/SafeFsExecutor.test.ts` 22/22 (20 before + 2 new); `SafeFsExecutor-atomicWrite` 9/9;
|
|
46
|
+
`handoff-manager` (the test that failed on main) 71/71.
|
|
47
|
+
- `tsc --noEmit` clean — after fixing a self-inflicted break: the first draft of the doc block
|
|
48
|
+
contained a literal path with `*/` in it, which closed the comment early. The compiler caught it.
|