instar 1.3.306 → 1.3.308

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.
@@ -24,6 +24,18 @@ export interface SafeFsOptions {
24
24
  export type SafeRmOptions = fs.RmOptions & SafeFsOptions;
25
25
  export type SafeRmDirOptions = fs.RmDirOptions & SafeFsOptions;
26
26
  export declare class SafeFsExecutor {
27
+ /**
28
+ * Recursive force-deletes default to fs.rm's native transient-error retry
29
+ * (ENOTEMPTY/EBUSY/EPERM). A recursive tree delete racing a concurrent
30
+ * writer (git finishing an object write, an mtime scanner walking the
31
+ * tree) fails ENOTEMPTY exactly once and succeeds milliseconds later —
32
+ * fs.rm retries this class natively, but only when maxRetries is set.
33
+ * Live: CI shard failure 2026-06-05 in handoff-manager.test.ts cleanup
34
+ * (`ENOTEMPTY: directory not empty, rmdir '/tmp/handoff-…/.git'`) on a
35
+ * loaded runner — a whole-class flake every tmpdir-cleanup test inherits.
36
+ * Explicit caller-set values always win; non-recursive deletes unchanged.
37
+ */
38
+ private static withRmRetryDefaults;
27
39
  /** Async fs.promises.rm wrapper. */
28
40
  static safeRm(target: string, opts: SafeRmOptions): Promise<void>;
29
41
  /** Sync fs.rmSync wrapper. */
@@ -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,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,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"}
@@ -98,12 +98,29 @@ function guard(target, operation, fnName) {
98
98
  }
99
99
  // ── Public API ──────────────────────────────────────────────────────
100
100
  export class SafeFsExecutor {
101
+ /**
102
+ * Recursive force-deletes default to fs.rm's native transient-error retry
103
+ * (ENOTEMPTY/EBUSY/EPERM). A recursive tree delete racing a concurrent
104
+ * writer (git finishing an object write, an mtime scanner walking the
105
+ * tree) fails ENOTEMPTY exactly once and succeeds milliseconds later —
106
+ * fs.rm retries this class natively, but only when maxRetries is set.
107
+ * Live: CI shard failure 2026-06-05 in handoff-manager.test.ts cleanup
108
+ * (`ENOTEMPTY: directory not empty, rmdir '/tmp/handoff-…/.git'`) on a
109
+ * loaded runner — a whole-class flake every tmpdir-cleanup test inherits.
110
+ * Explicit caller-set values always win; non-recursive deletes unchanged.
111
+ */
112
+ static withRmRetryDefaults(rmOpts) {
113
+ if (rmOpts.recursive && rmOpts.force && rmOpts.maxRetries === undefined) {
114
+ return { ...rmOpts, maxRetries: 3, retryDelay: 100 };
115
+ }
116
+ return rmOpts;
117
+ }
101
118
  /** Async fs.promises.rm wrapper. */
102
119
  static async safeRm(target, opts) {
103
120
  const { operation, ...rmOpts } = opts;
104
121
  const canonical = guard(target, operation, 'safeRm');
105
122
  try {
106
- await fsp.rm(target, rmOpts);
123
+ await fsp.rm(target, SafeFsExecutor.withRmRetryDefaults(rmOpts));
107
124
  audit('safeRm', operation, canonical, 'allowed');
108
125
  }
109
126
  catch (err) {
@@ -116,7 +133,7 @@ export class SafeFsExecutor {
116
133
  const { operation, ...rmOpts } = opts;
117
134
  const canonical = guard(target, operation, 'safeRmSync');
118
135
  try {
119
- fs.rmSync(target, rmOpts);
136
+ fs.rmSync(target, SafeFsExecutor.withRmRetryDefaults(rmOpts));
120
137
  audit('safeRmSync', operation, canonical, 'allowed');
121
138
  }
122
139
  catch (err) {
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.306",
3
+ "version": "1.3.308",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -45,6 +45,23 @@ const TRACES_DIR = path.join(ROOT, '.instar', 'instar-dev-traces');
45
45
  // DECISIONS_DIR instead: distinct filenames can never conflict.
46
46
  // (The frozen legacy file remains at .instar/instar-dev-decisions.jsonl.)
47
47
  const DECISIONS_DIR = path.join(ROOT, '.instar', 'instar-dev-decisions');
48
+
49
+ // Set by writeDecisionAudit; consumed by the process 'exit' handler that
50
+ // finalizes the entry's verdict. BOTH the declaration AND the handler
51
+ // registration live here, above the top-level audit call site — placed
52
+ // after it, the declaration TDZ-throws inside writeDecisionAudit's
53
+ // try/catch, and the handler registration is never even reached when
54
+ // blockCommit exits first (top-level statements run in source order).
55
+ let pendingAuditEntry = null;
56
+ process.on('exit', (code) => {
57
+ if (!pendingAuditEntry) return;
58
+ try {
59
+ const { entryPath, entryData } = pendingAuditEntry;
60
+ entryData.verdict = code === 0 ? 'pass' : 'blocked';
61
+ fs.writeFileSync(entryPath, JSON.stringify(entryData, null, 2) + '\n');
62
+ execSync(`git add ${JSON.stringify(path.relative(ROOT, entryPath))}`, { cwd: ROOT });
63
+ } catch { /* best-effort — 'pending' is still more truthful than no verdict */ }
64
+ });
48
65
  const WINDOW_MS = 60 * 60 * 1000; // 60 minutes
49
66
  const MIN_ARTIFACT_CHARS = 200;
50
67
 
@@ -811,23 +828,31 @@ function writeDecisionAudit({ slug, suggestedTier, declaredTier, riskFloor, risk
811
828
  while (fs.existsSync(entryPath)) {
812
829
  entryPath = path.join(DECISIONS_DIR, `${ts.replace(/[:.]/g, '-')}-${safeSlug}-${n++}.json`);
813
830
  }
814
- fs.writeFileSync(
815
- entryPath,
816
- JSON.stringify({
817
- ts,
818
- slug,
819
- suggestedTier,
820
- declaredTier,
821
- // riskFloor (the number) keeps the entry self-contained for later review
822
- // without re-running the classifier — not just the derived belowFloor.
823
- riskFloor,
824
- riskFloorReasons,
825
- belowFloor,
826
- files,
827
- loc,
828
- }, null, 2) + '\n',
829
- );
831
+ const entryData = {
832
+ ts,
833
+ slug,
834
+ suggestedTier,
835
+ declaredTier,
836
+ // riskFloor (the number) keeps the entry self-contained for later review
837
+ // without re-running the classifier — not just the derived belowFloor.
838
+ riskFloor,
839
+ riskFloorReasons,
840
+ belowFloor,
841
+ files,
842
+ loc,
843
+ // Finalized by the process exit handler below: 'pass' when the gate
844
+ // allowed the commit, 'blocked' otherwise. The riding-the-retry design
845
+ // (a blocked evaluation's entry rides the next successful commit, see
846
+ // header comment) is deliberate — but without a verdict, a rode-along
847
+ // entry written under a stale/unresolved trace slug READS as a real
848
+ // shipped decision for that slug. Live recurrence (2026-06-05): both
849
+ // echo (#836) and codey (#842) shipped mislabeled "unknown"/foreign-slug
850
+ // entries in one day. The verdict makes every entry self-describing.
851
+ verdict: 'pending',
852
+ };
853
+ fs.writeFileSync(entryPath, JSON.stringify(entryData, null, 2) + '\n');
830
854
  execSync(`git add ${JSON.stringify(path.relative(ROOT, entryPath))}`, { cwd: ROOT });
855
+ pendingAuditEntry = { entryPath, entryData };
831
856
  return entryPath;
832
857
  } catch {
833
858
  // best-effort — never block on audit I/O
@@ -835,6 +860,13 @@ function writeDecisionAudit({ slug, suggestedTier, declaredTier, riskFloor, risk
835
860
  }
836
861
  }
837
862
 
863
+ // ── Verdict finalization ──────────────────────────────────────────────────
864
+ // The process 'exit' handler that finalizes each entry's verdict is
865
+ // registered next to the pendingAuditEntry declaration near the top of this
866
+ // file (it must be registered BEFORE the top-level gate flow can exit). One
867
+ // hook covers every exit path: enforceTier1's process.exit(0), the Tier-2
868
+ // fall-through, and every blockCommit.
869
+
838
870
  // ─── Tier-1 lite enforcement ──────────────────────────────────────────────
839
871
  // Tier-1 requirement set: a staged ELI16 (trace.eli16Path) passing the length
840
872
  // check + a staged side-effects artifact (trace.sideEffectsPath, sha-matched if
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-05T15:43:57.729Z",
5
- "instarVersion": "1.3.306",
4
+ "generatedAt": "2026-06-05T16:13:14.546Z",
5
+ "instarVersion": "1.3.308",
6
6
  "entryCount": 198,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,20 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The instar-dev pre-commit gate's decision-audit entries gain a verdict field ('pass' | 'blocked', written as 'pending' and finalized by a process exit hook that also re-stages the corrected file). The riding-the-retry design is unchanged — blocked-run entries still ride the next successful commit — but each entry is now self-describing.
9
+
10
+ ## What to Tell Your User
11
+
12
+ Nothing user-visible — contributor audit hygiene. Gate audit records that ride into a PR from earlier blocked attempts (often under an unresolved or stale slug) are now labeled as blocked evaluations instead of reading like real shipped decisions.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - Decision-audit entries carry verdict: pass | blocked (pending only if finalization itself failed). Reviewers can distinguish shipped decisions from rode-along blocked evaluations at a glance.
17
+
18
+ ## Evidence
19
+
20
+ Live recurrence (2026-06-05, twice in one day): echo's PR #836 swept in a blocked-attempt entry labeled with a DIFFERENT PR's slug (the then-freshest stale trace), and codey's PR #842 shipped an "unknown"-slug entry from a pre-trace gate run — both read as real decisions and needed review-time explanation. Pinned by 2 new sandbox tests in tests/unit/instar-dev-precommit-audit-staging.test.ts (blocked run finalizes 'blocked' incl. the STAGED copy; passing Tier-1 run finalizes 'pass') alongside the existing 4; the development itself caught the source-order trap twice (TDZ on the shared variable, exit-before-registration on the hook) — both now documented in code comments and covered by the blocked-path test.
@@ -0,0 +1,20 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ SafeFsExecutor's safeRm/safeRmSync default fs.rm's native transient-error retry (maxRetries 3, retryDelay 100ms) for recursive+force deletes when the caller didn't set maxRetries. Explicit values win; non-recursive deletes unchanged.
9
+
10
+ ## What to Tell Your User
11
+
12
+ Nothing user-visible — internal robustness. Deleting a directory tree that something else is briefly touching (the classic "directory not empty" race) now retries for a moment instead of failing, which removes a whole class of flaky CI failures and transient cleanup errors.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - All recursive force-deletes through the SafeFsExecutor funnel tolerate transient ENOTEMPTY/EBUSY races (3 retries x 100ms) by default.
17
+
18
+ ## Evidence
19
+
20
+ Live CI failure (2026-06-05, PR #844's first run): handoff-manager.test.ts cleanup failed ENOTEMPTY rmdir on /tmp/handoff-.../.git on a loaded shard — a green change turned red by a cleanup race every tmpdir test inherits. Pinned by 3 new tests in tests/unit/SafeFsExecutor.test.ts (race-window convergence, explicit maxRetries 0 respected, non-recursive unchanged).
@@ -0,0 +1,11 @@
1
+ # Gate audit entries now say whether the commit actually passed
2
+
3
+ Every gated commit writes a small audit record — which tier the change declared, what the risk heuristic suggested, how big the diff was. By design, a record written during a BLOCKED attempt also survives: it gets staged, and when the developer fixes the problem and commits again, the old record rides along. The intent was honest bookkeeping — every gate evaluation leaves a trace.
4
+
5
+ The problem: nothing in the record said whether the evaluation passed or was blocked. And blocked attempts often run before the developer's trace file is fully resolved, so the record gets written under the wrong name — the slug says "unknown", or worse, it carries the slug of some OTHER pull request whose stale trace happened to be the freshest file at that moment. The result reads like a real shipped decision for a change that never shipped under that name. This bit twice in one day: Echo's registry-fix PR carried a record labeled with a different PR's slug, and Codey's header PR carried an "unknown" record — both rode into main as confusing audit noise, and both had to be explained in review.
6
+
7
+ The fix keeps the deliberate riding-the-retry design and makes every record self-describing: a **verdict** field, finalized the moment the gate process exits. Records start as "pending" when written, and a process exit hook — one hook covering every way the gate can finish — rewrites them as "pass" or "blocked" and re-stages the corrected file. A reviewer who sees verdict "blocked" next to a foreign slug now knows exactly what they're looking at: a failed evaluation under a stale trace, not a shipped decision.
8
+
9
+ Two implementation traps are documented in the code because both actually fired during development: the shared variable and the exit hook must both live ABOVE the gate's main flow in the file, because the gate runs top-to-bottom and can exit (blocked) before ever reaching code placed lower down. The first draft had the hook at the bottom; blocked runs exited before the hook was registered, and the verdict silently stayed "pending" — caught by the new tests.
10
+
11
+ Nothing changes about when records are written, staged, or how files are named. Old records without a verdict field remain valid history. Two new tests pin both sides: a blocked run's record finalizes as "blocked" (including the staged copy), and a passing Tier-1 run's record finalizes as "pass".
@@ -0,0 +1,7 @@
1
+ # Deleting a busy folder no longer fails the whole test run
2
+
3
+ When the system deletes a folder tree (a test's temporary directory, an old worktree), something else is occasionally still touching a file inside it at that exact moment — git finishing a write, a file scanner mid-walk. The delete then fails with "directory not empty" even though trying again fifty milliseconds later would succeed. Node's built-in delete function knows about this exact situation and can retry automatically — but only if the caller asks for retries, and ours never did.
4
+
5
+ This bit us today in CI: a test suite's cleanup tried to delete its temporary git repo while something still held the .git folder, failed once, and turned a completely green change into a red build. Any test that cleans up a temporary directory inherits this lottery ticket, and on a loaded CI runner the lottery pays out regularly.
6
+
7
+ The fix goes in the one funnel every delete already passes through (the safety wrapper that guards against deleting the wrong thing): recursive force-deletes now default to three quick retries, a third of a second of patience total. Explicit caller settings always win — passing zero retries keeps the old fail-fast behavior — and non-recursive deletes are untouched. Three tests pin the behavior: a delete racing a concurrent writer converges, an explicit zero is respected, and non-recursive semantics are unchanged.
@@ -0,0 +1,41 @@
1
+ # Side-Effects Review — Gate decision-audit verdict finalization
2
+
3
+ **Version / slug:** `gate-blocked-audit-hygiene`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `instar-echo`
6
+
7
+ ## Summary
8
+
9
+ `writeDecisionAudit` writes entries with `verdict: 'pending'` and records `{entryPath, entryData}` in a module variable; a `process.on('exit')` hook (registered next to the variable, ABOVE the gate's top-level flow) rewrites the entry with `verdict: code === 0 ? 'pass' : 'blocked'` and re-stages it. Entry naming, staging, timing, and the riding-the-retry property are unchanged.
10
+
11
+ ## Decision-point inventory
12
+
13
+ - Entry schema — extended — new `verdict` field ('pending' at write; finalized at exit). Additive: old entries without the field remain valid; no reader migration (the decision-audit-presence CI check matches by path, not schema — verified, its 9 tests untouched and green).
14
+ - Exit hook — added — one hook covers every exit path (enforceTier1's exit(0), Tier-2 fall-through, every blockCommit's exit(1)); synchronous-only work; its own try/catch leaves 'pending' on failure (still more truthful than no verdict).
15
+ - Source-order placement — the variable AND the hook registration live above the top-level audit call site. Both failure modes fired in development: a below-call-site declaration TDZ-throws inside writeDecisionAudit's try/catch (silently skipping tracking), and a below-flow registration is never reached when blockCommit exits early (verdict stayed 'pending' — caught by the new blocked-path test).
16
+
17
+ ## Direction of failure
18
+
19
+ - Old failure: rode-along entries from blocked runs (often under 'unknown'/foreign slugs) read as real shipped decisions — twice in one day (echo #836, codey #842).
20
+ - New behavior: every entry self-describes its outcome.
21
+ - Conservative direction: a finalization failure leaves 'pending' — ambiguous but honest; never a wrong verdict.
22
+
23
+ ## Side-effects checklist
24
+
25
+ 1. **Over-block:** none — the gate's pass/block decisions are untouched; this only records them.
26
+ 2. **Exit-hook safety:** synchronous fs/execSync only (required in 'exit' handlers); wrapped in try/catch; cannot change the exit code (the 'exit' event can't).
27
+ 3. **Double-stage:** the entry is git-added at write AND at finalize — idempotent (same path, updated content).
28
+ 4. **CI interplay:** decision-audit-presence-check matches entries by PATH under .instar/instar-dev-decisions/ — schema-agnostic; its tests run green against the new field.
29
+ 5. **Level-of-abstraction fit:** the verdict is determined by the process outcome, not by threading state through every blockCommit call site — one mechanism, all paths.
30
+ 6. **External surfaces:** none — local gate script + committed JSON records.
31
+ 7. **Rollback cost:** revert; entries return to verdict-less (old shape), already-committed verdict entries remain valid.
32
+
33
+ ## Scope not taken
34
+
35
+ - No slug-resolution improvement for blocked runs (the verdict defuses the mislabeling harm; resolving the "right" slug for an unmatched trace is guesswork).
36
+ - No retroactive verdict backfill of historical entries.
37
+ - No blocked-entry relocation/exclusion — riding-the-retry stays (deliberate #827-era design: every evaluation leaves a committed trace).
38
+
39
+ ## Rollback
40
+
41
+ Revert the commit.
@@ -0,0 +1,40 @@
1
+ # Side-Effects Review — SafeFsExecutor recursive-delete retry defaults
2
+
3
+ **Version / slug:** `safefs-rm-retry-default`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `instar-echo`
6
+
7
+ ## Summary
8
+
9
+ New private `withRmRetryDefaults`: when a safeRm/safeRmSync call is `recursive && force` and the caller did NOT set `maxRetries`, default `{maxRetries: 3, retryDelay: 100}` (fs.rm's native transient-error retry). Guard, audit, and error propagation unchanged.
10
+
11
+ ## Decision-point inventory
12
+
13
+ - `withRmRetryDefaults` — added — fills only `undefined`; explicit values (incl. 0) win.
14
+ - `safeRm` / `safeRmSync` — modified — options pass through the helper.
15
+ - `safeRmdirSync`, `safeUnlink*`, guard/audit paths — untouched.
16
+
17
+ ## Direction of failure
18
+
19
+ - Old: a transient ENOTEMPTY/EBUSY race failed the delete immediately (CI flake class; live shard failure 2026-06-05).
20
+ - New: up to 3 retries over ~300ms; a PERSISTENT error still throws identically (same error, same audit 'denied' record).
21
+ - Conservative direction: deletes the caller asked for succeed slightly more often; nothing is deleted that wasn't requested — the guard runs BEFORE any retry and the target path never changes.
22
+
23
+ ## Side-effects checklist
24
+
25
+ 1. **Latency:** worst case +300ms on a genuinely failing recursive delete — negligible against the operations involved.
26
+ 2. **Semantics:** retry only widens the success window of the SAME operation; no new deletion scope. SourceTreeGuard evaluation is unaffected (it runs once, before).
27
+ 3. **Race-with-writer behavior:** a writer that keeps writing past the window still fails the delete with the original error — honest failure preserved.
28
+ 4. **Caller control:** explicit `maxRetries` (incl. 0 for fail-fast) is never overridden — pinned by test.
29
+ 5. **Funnel placement:** single chokepoint benefits every existing and future caller — no per-callsite churn.
30
+ 6. **External surfaces:** none.
31
+ 7. **Rollback:** revert; behavior returns to fail-fast.
32
+
33
+ ## Scope not taken
34
+
35
+ - No retry on safeUnlink/safeRmdirSync (single-entry ops don't exhibit the tree-walk race).
36
+ - No backoff tuning knob (constants suffice; revisit only with evidence).
37
+
38
+ ## Rollback
39
+
40
+ Revert the commit.