# SQLite Artifact Safety

Zaparoo Core opens both databases in WAL mode:

- `media.db`: rebuildable media index, `synchronous=NORMAL`
- `user.db`: non-rebuildable user data, `synchronous=FULL`

Ordinary file copies of an active SQLite database are not atomic. Copying main file and sidecars separately cannot guarantee one transaction boundary.

## Never modify source

Do not run these against device/source database:

- `sqlite3` inspection or integrity checks
- `VACUUM`, checkpoint, repair, migration, or schema commands
- opening database in GUI/browser
- renaming, deleting, compressing in place, or changing permissions
- copying a replacement back onto device

Even read-looking SQLite opens can create/update `-shm`, perform recovery, or interact with WAL. Validate only disposable local copies.

## Sidecars

For each main file, consider same-basename sidecars independently:

```text
media.db
media.db-wal
media.db-shm
media.db-journal

user.db
user.db-wal
user.db-shm
user.db-journal
```

- `-wal`: may contain committed transactions absent from main database. Missing it can lose newest data or make copy misleading.
- `-shm`: WAL index/shared-memory state. SQLite can often rebuild it, but include it when present for exact forensic capture.
- `-journal`: rollback journal. Capture when present; it can matter after interrupted or transitional writes.

Do not infer health from sidecar presence or absence alone.

## Live mode

Use only when downtime is not approved or possible.

Required report label:

```text
mode: live
coherent: false
warning: Core remained active; files may have changed during transfer.
```

Procedure:

1. Keep Core running. Do not stop or signal it.
2. Create local destination with owner-only access when possible (`0700` directory, `0600` files).
3. Record exact main/sidecar names, sizes, and modification times before copy.
4. Copy `media.db` and every present media sidecar without changing source.
5. Copy `user.db` and every present user sidecar without changing source.
6. Record same metadata after copy.
7. Record files that appeared, disappeared, changed size, or changed modification time.
8. Hash local copies (SHA-256) after transfer.
9. Never retry until output looks stable and then call it coherent. A quiet interval is not an SQLite snapshot guarantee.

A sidecar disappearing between probe and copy is a race, not permission to omit warning. Report it. If a main database cannot be copied, mark that family failed; do not present sidecars alone as usable database.

When consistency is essential, request user-approved stopped capture instead.

## Stopped mode

Only user decides to stop Core through their normal platform workflow. Agent must not issue stop, kill, disable, or restart commands automatically.

Before copy:

1. Confirm user intentionally stopped Core.
2. With approval, verify through platform-appropriate service/process status when practical.
3. Do not rely only on `core.pid`; stale PID files exist.
4. If Core appears active, refuse stopped-mode copy.
5. If inactivity cannot be verified, record user assertion rather than claiming verification.

Labels:

```text
coherent: verified   # agent verified Core inactive
coherent: asserted   # user said Core stopped; agent could not verify
```

Copy both main databases and every present `-wal`, `-shm`, and `-journal` sidecar. A stopped database can still have sidecars after crash or unclean shutdown; do not omit them.

Do not restart Core after collection unless user separately requests that action. A collection request does not imply restart permission.

## Local layout

Keep files together and preserve basenames:

```text
<case-directory>/
  manifest.json
  media.db
  media.db-wal        # if present
  media.db-shm        # if present
  media.db-journal    # if present
  user.db
  user.db-wal         # if present
  user.db-shm         # if present
  user.db-journal     # if present
  core.log            # if requested
```

Do not place sidecars in a different directory or rename them before validation.

## Manifest

Record at minimum:

- collection timestamp and timezone
- target identifier safe to retain
- Core platform and version when known
- transport used
- source data/log paths
- `live` or `stopped` mode
- inactivity status: verified, asserted, active, or unknown
- each file's source path, local name, size, and SHA-256
- before/after source metadata for live captures when available
- missing, appeared, disappeared, or changed files
- validation result or skip reason
- warnings and failures

Never record API keys, auth tokens, pairing keys, SSH passwords, private-key contents, or complete environment dumps.

## Disposable validation

Validation is optional and never upgrades a live capture to coherent.

1. Duplicate captured database family into separate temporary validation directory.
2. Keep main file and sidecars together with original basenames.
3. Run local SQLite `PRAGMA quick_check(1)` against disposable main file only when `sqlite3` is available.
4. Expect SQLite may recover/checkpoint or change disposable sidecars.
5. Record output and tool version.
6. Delete disposable validation directory; retain untouched captured originals.

Validate `media.db` and `user.db` separately. A successful quick check means disposable copy was readable and passed bounded check; it does not prove live transfer represented a single point in time. A failed check can indicate source corruption, transfer race, missing sidecar, or copy damage—report evidence without attempting repair.

## Sensitivity

- `user.db` can contain token mappings, history, profiles, and user configuration.
- `media.db` reveals library names and filesystem paths.
- logs can reveal hostnames, paths, errors, and operational context.

Use restrictive permissions, avoid shared/temp directories when possible, and do not upload or commit artifacts without separate explicit approval.
