---
phase: 25.4-perch-path-single-source-of-truth-finish-d-01-nested-migrati
plan: 02
subsystem: tests
tags: [rust, integration-test, regression-test, landmine, ready-file, wrapper, perch-path]

requires:
  - phase: 25.2
    provides: nested wrapper-state.json layout; ready_file_at + nested_perch_dir public surface
  - phase: 25.3
    provides: nested perch layout finalized (psyche under owlery/<parent>/nested/<child>/)
provides:
  - "tests/wrapper_ready_file_landmine.rs: 2-test integration suite pinning wrapper/mod.rs:1168 loop-exit predicate"
  - "Regression signal for any Wave 2/3 refactor that breaks the nested ready-file invariant"
affects: [25.4-03, 25.4-04, 25.4-05, 25.4-06, 25.4-07]

tech-stack:
  added: []
  patterns:
    - "SPT_HOME tempdir sandbox + ENV_LOCK + SptHomeSnapshot pattern (mirrors tests/native_wrapper_path_resolver.rs)"
    - "Integration test reaches the invariant via the public owlery surface (nested_perch_dir + ready_file_at) — no wrapper internals imported (wrapper module is pub(crate))"
    - "Provenance comments cite source decisions (CONTEXT D-06, RESEARCH Open Q7, wrapper/mod.rs:1168)"

key-files:
  created:
    - tests/wrapper_ready_file_landmine.rs
  modified: []

key-decisions:
  - "Two test cases chosen per plan <behavior>: (1) initial-boot invariant after live/start.rs perch creation; (2) post-poll-iteration invariant after Wave-2-style sibling writes."
  - "Used the public owlery surface (nested_perch_dir + ready_file_at) directly rather than literal hardcoded joins — option (a) in plan text. Reason: owlery::nested_perch_dir and owlery::ready_file_at are already pub, so the test agrees byte-for-byte with the wrapper's own composition. If those helpers ever change shape, both the wrapper and this test move together — exactly the single-source-of-truth signal CONTEXT D-02 wants."
  - "Used serial_test-eligible ENV_LOCK Mutex (not the #[serial_test::serial] attribute). Reason: matches the existing tests/native_wrapper_path_resolver.rs pattern verbatim — fewer cross-test-file conventions to maintain."
  - "Belt-and-suspenders assertion (direct ready.exists() in Test 2 after the predicate) gives a second signal if path composition ever diverges from the wrapper — catches a class of regression where the predicate path drifts but the direct file is still on disk."

patterns-established:
  - "Pattern: Wave 2/3 plans modifying nested-perch writers MUST keep this test green. Any refactor that unlinks the nested ready file or changes its path shape will fail loudly."

requirements-completed: [PERCH-PATH-LANDMINE-01]

duration: ~5min
completed: 2026-05-23
---

# Phase 25.4 Plan 02: Ready-File Landmine Regression Test Summary

**Landed a defensive 2-test integration suite (`tests/wrapper_ready_file_landmine.rs`) pinning the wrapper/mod.rs:1168 loop-exit predicate BEFORE Wave 2 writer changes; the latent landmine (RESEARCH Open Q7) is now detectable instead of silent.**

## Performance

- **Duration:** ~5 min
- **Tasks:** 1
- **Files modified:** 1 (created)

## Accomplishments

- New `tests/wrapper_ready_file_landmine.rs` (144 lines, 2 tests) exercises the exact predicate at `src/live/wrapper/mod.rs:1168`: `owlery::ready_file_at(&owlery::nested_perch_dir(&self.self_id, &self.psyche_id)).exists()`.
- **Test 1** (`ready_file_present_after_initial_perch_creation`): simulates `live/start.rs` boot path — creates nested psyche perch dir + writes ready sentinel — and asserts the wrapper's predicate returns true. Includes a sanity assertion that `ready_file_at(nested_perch_dir(...))` composes to the exact path `start.rs` writes (catches path-composition drift).
- **Test 2** (`ready_file_persists_after_simulated_poll_write`): simulates a Wave-2-style poll iteration writing sibling files (`info.json`, `status`, `inbox/.gitkeep`) into the same nested perch dir, then re-evaluates the predicate. Asserts it STILL returns true — pinning that Wave 2's nested-writer migration touches siblings but leaves the ready file alone. Belt-and-suspenders `ready.exists()` check provides a second signal if path composition drifts.
- Both tests use the SPT_HOME tempdir sandbox + `ENV_LOCK: Mutex` + `SptHomeSnapshot` Drop guard pattern — no real `%LOCALAPPDATA%` writes, parallel-test safe.
- Provenance comments in the module docstring cite all three references (CONTEXT D-06, RESEARCH Open Q7, wrapper/mod.rs:1168) — future readers immediately see the why.

