findProjectRoot utility for subdirectory support
Running `ana work status` (or any pipeline command) from a subdirectory like `packages/cli/src/` fails because it looks for `.ana/` only in CWD. The CLI should walk up the directory tree to find the project root, matching how git and other tools behave.
verdict PASSscore 9 / 9findings 5 (1 risk · 0 debt · 4 obs)duration 5h 16mrejection cycles 1shipped Apr 16, 2026
Pipeline timeline
Intent to proven code in 5h 16m across Think, Plan, Build, and Verify.
Think15m
Plan15m
Build293m
Verify9m
Assertion ledger
9 claims, each independently verified. Showing 8 — show all →
| ID | Says | Matcher | |
|---|---|---|---|
| A001 | Finding project root from the project directory returns that directory | verified | ok |
| A002 | Finding project root from a nested subdirectory walks up and finds the project | verified | ok |
| A003 | Finding project root from a deeply nested subdirectory still finds the project | verified | ok |
| A004 | A clear error is thrown when no project is found in any parent directory | verified | ok |
| A005 | The error message tells the user to run ana init | verified | ok |
| A006 | When two nested projects exist, the closest one is found | verified | ok |
| A007 | The utility is exported and importable from validators | verified | ok |
| A008 | readArtifactBranch accepts a project root parameter | verified | ok |
Findings 5 total
riskpackages/cli/src/utils/validators.ts→ closed
`findProjectRoot` checks for `.ana/` directory existence (validators.ts:105), not `.ana/ana.json`. A stale `.ana/` directory containing only `state/` (like `packages/cli/src/.ana/`) causes the function to return the wrong root. `readArtifactBranch` then fails with "No .ana/ana.json found." Checking `fs.existsSync(path.join(current, '.ana', 'ana.json'))` would be more robust. Not a spec violation — the spec explicitly says "looking for a directory containing `.ana/`" — but a production fragility worth addressing in a future cycle.
obspackages/cli/src/commands/artifact.ts→ closed
`slugDir2` in artifact.ts saveArtifact (line ~708) renamed from `slugDir` to avoid shadowing the pre-check block's `slugDir` (line ~547). Symptom of a long function — cosmetic, not functional. Carried from previous cycles.
obspackages/cli/tests/utils/findProjectRoot.test.ts→ closed
A009 test at findProjectRoot.test.ts:90-95 is `expect(true).toBe(true)` — a tautology that passes regardless of suite health. The builder's comment claims "if wiring broke existing tests, this file wouldn't reach execution," but Vitest executes test files independently. This test proves nothing. The suite-level result (1156 passed, 2 pre-existing failures) is the real evidence for A009, not this tagged test. Future contracts should express regression requirements as suite-run checks, not per-test tautologies.
obspackages/cli/tests/utils/findProjectRoot.test.ts→ closed
A007 test at findProjectRoot.test.ts:72-73 uses `typeof findProjectRoot === 'function'` — this passes for any function. The import statement at line 5 would throw `ERR_MODULE_NOT_FOUND` if the export didn't exist, which is the real verification. The typeof check adds no signal beyond the import.
obs→ closed
A009 as a contract assertion ("all existing tests continue to pass") is inherently untestable at the unit level. It's a suite-level property. Tagging a single test with `@ana A009` creates pressure to write a sentinel. Future contracts should either omit suite-level regression assertions or express them as "test command exits 0" verified during the build step, not as tagged tests.
Integrity seal
scopesha256:30148ec9a98ba...
contractsha256:e4011e2a4a638...
plansha256:7dc2a9c6d3886...
specsha256:18e933864e880...
build-reportsha256:13cbf4313c3e6...
verify-reportsha256:b08175794d24e...
audit cmd$ ana proof audit find-project-root → all hashes match