External-drive read-only pilot
v0.1.1 was
published and independently verified on 2026-09-26 for
#89. Its signed receipts
record all 13 pilot scenarios passing on each of the three native targets.
See the release verification record.
It retains read authority only: scans, reports, and review plans do not delete,
replace, move, quarantine, optimize, or reclaim space. Later source features
are not retroactively available in the old binary.
First external-drive trial
Install the exact host archive using the verification and installation instructions. Start with a disposable copy of a small collection before increasing its size. Put all state and command output on the local drive, outside every scan root. This includes the SQLite database, report captures, plans, and shell redirections. Do not scan your entire home directory while storing trial output underneath it.
pilot_directory="${HOME}/optiflow-pilot"
source_directory="/Volumes/DisposableMedia"
mkdir -p "${pilot_directory}"
optiflow --no-config --state-directory "${pilot_directory}/state" \
--json scan --no-probe "${source_directory}" \
> "${pilot_directory}/scan.json"
scan_status=$?
printf "Scan exit code: %s\n" "${scan_status}"
On Linux, select the actual mounted directory instead of /Volumes/....
Verify the expected volume is mounted at that path. The example assumes an
interactive shell; scripts using set -e must explicitly handle nonzero scan
outcomes before reading the JSON. Keep the JSON even when the exit is nonzero.
--no-config avoids user/project configuration. Clear any OPTIFLOW_*
environment overrides for a baseline trial. --no-probe avoids optional
ffprobe work; add probing only after the baseline succeeds. Hidden entries,
symbolic links, filesystem crossings, and OptiFlow's state are excluded by
default. Complete coverage means complete within the selected policy; excluded
files have not been inventoried. See configuration before
changing those defaults or loading explicitly trusted providers.
| Result | Meaning and next action |
|---|---|
Exit 0, success |
Inspect the coverage and report summary within the selected policy. |
Exit 3, partial_success |
Some requested scope was unavailable or unreadable; inspect coverage and diagnostics before relying on the inventory. |
Exit 2, invalid_input |
For example, the only requested root was missing; reconnect/correct the root and start a fresh scan. |
Exit 130 / 143, interrupted |
SIGINT / SIGTERM stopped the scan; completed artifacts must not be inferred. |
Other typed failures are documented in the CLI contract.
Machine mode writes one optiflow.command-result.v1 JSON envelope to stdout,
including diagnostics; it does not mix progress messages into that stream.
These contracts are unchanged by the pilot.
Read the run identifier from result.run.run_id in a successful scan. Keep
using the same state directory:
run_id="<run-id-from-scan>"
optiflow --no-config --state-directory "${pilot_directory}/state" \
--json report "${run_id}" > "${pilot_directory}/report.json"
optiflow --no-config --state-directory "${pilot_directory}/state" \
--json plan exact-duplicates --run "${run_id}" \
--output "${pilot_directory}/review-plan.json" \
> "${pilot_directory}/plan-result.json"
The plan declares mutates_files: false. A proposed keep path is a review
default. Logical duplicate bytes and allocation evidence are not a guarantee
of physical space that a later transaction would reclaim.
Privacy and local writes
Source files are opened read-only. OptiFlow writes its local state and requested report/plan artifacts, and the shell writes redirected output. Report and state contents can disclose filenames, directory structure, native path bytes, identities, hashes, media metadata, and provider paths. Base64 native-path representations are reversible, not anonymization. State backups carry the same exposure. Keep them private; share only a deliberately redacted excerpt when reporting an issue. The pilot runner generates its own synthetic files and retains aggregate measurements rather than a personal media inventory.
Cancellation, restart, and reconnect
Press Ctrl-C once and wait for the typed interruption result. An interrupted run is not promoted to a completed report/plan set. Rerun the same scan command to start a new run with a new identifier. Stable, previously persisted observations can reuse the cache; there is no exact queue/cursor resume command and no promise to continue at the last pathname. An immediate interruption can leave no useful cache to reuse.
An uncatchable kill or power loss is different: a running database row can remain. Recovery can reconcile an already committed, marker-sealed artifact set, but cannot turn uncommitted work into a complete scan. Start a new scan and retain incomplete evidence for diagnosis. See the state model and artifact-set protocol.
If the drive disappears, stop relying on the current inventory. A root missing at startup is invalid input; loss during observation can produce partial or unavailable evidence. Reconnect the intended volume, verify its mount/root, then rerun. Path reuse alone is not proof that the same file or volume returned; fresh native identity/stability checks decide whether observations can be reused.
The deterministic filesystem corpus supplies exact
reproduction recipes: fs88-volume, fs88-disconnect, fs88-permission,
fs88-replacement, fs88-resize, fs88-metadata-race, fs88-state, and
fs88-run-recovery. Permission denial and mid-observation changes use explicit
fault hooks, including when tests run as root. The pilot's rename/reconnect
trial simulates disappearance; it is not a physical USB removal or power-loss
test across every filesystem/controller.
Upgrade and rollback
- Stop every OptiFlow process using the state directory. Retain the verified
v0.1.0executable and record the exact state path. - Copy the entire closed state directory, including the database and all artifact subdirectories, to a separate local backup outside scan roots. Copying only SQLite is insufficient. Keep the original directory location.
- Install the independently verified new executable. Use it to read an old report, then run a new scan against the original state location.
- To roll back, stop OptiFlow again, move the upgraded state aside, and restore the full backup at its original absolute path. Artifact references may contain absolute paths. Run the retained old executable and read the old report.
Do not run the old binary directly against upgraded state. This is an offline
backup/restore procedure, not a reverse migration or an in-place state downgrade.
Retain both state copies until review is complete; no source media is changed.
The automated trial verifies this sequence against the signed v0.1.0 bundle
on each native host before it can qualify that host's release archive.
Release qualification
The existing manual release workflow now builds and executes on native Linux
x86-64, Intel macOS, and Apple silicon macOS. Cross-compilation without native
execution cannot satisfy a target. Python 3.12, Git, Cosign 3.0.6, the built
binary, and the downloaded binary-v0.1.0.tar.gz are required to run the
repository-owned qualification harness; normal binary users do not need Python.
From a clean, committed checkout with a locked release build:
python3 scripts/qualify-read-only-pilot.py \
--binary "target/release/optiflow" \
--target "x86_64-unknown-linux-gnu" \
--release-version "v0.1.1" \
--source-revision "$(git rev-parse HEAD)" \
--previous-bundle "/local/downloads/binary-v0.1.0.tar.gz" \
--output-directory "target/pilot-v0.1.1"
Choose the native target and corresponding binary path on macOS. Use a fresh output directory for each attempt. The harness clean-installs the exact archive, verifies the old release's checksums, provenance, and Sigstore identity before executing it, and creates disposable sources outside all state directories.
| Trial | Required evidence |
|---|---|
| Large tree | 4,096 deterministic files; cold and warm scans, with 4,096 warm cache hits. |
| Large files | Two independently materialized 256 MiB files; one exact duplicate group and two warm cache hits. |
| Read-only commands | Scan, report, review plan; before/after source digests and metadata agree. |
| Partial / disconnect | Typed partial coverage, absent root refusal without artifacts, successful reconnect. |
| Interruption / restart | SIGINT after a durable running row; interrupted status, no completed artifacts, new run on restart. |
| Upgrade / rollback | New binary reads old evidence and scans; restored complete backup is readable by the verified old binary. |
| Resources / cleanup | Per-command elapsed seconds, cold/warm state bytes, aggregate state bytes, peak child RSS, and successful disposable-workspace cleanup. |
The profile uses roughly 512 MiB of materialized source data plus local state and retained archives. Each ordinary command has a 180-second timeout. Peak child RSS is the operating system's maximum across child processes, including Cosign and CLI commands, not a per-scan peak or total concurrent memory. Timings and artifact growth are observations from that host; they are not a universal throughput, memory, or external-drive SLO. Source snapshots compare content and metadata (excluding access times and the deliberately renamed root's metadata); this is bounded preservation evidence, not a kernel write audit.
The resulting receipt binds the source revision, archive digest, executable
digest, profile, outcomes, and measurements. Bundle preparation and independent
verification require all three matching receipts. The signed subject manifest
covers pilot-qualification.json as well as the archives, SBOM, and provenance.
The local Linux validation record retains
the historical candidate receipt and checks that were pending at that time.
The published-release record records
completed native qualification, signed publication, independent bundle
verification, and an independent Linux clean installation.
Unit-test receipts are explicitly synthetic; they cannot stand in for native
workflow execution. #90 follows the read-only release with
non-mutating execution and approval contracts.