# scripts/ reorganization plan — 2026-05-02

*Track 1 Bucket B fix #4 — read-only proposal. Nothing moved or deleted yet. Approve before executing.*

## Summary

The `~/aaronai/scripts/` directory currently holds **41** `.py`/`.sh` files. Reading the listing it is hard to tell which files are live workers and which are completed-experiment artifacts. The proposed split:

| Bucket | Count | Destination |
|---|---|---|
| Production (stay) | 11 | `scripts/` |
| Experimental (move) | 28 | `scripts/experiments/` (already exists, holds 4 files; will hold 32) |
| Deprecated (move) | 2 | `scripts/deprecated/` (new) |
| `.bak*` to delete | 19 | git history is the durable record |
| Uncertain | 0 | n/a |

After execution, `ls scripts/*.py scripts/*.sh` should return only the 11 production files plus the two subdirectories.

## Reference checks performed

Before producing this plan I grepped:
- `subprocess` calls inside `api.py` for paths under `scripts/`
- `import` and string-path references inside every production script
- `ExecStart=` lines across every `aaronai-*.service` in `/etc/systemd/system/`
- The user crontab for any line invoking a `scripts/` path

**Findings:**
- The only scripts referenced from `api.py` are `ingest.py` (line 43, `INGEST_SCRIPT`), `dream.py` (lines 661 and 1111), `ingest_conversations.py` (line 1127), and `corpus_integrity.py` (line 934, `CORPUS_INTEGRITY_SCRIPT`).
- `api.py` (line 937) and `corpus_integrity.py` (line 29) reference the data file `~/aaronai/experiments/tier1_migration_state.json` — that path is the **state file** in `~/aaronai/experiments/`, not the script. Moving `tier1_migration.py` does not break either reader.
- No production script imports or shells out to any experimental file.
- All eight `aaronai-*.service` units' `ExecStart` lines point at production scripts only.
- The user crontab references `backup.sh` and `aaronai-watcher` (a service) — no experimental files.

So the reorganization is safe at the reference level for every file in section B (experiments), C (deprecated), and D (delete). No moves change a runtime code path.

---

## A — PRODUCTION (stay in `scripts/`)

These 11 files are constraint-locked or referenced by an active runtime mechanism. None moves.