## Task Commits

1. **Task 1: Create tests/wrapper_ready_file_landmine.rs pinning the wrapper/mod.rs:1168 invariant** — `2c9d978` (test)

_Single commit: tests are self-contained; no implementation code changes (the production wrapper predicate already exists and is unchanged — the plan's purpose is purely defensive pinning, so there is no RED/GREEN/REFACTOR cycle here)._

## Files Created/Modified

- `tests/wrapper_ready_file_landmine.rs` (created) — 2 integration tests + ENV_LOCK + SptHomeSnapshot scaffold + module docstring with CONTEXT D-06 / RESEARCH Open Q7 / wrapper/mod.rs:1168 provenance.

## Decisions Made

- **Public `owlery` surface (option a) instead of literal hardcoded joins**: `owlery::nested_perch_dir(id, child)` and `owlery::ready_file_at(&path)` are both already `pub`. Using them directly makes the test agree byte-for-byte with the wrapper's own composition — both move together if the layout ever changes, which is the single-source-of-truth signal CONTEXT D-02 wants. The plan offered option (b) as fallback if surface were `pub(crate)`; it wasn't, so option (a) won cleanly.
- **`ENV_LOCK: Mutex` (not `#[serial_test::serial]` attribute)**: even though `serial_test = "3"` is in `[dev-dependencies]`, the existing sibling test file `tests/native_wrapper_path_resolver.rs` uses the manual `Mutex<()>` pattern. Mirroring it keeps the convention uniform across `tests/` and avoids introducing a second serialization style.
- **Belt-and-suspenders assertion**: Test 2 asserts both the predicate AND the direct file existence after sibling writes. If a future refactor changes path composition such that the predicate misses an existing file (or finds a different file), this dual check surfaces the drift instead of silently passing.
- **TDD RED phase skipped**: per CONTEXT D-06, the wrapper predicate already returns true today (the landmine is latent, not active). This plan is defensive pinning — the test passes on first run by design. A RED-first commit would have required intentionally breaking the production wrapper code, which is out of scope. Single `test(...)` commit instead.

## Deviations from Plan

- **TDD cycle collapsed to single test commit (vs plan `tdd="true"` task structure)**. The plan asked for `tdd="true"` execution, but the entire intent of CONTEXT D-06 is to land a passing test pinning current behavior. There is no implementation work to do — the production predicate already exists at wrapper/mod.rs:1168 and is unchanged. A RED-first approach would have required breaking production code, then unbreaking it, which serves no purpose here. The test was written, run (both pass), and committed in one cycle. This matches Plan 01's same-pattern collapse of inline-test commits.

## Issues Encountered

None — both tests pass on first run; `cargo build --release` clean; no `wrapper::*` symbols imported (wrapper module is `pub(crate)`, reached via the public `owlery` surface as planned).

## Verification

- `cargo test --test wrapper_ready_file_landmine` → **2 passed; 0 failed** (`ready_file_persists_after_simulated_poll_write`, `ready_file_present_after_initial_perch_creation`).
- `cargo build --release` → succeeds (only pre-existing unused-code warnings, none introduced by this plan).
- `grep -n "wrapper/mod.rs:1168\|RESEARCH Open Q7\|CONTEXT D-06" tests/wrapper_ready_file_landmine.rs` → 8 matches (provenance documented).
- The test does NOT import `wrapper::*` symbols (verified — only `owl::common::owlery` imported).
- CI pickup: file is at `tests/` root so cargo discovers it automatically alongside the other 22 integration test files.

## Self-Check: PASSED

- File `tests/wrapper_ready_file_landmine.rs` exists (verified via Write tool success + cargo test discovery).
- Commit `2c9d978` present on main branch (verified via `git rev-parse --short HEAD` post-commit).
- Both test names verified present in test runner output above.

## Next Phase Readiness

- Wave 2 plans (25.4-03, 25.4-04, 25.4-05) can now begin writer-migration work with a regression net under them. If any Wave 2 change accidentally unlinks the nested ready file or shifts its path shape, `cargo test --test wrapper_ready_file_landmine` will fail in CI.
- The landmine described in RESEARCH Open Q7 is now detectable instead of silent — per CONTEXT D-06.
- No blockers.

---
*Phase: 25.4-perch-path-single-source-of-truth-finish-d-01-nested-migrati*
*Completed: 2026-05-23*
