Skip to content

Commit 972e446

Browse files
committed
feat(atomic-index): Rename audit_index.tmp to audit_index on success, cleanup on failure
- Add cleanup_audit_index_tmp() to remove temp directory on exit - Add cleanup_all() orchestrator to call both embed server and temp dir cleanup - Implement atomic rename: remove old audit_index/, mv audit_index.tmp/ → audit_index/ - On failure (EXIT, INT, TERM): cleanup trap removes only audit_index.tmp/, preserves existing audit_index/ - Update trap_cleanup_test.sh to verify cleanup_all coordination and AUDIT_INDEX_DIR guard - Add failure-path smoke test: pre-existing index preserved, temp cleaned on llmcc failure - Ensures previous audit results preserved if new run fails mid-execution
1 parent cbebe89 commit 972e446

3 files changed

Lines changed: 105 additions & 22 deletions

File tree

tests/run_index_mock_smoke.sh

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -407,23 +407,28 @@ EOF_RS
407407
resolved_output="$(printf '%s\n' "$run_output" | sed -n 's/^OUTPUT_DIR=//p' | tail -n1)"
408408
[ -n "$resolved_output" ] || fail "case $case_name: run_index.sh did not emit OUTPUT_DIR"
409409

410-
manifest="$resolved_output/audit_index.tmp/manifest.json"
410+
manifest="$resolved_output/audit_index/manifest.json"
411411
assert_nonempty_file "$manifest"
412-
assert_nonempty_file "$resolved_output/audit_index.tmp/derived/catalog.json"
413-
assert_nonempty_file "$resolved_output/audit_index.tmp/derived/hotspots.json"
414-
assert_nonempty_file "$resolved_output/audit_index.tmp/derived/dup_clusters.md"
415-
[ -e "$resolved_output/audit_index.tmp/derived/read_plan.tsv" ] || \
412+
assert_nonempty_file "$resolved_output/audit_index/derived/catalog.json"
413+
assert_nonempty_file "$resolved_output/audit_index/derived/hotspots.json"
414+
assert_nonempty_file "$resolved_output/audit_index/derived/dup_clusters.md"
415+
[ -e "$resolved_output/audit_index/derived/read_plan.tsv" ] || \
416416
fail "case $case_name: expected read_plan.tsv to exist"
417-
assert_nonempty_file "$resolved_output/audit_index.tmp/derived/read_plan.md"
417+
assert_nonempty_file "$resolved_output/audit_index/derived/read_plan.md"
418418

419-
# [R-003] Guard: no nested audit_index.tmp/audit_index.tmp path produced
420-
if [ -d "$resolved_output/audit_index.tmp/audit_index.tmp" ]; then
421-
fail "case $case_name: nested audit_index.tmp/audit_index.tmp directory detected — contract mismatch"
419+
# Guard: no nested audit_index/audit_index.tmp path produced
420+
if [ -d "$resolved_output/audit_index/audit_index.tmp" ]; then
421+
fail "case $case_name: nested audit_index/audit_index.tmp directory detected — contract mismatch"
422422
fi
423423

424-
# [R-006] Assert pre-existing audit_index/ is preserved during temp-dir generation
425-
if [ ! -f "$resolved_output/audit_index/.pre_existing_marker" ]; then
426-
fail "case $case_name: pre-existing audit_index/ was destroyed during audit_index.tmp generation"
424+
# Assert no stale audit_index.tmp/ remains after successful run
425+
if [ -d "$resolved_output/audit_index.tmp" ]; then
426+
fail "case $case_name: audit_index.tmp/ still exists after successful run — atomic rename failed"
427+
fi
428+
429+
# Pre-existing audit_index/ should be replaced (not preserved) on success
430+
if [ -f "$resolved_output/audit_index/.pre_existing_marker" ]; then
431+
fail "case $case_name: pre-existing sentinel still present — old audit_index/ was not replaced"
427432
fi
428433

429434
llmcc_mode_actual="$(json_string "$manifest" "llmcc_mode")"
@@ -464,7 +469,7 @@ EOF_RS
464469
fail "case $case_name: expected retrieval_mode=$expected_retrieval_mode, got $retrieval_mode"
465470
fi
466471

467-
catalog="$resolved_output/audit_index.tmp/derived/catalog.json"
472+
catalog="$resolved_output/audit_index/derived/catalog.json"
468473
assert_nonempty_file "$catalog"
469474