| File | Why it stays |
|---|---|
| `api.py` | `aaronai.service` ExecStart; long-running FastAPI backend; APScheduler. |
| `dream.py` | `aaronai-dreamer.service` ExecStart; called by APScheduler in `api.py`; called by `/api/dreamer/run`. |
| `watcher.py` | `aaronai-watcher.service` ExecStart; Stage 1 of the encoding pipeline. |
| `stage2_worker.py` | `aaronai-stage2.service` ExecStart. |
| `stage3_worker.py` | `aaronai-stage3.service` ExecStart (service is currently stopped, but the unit is enabled and the file is the unit's ExecStart). |
| `graphiti_service.py` | `aaronai-graphiti.service` ExecStart. |
| `ingest.py` | `INGEST_SCRIPT` constant in `api.py`; `/api/reindex` shells out to it. |
| `ingest_conversations.py` | `aaronai-index-conversations.service` ExecStart **and** APScheduler `ingest_job` in `api.py`. |
| `corpus_integrity.py` | `CORPUS_INTEGRITY_SCRIPT` constant in `api.py`; `/api/corpus/reconcile` shells out to it. |
| `st_embedder.py` | Imported by `graphiti_service.py` at sidecar startup (`SentenceTransformerEmbedder`). |
| `backup.sh` | User crontab `0 3 * * *` daily snapshot of `memory.md`, `settings.json`, `conversations.db`. |

---

## B — MOVE TO `scripts/experiments/`

28 files. None is referenced by any production code, systemd unit, or cron job.

For brevity, the "Why" column gives the experiment identity — full per-file write-ups are in the inventory's Phase 1 experimental table. The "Referenced by" column is the result of the grep against api.py / systemd ExecStart lines / cron / production scripts; "(none in production)" means no production code references it.

| Current path | Action | Why | Referenced by |
|---|---|---|---|
| `scripts/audit_expansion_draw.py` | move → `scripts/experiments/` | Type-aware stratified draw for n=20 audit expansion (sample-construction tool for `base_class_audit_rerun.py`). | (none in production) |
| `scripts/base_class_test.py` | move → `scripts/experiments/` | Base-class enrichment OOP framing experiment, n=20. | (none in production) |
| `scripts/base_class_validation.py` | move → `scripts/experiments/` | Base-class enrichment validation, n=50. | (none in production) |
| `scripts/base_class_audit_rerun.py` | move → `scripts/experiments/` | Base-class n=8 paired-extraction audit. | (none in production) |
| `scripts/briefing_generator_v2.py` | move → `scripts/experiments/` | Experiment 002b — briefing v2; validated 96% Mistral structural pattern. | (none in production) |
| `scripts/briefing_test.py` | move → `scripts/experiments/` | Experiment 002 — briefing v1; superseded by v2. | (none in production) |
| `scripts/cascade_test.py` | move → `scripts/experiments/` | Entity-drafter cascade n=20; falsified. | (none in production) |
| `scripts/cascade_optimization_test.py` | move → `scripts/experiments/` | Optimized entity-drafter cascade n=30; confirmed entity-drafter cascade is dead. | (none in production) |
| `scripts/consistency_test.py` | move → `scripts/experiments/` | Experiment 001 — Mistral 3-pass consistency, n=50. | (none in production) |
| `scripts/consistency_test_v2.py` | move → `scripts/experiments/` | Experiment 003 — entity-only consistency with corrected sampling. | (none in production) |
| `scripts/cost_test_graphiti_bulk.py` | move → `scripts/experiments/` | Bulk endpoint cost test, n=50. | (none in production) |
| `scripts/cost_test_graphiti_bulk_retry.py` | move → `scripts/experiments/` | Retry of failed bulk batches (pre-MAX_QUEUED_QUERIES bump). | (none in production) |
| `scripts/cost_test_graphiti_bulk_retry2.py` | move → `scripts/experiments/` | Second retry attempt, smaller batches. | (none in production) |
| `scripts/cost_test_graphiti_migration.py` | move → `scripts/experiments/` | Single-episode migration cost test, n=50. | (none in production) |
| `scripts/e1_select_sample.py` | move → `scripts/experiments/` | E1 sample selection. | (none in production) |
| `scripts/e1_run_cascade.py` | move → `scripts/experiments/` | E1 cascade orchestration (initial). | (none in production) |
| `scripts/e1_run_cascade_corrected.py` | move → `scripts/experiments/` | E1 corrected (custom_extraction_instructions path). | (none in production) |
| `scripts/e1_per_source_predicates.py` | move → `scripts/experiments/` | E1 per-source predicate count, corrected metric. | (none in production) |
| `scripts/e1_compare_metrics.py` | move → `scripts/experiments/` | E1 A vs B metrics comparison. | (none in production) |
| `scripts/e14_select_sample.py` | move → `scripts/experiments/` | E1.4 stratified sample selection (n=30). | (none in production) |
| `scripts/e14_run_cascade.py` | move → `scripts/experiments/` | E1.4 cascade orchestration. | (none in production) |
| `scripts/e14_per_source_predicates.py` | move → `scripts/experiments/` | E1.4 per-source predicate diversity. | (none in production) |
| `scripts/e16_rate_purity.py` | move → `scripts/experiments/` | E1.6 domain-purity human rating UI; surfaced taxonomic-mismatch finding. | (none in production) |
| `scripts/e16_analyze.py` | move → `scripts/experiments/` | E1.6 Spearman correlation against E1.4. | (none in production) |
| `scripts/e2_resolution_check.py` | move → `scripts/experiments/` | E2 entity-resolution diagnostic on six test entities. | (none in production) |
| `scripts/e2_alias_followup.py` | move → `scripts/experiments/` | E2 alias follow-up (Aaron AI variants etc.). | (none in production) |
| `scripts/e2_source_diversity.py` | move → `scripts/experiments/` | E2 episode count per entity. | (none in production) |
| `scripts/token_measurement_test.py` | move → `scripts/experiments/` | Experiment 005 — token reduction measurement. | (none in production) |

`scripts/experiments/` already contains four files (`e1_8_eval.py`, `e1_8_taxfree_cascade.py`, `e1_9_retroactive.py`, `e3_dreamer_substrate.py`); after the move it holds 32. **No collisions** between current `scripts/` filenames and existing `scripts/experiments/` filenames — verified by the file lists.

---

## C — MOVE TO `scripts/deprecated/`

Two files. New directory `scripts/deprecated/` is created. Per the user constraint on tier1, both are flagged.

| Current path | Action | Why | Referenced by |
|---|---|---|---|
| `scripts/consolidator_v0_1.py` | move → `scripts/deprecated/` | The reframe doc explicitly identifies "consolidator-as-separate-system" as the architectural mistake (its function moves into the dream phase). The 0.1 calibration findings (2026-04-29) showed alias-resolution-from-graph-features-alone has structural problems on this corpus that threshold tuning cannot address. Bespoke decision dissolves the layer. | (none in production); `scripts/consolidator_v0_1.py.bak` is in section D. |
| `scripts/tier1_migration.py` | move → `scripts/deprecated/` | One-shot completed 2026-04-30 (1,205 sources, 4,990 nodes, 22,289 edges). Under the bespoke decision the substrate this migrated **to** is being replaced; re-running the script against the bespoke substrate would not be the right move. **Flag (per Tier1 constraint):** the script's state file at `~/aaronai/experiments/tier1_migration_state.json` IS still consumed — `corpus_integrity.py:29` and `api.py:937` read it for the "graphiti coverage" report. **Moving the script does not affect the state file** (the state file lives in `~/aaronai/experiments/`, not `~/aaronai/scripts/`). The reader-vs-writer separation makes this safe. | (none in production); state file `~/aaronai/experiments/tier1_migration_state.json` consumed by `corpus_integrity.py` + `api.py`, not the script itself |

---

## D — DELETE (`.bak*` files)

19 files. Git history is the durable record of every prior version. Removing `.bak*` files is a cleanup, not a loss.

For each: action is `rm`. None is referenced by any production path.

| File | Approximate purpose |
|---|---|
| `scripts/api.py.bak.20260501-001427` | Pre-CV-pinning-strip / pre-F1 snapshot. |
| `scripts/consolidator_v0_1.py.bak` | Pre-0.1.5-patch (Jaccard, before containment metric). |
| `scripts/corpus_integrity.py.bak.20260501-021703` | Pre-F14 truncation snapshot. |
| `scripts/dream.py.bak` | Older dreamer (pre v1.1 score-band). |
| `scripts/dream.py.bak.20260501-002209` | Pre-F1 dreamer. |
| `scripts/graphiti_service.py.bak` | Pre-bulk-saga sidecar. |
| `scripts/graphiti_service.py.bak.20260501-185619` | Mid-rollback snapshot. |
| `scripts/graphiti_service.py.bak.20260502-022307` | Mid-rollback snapshot (rolled-back work). |
| `scripts/ingest.py.bak.20260501-004131` | Pre-F14 truncation snapshot. |
| `scripts/stage2_worker.py.bak.20260501-171928` | v2.0 → v2.1 transition. |
| `scripts/stage2_worker.py.bak.20260501-172531` | v2.1 patch step. |
| `scripts/stage2_worker.py.bak.20260501-185942` | v2.1 patch step. |
| `scripts/stage3_worker.py.bak.20260501-050354` | Pre-saga-split. |
| `scripts/stage3_worker.py.bak.20260501-050453` | Pre-saga-split. |
| `scripts/stage3_worker.py.bak.20260501-050719` | Pre-saga-split. |
| `scripts/stage3_worker.py.bak.20260501-173233` | Mid-v2.1. |
| `scripts/stage3_worker.py.bak.20260501-190357` | v2.1 final. |
| `scripts/watcher.py.bak` | Pre-in-process refactor (2026-04-30). |
| `scripts/watcher.py.bak.20260501-004131` | Pre-F14 truncation snapshot. |

Stage 3 alone has five `.bak` versions; Stage 2 has three. Both are visible in `git log` for the corresponding production files — no information is lost.

---

## E — UNCERTAIN

None. Every file in `scripts/` is classified above. The grep against api.py / systemd / cron / production scripts produced clean answers for each.

The `scripts/__pycache__/` directory exists and contains `.pyc` for `api`, `corpus_integrity`, `dream`, `ingest`, `stage3_worker`, `st_embedder`, `watcher` (notably no `.pyc` for `stage2_worker.py`). Not part of this plan, but Python regenerates `.pyc` on next import — `__pycache__/` is safe to remove at any time and has no bearing on the moves above. **Recommended but not in this plan: `rm -rf scripts/__pycache__/` after the moves complete, so stale entries for moved files don't linger.**

---

## Execution-step preview (NOT executed in this turn)

For when the plan is approved, the proposed mechanic is:

```bash
mkdir -p ~/aaronai/scripts/deprecated/

# Section B — 28 moves to scripts/experiments/
git mv scripts/{audit_expansion_draw,base_class_test,base_class_validation,base_class_audit_rerun, \
                briefing_generator_v2,briefing_test, \
                cascade_test,cascade_optimization_test, \
                consistency_test,consistency_test_v2, \
                cost_test_graphiti_bulk,cost_test_graphiti_bulk_retry,cost_test_graphiti_bulk_retry2,cost_test_graphiti_migration, \
                e1_select_sample,e1_run_cascade,e1_run_cascade_corrected,e1_per_source_predicates,e1_compare_metrics, \
                e14_select_sample,e14_run_cascade,e14_per_source_predicates, \
                e16_rate_purity,e16_analyze, \
                e2_resolution_check,e2_alias_followup,e2_source_diversity, \
                token_measurement_test}.py scripts/experiments/

# Section C — 2 moves to scripts/deprecated/
git mv scripts/consolidator_v0_1.py scripts/tier1_migration.py scripts/deprecated/

# Section D — 19 deletes
rm scripts/*.bak*

# Section E recommendation (post-move)
rm -rf scripts/__pycache__/
```

`git mv` keeps git history. After execution, a single commit with a body listing each move and delete (no Co-Authored-By trailer) would land the change.

---

## What this plan does NOT do

- Does not modify `api.py`, `corpus_integrity.py`, `tier1_migration.py`, or any other code. The `MIGRATION_STATE` path in `corpus_integrity.py:29` and the matching constant in `api.py:937` continue to point at `~/aaronai/experiments/tier1_migration_state.json` — unchanged by the move.
- Does not modify any systemd unit. Every `ExecStart` continues to point at a `scripts/<production>.py` path that remains valid.
- Does not touch the user crontab.
- Does not touch `~/aaronai/db/` (separate decision flagged in inventory; ChromaDB-era 550M directory).
- Does not delete `scripts/__pycache__/` (recommendation only).
- Does not touch the four files already in `scripts/experiments/` (`e1_8_eval.py`, `e1_8_taxfree_cascade.py`, `e1_9_retroactive.py`, `e3_dreamer_substrate.py`).

## Awaiting approval

Tell me to proceed and I will execute Sections B → C → D in order, then run `git status` and `git diff --stat` so you can review before the commit. No commit will be made until you give the second go-ahead.
