Luigit
repositories / termux-janitor

termux-janitor

Interactive cleanup assistant for Termux: transparent, safe, confirmed disk reclamation.

owned by admin

spec/experiments/package_manager_dry_run.md

Raw
Rendered preview

Package-manager dry-run purity experiment

Question

Can an adapter treat a package manager's --dry-run option as evidence that planning is read-only?

This tests the dry-run and adapter assumptions in PRODUCT.md.

Environment

  • Date: 2026-09-13
  • npm: 11.19.1
  • Node.js: 26.4.0
  • strace: 7.2
  • Platform: Termux on Android Linux 6.1, AArch64

Isolation

Each invocation used a fresh fixture below Termux $TMPDIR with dedicated HOME, temporary, XDG, npm cache, npm log, configuration, prefix, and project paths. The process received an allowlisted environment through env -i. Network access, lifecycle scripts, audit, funding output, update checks, color, progress, npm log creation, and the Node.js compile cache were disabled. No operator npm cache, configuration, credentials, project, or package state was used.

The complete fixture was snapshotted before and after each invocation. strace -f recorded filesystem, process, network, write, mapping, and locking operations outside the fixture.

Cache-clean dry-run

The fixture contained a sentinel below cache/_cacache/. The probe invoked:

npm --cache=<fixture>/cache --logs-dir=<fixture>/logs ... \
  --logs-max=0 cache clean --force --dry-run

Observed result:

exit=0
npm warn using --force Recommended protections disabled.
cache/_cacache/content-v2/sha512/aa/sentinel -> deleted
cache/_cacache -> deleted

The trace recorded successful unlinkat calls for the sentinel and its parent directories. Installed npm source at /data/data/com.termux/files/usr/lib/node_modules/npm/lib/commands/cache.js:143 calls recursive fs.rm for full cache cleaning without checking dry-run. The operation-specific npx cache removal paths elsewhere in the same file do check dry-run.

Read-command startup mutation

A separate fixture contained three old files in the configured npm log directory. The probe invoked:

npm --cache=<fixture>/cache --logs-dir=<fixture>/logs ... \
  --logs-max=0 cache ls

Observed result:

exit=0
one pre-existing log file -> deleted

The trace recorded the successful unlinkat. Installed npm source at /data/data/com.termux/files/usr/lib/node_modules/npm/lib/utils/log-file.js:181-239 performs old-log cleanup during startup. logs-max=0 disables creation of a new log but does not disable that cleanup.

Conclusion

A manager option named --dry-run is not evidence of read-only behavior. npm 11.19.1 performed the requested destructive cache cleanup despite --dry-run. A nominally read-only cache listing also mutated manager logs during startup.

Planning capability must therefore be qualified by adapter operation and supported manager version under controlled effective configuration. Tests must include manager and runtime startup behavior, not only the command's primary operation. An operation without established read-only planning must be reported unavailable rather than invoked during Janitor dry-run.

This result applies directly to the tested npm operations and version. It does not prove that every npm operation or other package manager is impure.

# Package-manager dry-run purity experiment

## Question

Can an adapter treat a package manager's `--dry-run` option as evidence that planning is read-only?

This tests the dry-run and adapter assumptions in [`PRODUCT.md`](../PRODUCT.md#10-planning-dry-run-and-confirmation).

## Environment

- Date: 2026-09-13
- npm: 11.19.1
- Node.js: 26.4.0
- strace: 7.2
- Platform: Termux on Android Linux 6.1, AArch64

## Isolation

Each invocation used a fresh fixture below Termux `$TMPDIR` with dedicated HOME, temporary, XDG, npm cache, npm log, configuration, prefix, and project paths.
The process received an allowlisted environment through `env -i`.
Network access, lifecycle scripts, audit, funding output, update checks, color, progress, npm log creation, and the Node.js compile cache were disabled.
No operator npm cache, configuration, credentials, project, or package state was used.

The complete fixture was snapshotted before and after each invocation.
`strace -f` recorded filesystem, process, network, write, mapping, and locking operations outside the fixture.

## Cache-clean dry-run

The fixture contained a sentinel below `cache/_cacache/`.
The probe invoked:

```text
npm --cache=<fixture>/cache --logs-dir=<fixture>/logs ... \
  --logs-max=0 cache clean --force --dry-run
```

Observed result:

```text
exit=0
npm warn using --force Recommended protections disabled.
cache/_cacache/content-v2/sha512/aa/sentinel -> deleted
cache/_cacache -> deleted
```

The trace recorded successful `unlinkat` calls for the sentinel and its parent directories.
Installed npm source at `/data/data/com.termux/files/usr/lib/node_modules/npm/lib/commands/cache.js:143` calls recursive `fs.rm` for full cache cleaning without checking `dry-run`.
The operation-specific npx cache removal paths elsewhere in the same file do check `dry-run`.

## Read-command startup mutation

A separate fixture contained three old files in the configured npm log directory.
The probe invoked:

```text
npm --cache=<fixture>/cache --logs-dir=<fixture>/logs ... \
  --logs-max=0 cache ls
```

Observed result:

```text
exit=0
one pre-existing log file -> deleted
```

The trace recorded the successful `unlinkat`.
Installed npm source at `/data/data/com.termux/files/usr/lib/node_modules/npm/lib/utils/log-file.js:181-239` performs old-log cleanup during startup.
`logs-max=0` disables creation of a new log but does not disable that cleanup.

## Conclusion

**A manager option named `--dry-run` is not evidence of read-only behavior.**
npm 11.19.1 performed the requested destructive cache cleanup despite `--dry-run`.
A nominally read-only cache listing also mutated manager logs during startup.

Planning capability must therefore be qualified by adapter operation and supported manager version under controlled effective configuration.
Tests must include manager and runtime startup behavior, not only the command's primary operation.
An operation without established read-only planning must be reported unavailable rather than invoked during Janitor dry-run.

This result applies directly to the tested npm operations and version.
It does not prove that every npm operation or other package manager is impure.