@@ -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
537586PIPELINE_SCRIPTS=(
538587 " $ROOT_DIR /vibe-code-audit/scripts/run_index.sh"
539588 " $ROOT_DIR /vibe-code-audit/scripts/build_derived_artifacts.sh"
0 commit comments