ruflo-adr: the documented ADR_ROOT override makes every store fail (cwd:ROOT doubles as the db root), and import.mjs always exits 0 so it reports success
- Dominant language
- TypeScript
- Stars
- 72.7k
- Forks
- 8.6k
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 83
Description
`scripts/import.mjs` documents an `ADR_ROOT` override:
```
// ADR_ROOT=/path/to/repo node scripts/import.mjs # override scan root (default: cwd)
```
and `skills/adr-index/SKILL.md:34` advertises the same: `` `ADR_ROOT=/path` — scan a different root (default: cwd) ``.
**Setting it to anything other than the repo root makes every store fail, and the importer still exits 0.**
## What happens
Scanning is scoped correctly — the right files are found and parsed. Then every write fails:
```
Total ADRs: **43** across 43 source dirs (root: /path/to/repo/docs/adr)
Records stored to `adr-patterns`: 0/43
Edges stored to `adr-edges`: 0/27
...
- Storage errors: 70
- ADR-001 ...: error: [ERROR] Failed to store: [ruflo-source-patch] REFUSING memory.db operation for /Users/
```
70 = 43 records + 27 edges. Not a partial failure — a total one.
## Cause
`import.mjs:74` passes `cwd: ROOT` to the memory subprocess, and `ROOT` is `ADR_ROOT || process.cwd()` (`:50`). The comment above it is explicit about why:
```js
// #2666 point 2: without `cwd: ROOT`, this subprocess inherits THIS
// process's own cwd, so `ADR_ROOT=/other/repo node import.mjs` run from
// anywhere else scans the right files but writes to the wrong
// `.swarm/memory.db` (the CLI resolves the db path relative to the
// subprocess's cwd, not ADR_ROOT). Every memory subprocess call in this
// plugin must pass `cwd: ROOT` so the scan root and the db root agree.
```
That reasoning is right for the case it was written for — `ADR_ROOT` pointing at **another repo root**. It silently breaks the other documented use, `ADR_ROOT` pointing at a **subdirectory of the current repo** (`./docs/adr`), which is the natural way to scope a scan. The subprocess then resolves its db path from `docs/adr`, walks out of the project, and the guard refuses the write.
`ROOT` is doing two jobs — *where ADRs are read from* and *where the database lives* — and they only coincide when `ADR_ROOT` happens to be a repo root.
## Reproduction
From a repo with ADRs in `docs/adr/`:
```sh
# works: scan root and db root coincide
node scripts/import.mjs # Records stored: 43/43
# fails: same files, every store refused
ADR_ROOT="$PWD/docs/adr" node scripts/import.mjs # Records stored: 0/43, Storage errors: 70
echo $? # 0
```
## The exit code is 0 either way
`import.mjs`'s only `process.exit` is `process.exit(0)` at `:171`, inside the `IMPORT_FORMAT=json` branch. The markdown branch falls off the end of the script, so the process always exits 0 — regardless of `errors.length`.
So the failing invocation above reports success to anything that gates on `$?`. In my case the importer was being run from a documented recipe that used `ADR_ROOT`; it had been believed to work for weeks because it exits 0 and prints a well-formed summary. The `0/43` is the only signal, and it is easy to miss in a report that otherwise looks healthy.
This is the same class as the title of #2660 — *"and both reported as success"* — surfacing again in a different path.
## Suggested directions
- **Separate the two roots.** Keep `cwd` for the memory subprocess anchored to the *project* root (walk up for `.swarm`/`package.json`/`.git` from `ROOT`, or take an explicit `--db-root`), and let `ADR_ROOT` mean only "where to scan". That preserves the #2666 fix while unbreaking subdirectory scoping.
- **Exit non-zero when `errors.length > 0`**, at minimum for a total failure. A `--strict` flag would do if a bare non-zero is considered breaking.
- **Or reject the input.** If `ADR_ROOT` is only ever meant to be a repo root, detect that it isn't one and fail fast with that message, rather than scanning happily and discarding every write.
Versions: `ruflo-adr` 0.4.1, node 22, macOS. Related: #2666 (introduced `cwd: ROOT`), #2660 (success-reporting), #3096 (orphan detector, filed alongside this).
Contributor guide
Research direction
Start with scripts/import.mjs, especially the ROOT assignment, memory subprocess cwd, and exit handling; also read skills/adr-index/SKILL.md:34 and the related #2666 and #2660 context. Run both documented ADR_ROOT reproductions and verify that subdirectory scans store records in the project database while storage errors produce a non-zero exit status.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- node.js, typescript
- Domain
- database, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100