@riddledc/riddle-proof 0.5.37 → 0.5.38

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/README.md CHANGED
@@ -82,21 +82,25 @@ updates Discord, OpenClaw, GitHub, or another integration.
82
82
 
83
83
  The packaged proof-run setup uses isolated git worktrees for before and after
84
84
  states. By default those worktrees now live under
85
- `/tmp/.riddle-proof-worktrees`, with dependency caches under the matching local
86
- temp root. This keeps repeated `node_modules` cache materialization on local
87
- scratch storage instead of walking large dependency trees on EFS or other shared
88
- workspace filesystems.
85
+ `/var/tmp/riddle-proof/.riddle-proof-worktrees`, with dependency caches under
86
+ the matching disk-backed scratch root. This keeps repeated `node_modules` cache
87
+ materialization off tmpfs `/tmp` and away from EFS or other shared workspace
88
+ filesystems.
89
89
 
90
90
  Set `RIDDLE_PROOF_WORKTREE_ROOT` to choose an explicit location. Set
91
91
  `RIDDLE_PROOF_USE_WORKSPACE_WORKTREE_ROOT=1` to keep the previous behavior of
92
- placing proof worktrees next to the active repository.
92
+ placing proof worktrees next to the active repository. Set
93
+ `RIDDLE_PROOF_SCRATCH_ROOT` to choose the scratch parent, or
94
+ `RIDDLE_PROOF_USE_TMP_SCRATCH=1` to force tmp-backed scratch for a short-lived
95
+ test.
93
96
 
94
97
  When local scratch storage is low, setup prunes stale
95
98
  `riddle-proof-*` worktrees from the scratch root before creating the next run.
96
99
  This preserves the dependency cache for speed while avoiding old failed runs
97
- filling `/tmp`. Set `RIDDLE_PROOF_KEEP_SCRATCH_WORKTREES=1` to disable that
98
- cleanup for debugging, or tune the low-space threshold with
99
- `RIDDLE_PROOF_MIN_SCRATCH_FREE_MB`.
100
+ filling the scratch disk. Setup also records scratch disk snapshots in the run
101
+ state so disk blockers are visible during proof inspection. Set
102
+ `RIDDLE_PROOF_KEEP_SCRATCH_WORKTREES=1` to disable that cleanup for debugging,
103
+ or tune the low-space threshold with `RIDDLE_PROOF_MIN_SCRATCH_FREE_MB`.
100
104
 
101
105
  ## Capture Diagnostics
102
106
 
