NAS STORAGE CONVERGENCE PLAN — blueflyNAS DS224+¶
Status: DRAFT FOR THOMAS'S REVIEW — no physical migration is authorized by this document. Evidence: NAS-AUDIT-EVIDENCE.md (this directory) + dated snapshot in evidence/2026-08-02/. Historical note: staged during the audit at Engineering-Standard/infrastructure/nas (formerly staged at /volume1/AgentPlatform/Catalog, retired) (retired). Date: 2026-08-02. Wave 6 LLM SoR restated 2026-09-02 (owner: inference-topology.md).
1. What the NAS is for (target operating model)¶
One volume (Btrfs, 5.3 TB, 25% used) serving five separated authorities:
| Authority | Path | Owns | Must exclude |
|---|---|---|---|
| Source & engineering | /volume1/AgentPlatform |
Applications (174 repos), curated docs (BluCity-Docs), LLM model library (SoR at LLM/; Mac/LM Studio is a client cache) |
live databases, container logs/caches, credentials, unmanaged .env, development worktrees |
| Container runtime | /volume1/docker |
services/* persistent data, databases, runtime config, logs, caches, deployment materialization | git clones (repos/), archives (_archive/), long-term backups, plaintext secret sprawl |
| User-private | /volume1/homes/bluefly |
SSH identity (~/.ssh 0600 — already proven), personal CLI config, restricted credentials pending 1Password injection | shared/service assets |
| Backup | new share /volume1/Backups (recommended) |
scheduled DB dumps, Hyper Backup targets, oracle backups, restore-test evidence | ad-hoc copies pretending to be backups |
| Archive | new share /volume1/Archive (recommended) |
migrations, preservation kits, recycled repos, retired deployments, historical dumps | anything still consumed |
Secret authority is 1Password (op CLI already installed). GitLab remains delivery authority; Oracle remains runtime/Beads authority; nothing here changes that.
Why the DS224+ is best used this way: it is a 2-bay SMB/Btrfs box — its highest-impact
roles are (a) canonical source library with snapshots, (b) model-weight SoR the Mac
must not own (/volume1/AgentPlatform/LLM; topology:
Engineering-Standard/standards/architecture/inference-topology.md), (c) always-on light
runtime (NAS Ollama, litellm, qdrant, clickhouse, cloudflared — not Oracle weights),
(d) backup/archive vault with Btrfs snapshots + retention. It should NOT be a build
farm, a secrets store on 777 shares, a second GitLab clone, or a Mac/Oracle model dump.
2. Headline findings (what forces this plan)¶
- Secrets exposure (worst finding): five private SSH keys, a TLS private key, and an
OCI API private key sit mode-777 on the SMB share (
AgentPlatform/config/{.ssh,ssl}); TLS material duplicated indocker/ssl(root 777); ~10 plaintext.envfiles acrossdocker/. 1Password exists on-box but isn't the injection path. - No snapshots on the source share: only
dockerhas snapshots; the share holding 174 repos (66 dirty) has none. - runtime/source inversion: running qdrant writes RW inside
Applications/; stopped containers (opencode,agent-ops) mounted the whole source share RW; git clones live inside the runtime share (docker/repos). - Compose fiction: 13 compose mount declarations point at
AgentPlatform/data/<service>paths that don't exist; the live stack actually usesdocker/services/*. Compose indocker/compose+docker/services/*is mutable and not Git-owned. - False backups:
docker/backups/{postgres,redis}empty since January; one-off July dumps inAgentPlatform/data; no restore-test evidence; Hyper Backup state unknown (root-only). - Two restart-looping containers (agent-tracer, cloudflared-contextcontrol) burning the small CPU.
- Naming/placement drift:
AgentPlatform/datais archives wearing a runtime name;_archivelives inside the runtime share; four empty dirs (anythingllm,artifacts,projects,cloudflared) indocker/;BluTown-minifyunclassified.
3. Dispositions (every current top-level entry)¶
KEEP (in place): AgentPlatform/{Applications, Knowledge, LLM, BluCity→, BluTown→, BluCity-Docs→ symlinks, #recycle}; docker/{services, agents, databases, cache, logs, .env†, config†, AGENTS.md}; homes/bluefly. (retention policy to set; †after Wave-1 secret extraction)
MOVE: Applications/qdrant/storage → docker/services/qdrant/storage (Wave 3);
docker/repos/ → Applications/
RENAME: none required beyond the moves (no case-only renames proposed).
MERGE: docker/opencode + stale AgentPlatform OpenCode references → one location under docker/services/opencode (Wave 3, after INVESTIGATE).
ARCHIVE: everything under #recycle per retention policy; _Archives repo group
stays archival (15 repos).
DELETE AFTER VERIFICATION (only after Wave-4 verification, operator-approved): docker/{anythingllm, artifacts, projects, cloudflared} (empty dirs), docker/config/.env.bak (once values live in 1Password), stale compose declarations.
INVESTIGATE: BluTown-minify; agent-tools (452 MB — does it contain source that belongs in Applications?); copaw-api; happy-server anonymous volume; the two restart loops; Knowledge & Scratch classification; docker/repos remote identities.
RUNTIME GENERATED: docker/{cache,logs}, service caches — get retention, not curation.
4. Execution waves (each = bounded receipt, own approval)¶
Wave 0 — Freeze & evidence (this document). Catalog created; inventories written; no further whole-share RW container mounts get started (operator discipline, no config change yet). RECOMMENDED OPERATOR ACTION (requires DSM administrator; NOT executed or authorized by this document itself): enable Snapshot Replication for AgentPlatform in DSM (~5 min) — the single cheapest risk reduction available.
Wave 1 — Secrets & ACL containment. Executor: NAS agent + operator. Approval: per-item.
Move the 5 SSH keys to ~/.ssh (0600) or retire duplicates (bluefly key already canonical
in ~/.ssh); OCI key + Termius creds + .op-env into 1Password; converge TLS to ONE
restricted store; migrate .env values to op run injection per stack (start:
docker/config/.env*, compose/.env). Update wiki-sync compose (only live consumer of
config/.ssh). Verification: every service restarts green with injected secrets; no
private key remains >0600 or SMB-exposed. Rollback: originals retained until each
service verifies.
Wave 2 — Git/IaC ownership. Executor: Mac dev + GitLab MR. Approval: MR review.
Import docker/compose + docker/services/*/compose into a Git-owned infra repo under
Applications (or the existing __Infra group repo that already owns them — INVESTIGATE
first, DON'T create a duplicate); fix the 13 dead AgentPlatform/data/<svc> mount
declarations to the real docker/services paths; deployment = materialized artifact
from the repo. Verification: docker compose config clean; live mounts == declared.
Wave 3 — Runtime path convergence. Executor: NAS agent. Approval: per-move. qdrant storage out of Applications (stop → same-fs mv → mount update → start → verify collection count); prohibit whole-share RW mounts (opencode/agent-ops patterns) in the corrected compose; consolidate opencode data; fix or retire the two restart-looping containers. Verification: zero container mounts under Applications; all services green.
Wave 4 — Backup & Archive authorities. Executor: operator (shares) + NAS agent (moves). Create /volume1/Backups + /volume1/Archive shares (DSM); move backup/archive material per migration map; schedule REAL recurring DB dumps; set retention (logs/cache/#recycle); then and only then delete the verified-empty dirs. Verification: restore one mariadb dump end-to-end and record it — a backup is proven by a restore.
Wave 5 — Repository deduplication. Executor: NAS agent, read-mostly. Approval: per-repo. Compare docker/repos/* remotes/HEADs to Applications copies → converge or retire; triage the 66 dirty repos (bounded batches of ~10: commit via MR, preserve branch, or classify as drift — same receipts pattern as the BLU convergence); classify BluTown-minify + _Archives group. Verification: one clone per remote on the NAS.
Wave 6 — LLM normalization. Recommendation: NO move off NAS. Topology owner:
Engineering-Standard/standards/architecture/inference-topology.md (do not fork).
/volume1/AgentPlatform/LLM is the only model-storage SoR (registry
LLM/llms.txt before download; Ollama blobs at LLM/ollama/data). Do not relocate
the library to Mac or Oracle. /volume1/docker/services/ollama-models is not
SoR (wrong-tag residue, not AgentPlatform). Mac $HOME/.ollama pulls are a defect,
not a second canonical store. Compose binds to /volume1/AgentPlatform/ollama/data
are fiction (path missing). Actions: keep weights on NAS; prune empty taxonomy dirs
if still empty; do not invent a second library. Compose/LiteLLM alias repair is
agent-docker work, not a docs move.
Wave 7 — Retention, monitoring, restore proof. Executor: operator + NAS agent. Quarterly restore test; snapshot schedule review; catalog refresh cadence (regenerate nas_projects.json monthly); dirty-repo count and secrets-exposure count become the KPIs (both must trend to zero).
5. Follow-on Bead specifications (create on Oracle — NOT from the NAS)¶
- "Contain NAS share-resident secrets" — parent: NAS storage convergence. AC: zero private keys/tokens >0600 or SMB-exposed; 1Password injection live for migrated stacks; receipts per secret. Executor: NAS agent + operator.
- "Converge Docker runtime paths and compose truth" — AC: live mounts == Git-owned compose; zero mounts under Applications; stale declarations removed. Executor: Mac dev (MR) + NAS agent (moves).
- "Create Backup and Archive authorities with retention" — AC: /volume1/Backups + /volume1/Archive exist; material moved per map; scheduled dumps running; one verified restore recorded. Executor: operator + NAS agent.
- "Deduplicate NAS repository estate" — AC: docker/repos empty or retired; one clone per remote; dirty count from 66 → 0 via MR/preserve/classify receipts. Executor: NAS agent.
- "Normalize LLM model stores" — AC: one SoR (
/volume1/AgentPlatform/LLM+LLM/llms.txt+LLM/ollama/data); docker/services/ollama-models not treated as canonical; empty taxonomy pruned; no relocation to Mac or Oracle. Executor: NAS agent. Topology: inference-topology.md. - "Restore-test and monitoring cadence" — AC: quarterly restore proof; monthly catalog refresh; KPI dashboard row in MORNING-DASHBOARD. Executor: operator.
6. What this plan does NOT do¶
No moves, renames, deletions, SMB/ACL changes, container restarts, or model relocation are performed by this document. Every wave returns to Thomas for approval with exact commands, consumers, verification, and rollback — the same receipt discipline used for the BLU root convergence (see #recycle/blu-root-convergence-20260802-142848/MOVE-MANIFEST.md as the worked example).