470475
catalog_rust="$(json_bool "$catalog" "rust")"
@@ -533,7 +538,51 @@ run_case "embed-utf8-panic-falls-back-to-bm25" \
533538
"root-rust" "0" "unset" "1" "0" "direct" \
534539
"1" "1" "1" "1" "bm25-only" "1"
535540

536-
# [R-007] Shellcheck gate for modified pipeline scripts
541+
# --- Failure-path test: pre-existing audit_index/ preserved, audit_index.tmp/ cleaned up ---
542+
(
543+
set -euo pipefail
544+
545+
work_dir="$(mktemp -d "${TMPDIR:-/tmp}/vca-smoke.failure-cleanup.XXXXXX")"
546+
repo_dir="$work_dir/repo"
547+
output_dir="$work_dir/output"
548+
549+
# Create a minimal repo (no mock bins → llmcc not found → die)
550+
mkdir -p "$repo_dir/src"
551+
cat > "$repo_dir/Cargo.toml" <<'EOF_CARGO'
552+
[package]
553+
name = "mock-fail"
554+
version = "0.1.0"
555+
edition = "2021"
556+
EOF_CARGO
557+
558+
# Pre-create audit_index/ with sentinel
559+
mkdir -p "$output_dir/audit_index"
560+
printf 'survivor\n' > "$output_dir/audit_index/.pre_existing_marker"
561+
562+
# Run without mock bins on PATH — llmcc check will die
563+
# Use a clean PATH without mock bins
564+
if PATH="/usr/bin:/bin" bash "$RUN_INDEX_SCRIPT" \
565+
--repo "$repo_dir" \
566+
--output "$output_dir" \
567+
--mode standard >/dev/null 2>&1; then
568+
fail "failure-cleanup: expected run_index.sh to fail when llmcc is missing"
569+
fi
570+
571+
# Assert: pre-existing audit_index/ is preserved
572+
if [ ! -f "$output_dir/audit_index/.pre_existing_marker" ]; then
573+
fail "failure-cleanup: pre-existing audit_index/ was destroyed on failure"
574+
fi
575+
576+
# Assert: audit_index.tmp/ is cleaned up
577+
if [ -d "$output_dir/audit_index.tmp" ]; then
578+
fail "failure-cleanup: audit_index.tmp/ still exists after failure — cleanup trap did not run"
579+
fi
580+
581+
printf '[run_index_mock_smoke] PASS: failure-cleanup (pre-existing index preserved, tmp cleaned)\n'
582+
rm -rf "$work_dir"
583+
)
584+
585+
# Shellcheck gate for modified pipeline scripts
537586
PIPELINE_SCRIPTS=(
538587
"$ROOT_DIR/vibe-code-audit/scripts/run_index.sh"
539588
"$ROOT_DIR/vibe-code-audit/scripts/build_derived_artifacts.sh"

tests/trap_cleanup_test.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ echo "=== Trap & Cleanup Tests ==="
1212

1313
# --- Static checks: trap signatures ---
1414

15-
if grep -q 'trap cleanup_embed_server EXIT INT TERM' "$SCRIPTS_DIR/run_index.sh"; then
16-
pass "run_index.sh traps EXIT INT TERM"
15+
if grep -q 'trap cleanup_all EXIT INT TERM' "$SCRIPTS_DIR/run_index.sh"; then
16+
pass "run_index.sh traps EXIT INT TERM via cleanup_all"
1717
else
18-
fail "run_index.sh missing EXIT INT TERM trap"
18+
fail "run_index.sh missing EXIT INT TERM trap via cleanup_all"
1919
fi
2020

2121
if grep -q 'trap cleanup EXIT INT TERM' "$SCRIPTS_DIR/run_agentroot_embed.sh"; then
@@ -25,7 +25,7 @@ else
2525
fi
2626

2727
# Negative: no EXIT-only traps in target scripts
28-
if grep -qE 'trap cleanup_embed_server EXIT$' "$SCRIPTS_DIR/run_index.sh"; then
28+
if grep -qE 'trap cleanup_all EXIT$' "$SCRIPTS_DIR/run_index.sh"; then
2929
fail "run_index.sh still has EXIT-only trap"
3030
else
3131
pass "run_index.sh has no EXIT-only trap"
@@ -62,14 +62,34 @@ fi
6262
# --- Static checks: trap registration ordering ---
6363
# Trap must be registered after function definition but before resource-critical code
6464

65-
RUN_INDEX_FUNC_LINE=$(grep -n 'cleanup_embed_server()' "$SCRIPTS_DIR/run_index.sh" | head -1 | cut -d: -f1)
66-
RUN_INDEX_TRAP_LINE=$(grep -n 'trap cleanup_embed_server EXIT INT TERM' "$SCRIPTS_DIR/run_index.sh" | head -1 | cut -d: -f1)
65+
RUN_INDEX_FUNC_LINE=$(grep -n 'cleanup_all()' "$SCRIPTS_DIR/run_index.sh" | head -1 | cut -d: -f1)
66+
RUN_INDEX_TRAP_LINE=$(grep -n 'trap cleanup_all EXIT INT TERM' "$SCRIPTS_DIR/run_index.sh" | head -1 | cut -d: -f1)
6767
if [ "$RUN_INDEX_TRAP_LINE" -gt "$RUN_INDEX_FUNC_LINE" ]; then
6868
pass "run_index.sh trap registered after function definition (line $RUN_INDEX_FUNC_LINE < $RUN_INDEX_TRAP_LINE)"
6969
else
7070
fail "run_index.sh trap registered before function definition"
7171
fi
7272

73+
# Verify cleanup_all calls both cleanup functions
74+
if grep -A5 'cleanup_all()' "$SCRIPTS_DIR/run_index.sh" | grep -q 'cleanup_embed_server'; then
75+
pass "run_index.sh cleanup_all calls cleanup_embed_server"
76+
else
77+
fail "run_index.sh cleanup_all missing cleanup_embed_server call"
78+
fi
79+
80+
if grep -A5 'cleanup_all()' "$SCRIPTS_DIR/run_index.sh" | grep -q 'cleanup_audit_index_tmp'; then
81+
pass "run_index.sh cleanup_all calls cleanup_audit_index_tmp"
82+
else
83+
fail "run_index.sh cleanup_all missing cleanup_audit_index_tmp call"
84+
fi
85+
86+
# Verify cleanup_audit_index_tmp has guard for undefined variable
87+
if awk '/^cleanup_audit_index_tmp\(\)/,/^}/' "$SCRIPTS_DIR/run_index.sh" | grep -q 'AUDIT_INDEX_DIR:-'; then
88+
pass "run_index.sh cleanup_audit_index_tmp guards undefined AUDIT_INDEX_DIR"
89+
else
90+
fail "run_index.sh cleanup_audit_index_tmp missing undefined variable guard"
91+
fi
92+
7393
EMBED_FUNC_LINE=$(grep -n '^cleanup()' "$SCRIPTS_DIR/run_agentroot_embed.sh" | head -1 | cut -d: -f1)
7494
EMBED_TRAP_LINE=$(grep -n 'trap cleanup EXIT INT TERM' "$SCRIPTS_DIR/run_agentroot_embed.sh" | head -1 | cut -d: -f1)
7595
if [ "$EMBED_TRAP_LINE" -gt "$EMBED_FUNC_LINE" ]; then

vibe-code-audit/scripts/run_index.sh

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,18 @@ cleanup_embed_server() {
149149
EMBED_SERVER_PID=""
150150
fi
151151
}
152-
trap cleanup_embed_server EXIT INT TERM
152+
153+
cleanup_audit_index_tmp() {
154+
if [ -n "${AUDIT_INDEX_DIR:-}" ] && [ -d "$AUDIT_INDEX_DIR" ]; then
155+
rm -rf "$AUDIT_INDEX_DIR"
156+
fi
157+
}
158+
159+
cleanup_all() {
160+
cleanup_embed_server
161+
cleanup_audit_index_tmp
162+
}
163+
trap cleanup_all EXIT INT TERM
153164

154165
log "repo: $REPO_PATH_ABS"
155166
log "output: $OUTPUT_DIR_ABS"
@@ -620,5 +631,8 @@ if [ "$SKIP_READ_PLAN" -eq 0 ]; then
620631
fi
621632
fi
622633

623-
log "Indexing complete"
634+
log "Indexing complete — finalizing output"
635+
rm -rf "$OUTPUT_DIR_ABS/audit_index"
636+
mv "$AUDIT_INDEX_DIR" "$OUTPUT_DIR_ABS/audit_index"
637+
log "Renamed audit_index.tmp/ → audit_index/"
624638
printf 'OUTPUT_DIR=%s\n' "$OUTPUT_DIR_ABS"

0 commit comments

Comments
 (0)