@@ -15,6 +15,8 @@ import {
15
15
  import path from "node:path";
16
16
  import { fileURLToPath } from "node:url";
17
17
 
18
+ const DEFAULT_RIDDLE_PROOF_SCRATCH_ROOT = "/var/tmp/riddle-proof";
19
+
18
20
  function commandEnv() {
19
21
  return { ...process.env, HOME: "/root" };
20
22
  }
@@ -58,6 +60,26 @@ export function uniqueToken(now = new Date()) {
58
60
  return `${stamp}-${randomUUID().slice(0, 8)}`;
59
61
  }
60
62
 
63
+ function envFlag(name, defaultValue = false) {
64
+ const raw = String(process.env[name] || "").trim().toLowerCase();
65
+ if (["1", "true", "yes", "on"].includes(raw)) return true;
66
+ if (["0", "false", "no", "off"].includes(raw)) return false;
67
+ return defaultValue;
68
+ }
69
+
70
+ export function riddleProofScratchRoot() {
71
+ const configured = (process.env.RIDDLE_PROOF_SCRATCH_ROOT || "").trim();
72
+ if (configured) return path.resolve(configured);
73
+ if (envFlag("RIDDLE_PROOF_USE_TMP_SCRATCH", false)) {
74
+ return path.join("/tmp", "riddle-proof");
75
+ }
76
+ return DEFAULT_RIDDLE_PROOF_SCRATCH_ROOT;
77
+ }
78
+
79
+ export function defaultRiddleProofWorktreeRoot() {
80
+ return path.join(riddleProofScratchRoot(), ".riddle-proof-worktrees");
81
+ }
82
+
61
83
  export function workspaceRoots({ workspaceRoot = "", currentRepoDir = "" } = {}) {
62
84
  const roots = [];
63
85
  for (const candidate of [
@@ -332,7 +354,7 @@ function dependencyCacheRoot(projectDir) {
332
354
  if (worktreeIndex >= 0) {
333
355
  return path.join(resolved.slice(0, worktreeIndex), ".riddle-proof-deps-cache");
334
356
  }
335
- return path.join(path.dirname(resolved), ".riddle-proof-deps-cache");
357
+ return path.join(riddleProofScratchRoot(), ".riddle-proof-deps-cache");
336
358
  }
337
359
 
338
360
  function dependencyCacheKey(fingerprint, installCmd) {
@@ -497,6 +519,15 @@ async function main() {
497
519
  case "dependency-fingerprint":
498
520
  ok({ fingerprint: computeDependencyFingerprint(payload.projectDir) });
499
521
  return;
522
+ case "scratch-root":
523
+ ok({
524
+ scratchRoot: riddleProofScratchRoot(),
525
+ worktreeRoot: defaultRiddleProofWorktreeRoot(),
526
+ });
527
+ return;
528
+ case "dependency-cache-root":
529
+ ok({ cacheRoot: dependencyCacheRoot(payload.projectDir || process.cwd()) });
530
+ return;
500
531
  default:
501
532
  throw new Error(`Unsupported command: ${command}`);
502
533
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.5.37",
3
+ "version": "0.5.38",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -1,9 +1,9 @@
1
1
  """Setup: create worktrees, install deps, validate args, write state.
2
2
 
3
- Idempotent — safe to re-run. Creates per-run worktrees under the active
4
- local temp storage by default:
5
- /tmp/.riddle-proof-worktrees/riddle-proof-<run_id>-before
6
- /tmp/.riddle-proof-worktrees/riddle-proof-<run_id>-after
3
+ Idempotent — safe to re-run. Creates per-run worktrees under disk-backed
4
+ scratch storage by default:
5
+ /var/tmp/riddle-proof/.riddle-proof-worktrees/riddle-proof-<run_id>-before
6
+ /var/tmp/riddle-proof/.riddle-proof-worktrees/riddle-proof-<run_id>-after
7
7
  """
8
8
 
9
9
  import json, subprocess as sp, os, sys, shutil, time, tempfile
@@ -24,6 +24,7 @@ SAFE_RUN_ID = ''.join(ch if ch.isalnum() or ch in ('-', '_') else '-' for ch in
24
24
 
25
25
  AFTER_WORKTREE_BRANCH = 'riddle-proof/' + SAFE_RUN_ID + '-after'
26
26
  LEGACY_WORKTREE_DIRS = ('/tmp/riddle-proof-before', '/tmp/riddle-proof-after')
27
+ DEFAULT_SCRATCH_ROOT = '/var/tmp/riddle-proof'
27
28
 
28
29
  if branch.startswith('riddle-proof/'):
29
30
  raise SystemExit(
@@ -158,17 +159,26 @@ def compatible_reuse_source(source_dir, target_dirs):
158
159
 
159
160
 
160
161
  def resolve_worktree_root(repo_dir):
161
- configured = (s.get('worktree_root') or os.environ.get('RIDDLE_PROOF_WORKTREE_ROOT') or '').strip()
162
+ configured = (os.environ.get('RIDDLE_PROOF_WORKTREE_ROOT') or '').strip()
162
163
  if configured:
163
164
  return os.path.abspath(os.path.expanduser(configured))
165
+ state_worktree_root = (s.get('worktree_root') or '').strip()
166
+ legacy_tmp_root = os.path.abspath(os.path.join(tempfile.gettempdir(), '.riddle-proof-worktrees'))
167
+ if state_worktree_root and os.path.abspath(os.path.expanduser(state_worktree_root)) != legacy_tmp_root:
168
+ return os.path.abspath(os.path.expanduser(state_worktree_root))
164
169
  if os.environ.get('RIDDLE_PROOF_USE_WORKSPACE_WORKTREE_ROOT', '').strip().lower() in ('1', 'true', 'yes'):
165
170
  repo_parent = os.path.dirname(os.path.abspath(repo_dir))
166
171
  return os.path.join(repo_parent, '.riddle-proof-worktrees')
167
172
 
168
- # Proof worktrees are scratch data. Keep them on local temp storage by
169
- # default so dependency cache materialization does not crawl across EFS or
170
- # other shared workspace filesystems.
171
- return os.path.join(tempfile.gettempdir(), '.riddle-proof-worktrees')
173
+ # Proof worktrees and dependency caches are large generated data. Keep
174
+ # them on disk-backed scratch storage by default so tmpfs /tmp remains
175
+ # available for small state files and short-lived artifacts.
176
+ scratch_root = (s.get('scratch_root') or os.environ.get('RIDDLE_PROOF_SCRATCH_ROOT') or '').strip()
177
+ if scratch_root:
178
+ return os.path.join(os.path.abspath(os.path.expanduser(scratch_root)), '.riddle-proof-worktrees')
179
+ if os.environ.get('RIDDLE_PROOF_USE_TMP_SCRATCH', '').strip().lower() in ('1', 'true', 'yes'):
180
+ return os.path.join(tempfile.gettempdir(), 'riddle-proof', '.riddle-proof-worktrees')
181
+ return os.path.join(DEFAULT_SCRATCH_ROOT, '.riddle-proof-worktrees')
172
182
 
173
183
 
174
184
  def env_flag(name, default=False):
@@ -202,6 +212,33 @@ def disk_free_bytes(path):
202
212
  return 0
203
213
 
204
214
 
215
+ def disk_snapshot(path):
216
+ probe = path
217
+ while probe and not os.path.exists(probe):
218
+ parent = os.path.dirname(probe)
219
+ if parent == probe:
220
+ break
221
+ probe = parent
222
+ try:
223
+ usage = shutil.disk_usage(probe or tempfile.gettempdir())
224
+ except Exception as exc:
225
+ return {
226
+ 'path': path,
227
+ 'probe_path': probe or tempfile.gettempdir(),
228
+ 'error': str(exc)[:200],
229
+ }
230
+ used = usage.total - usage.free
231
+ percent_used = round((used / usage.total) * 100, 1) if usage.total else 0
232
+ return {
233
+ 'path': path,
234
+ 'probe_path': probe or tempfile.gettempdir(),
235
+ 'total_bytes': usage.total,
236
+ 'used_bytes': used,
237
+ 'free_bytes': usage.free,
238
+ 'percent_used': percent_used,
239
+ }
240
+
241
+
205
242
  def prune_scratch_worktrees(worktree_root, keep_dirs, repo_dir):
206
243
  report = {
207
244
  'requested': True,
@@ -475,16 +512,24 @@ s['branch'] = branch
475
512
  s['target_branch'] = target_branch
476
513
  s['ship_target_branch'] = target_branch
477
514
  s['worktree_root'] = WORKTREE_ROOT
515
+ s['scratch_root'] = os.path.dirname(WORKTREE_ROOT)
516
+ try:
517
+ cache_result = workspace_core('dependency-cache-root', {'projectDir': AFTER_DIR}, timeout=30)
518
+ s['dependency_cache_root'] = cache_result.get('cacheRoot') or ''
519
+ except Exception as exc:
520
+ s['dependency_cache_root_error'] = str(exc)[:200]
478
521
  capture_hint = apply_capture_hint(s)
479
522
  if capture_hint and capture_hint.get('applied_fields'):
480
523
  print('Applied last-good capture hint: ' + ', '.join(capture_hint.get('applied_fields') or []))
481
524
  save_state(s)
482
525
  print('Prepared workspace via ' + setup.get('source', 'workspace_core') + ': ' + repo_dir)
483
526
  os.makedirs(WORKTREE_ROOT, exist_ok=True)
527
+ s['scratch_disk_before_cleanup'] = disk_snapshot(WORKTREE_ROOT)
484
528
  scratch_cleanup = prune_scratch_worktrees(WORKTREE_ROOT, (BEFORE_DIR, AFTER_DIR), repo_dir)
485
529
  if scratch_cleanup.get('removed') or scratch_cleanup.get('errors'):
486
530
  print('Scratch cleanup: removed ' + str(len(scratch_cleanup.get('removed') or [])) + ' stale proof worktree(s)')
487
531
  s['scratch_cleanup'] = scratch_cleanup
532
+ s['scratch_disk_after_cleanup'] = disk_snapshot(WORKTREE_ROOT)
488
533
  save_state(s)
489
534
  cleanup_legacy_branch_worktrees(repo_dir, base_branch)
490
535
 
@@ -605,6 +650,7 @@ s['dependency_install'] = {
605
650
  'before': before_dep_status,
606
651
  'after': after_dep_status,
607
652
  }
653
+ s['scratch_disk_after_setup'] = disk_snapshot(WORKTREE_ROOT)
608
654
  if not (s.get('capture_script') or '').strip():
609
655
  s['proof_plan_status'] = 'pending_recon'
610
656
  save_state(s)