# PSD Clean ThothII Replacement Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace the disposable PSD ThothII installation without creating host identities and remove only its exclusive resources after the new Aritmolab journey passes. **Architecture:** Project A builds a separate `/srv/thothii` installation while the old resources remain an inert rollback boundary. The container keeps numeric UID/GID 10001 without a host account. Project B moves the Aritmolab integration to the accepted stack; exact legacy deletion is a final post-acceptance operation that excludes shared Chirone resources. **Tech Stack:** Linux ownership and identity checks, Docker Compose, native `tht`, Nginx/Aritmolab integration, protected evidence journals. ## Global Constraints - Never call `useradd`, `groupadd`, `usermod`, or edit `/etc/passwd`, `/etc/group`, `/etc/shadow`, or `/etc/gshadow`. - Treat UID/GID `10001:10001` as an unmapped numeric container identity only. - Never reuse `/home/chirone/thothii-data` for the replacement. - Never remove `omics_portal_omics_network`, `localllm_default`, `/home/chirone/chirone/etl/docs/evidence`, or any Omics Portal, LocalLLM, DWH, `dwh-auth`, Supabase, Authentik, ETL, or Superset resource. - Never run `docker system prune`, `docker network prune`, `docker volume prune`, or `docker compose down --volumes`. - Do not stop the old stack or start the new stack without the separate owner mutation gate already required by Project A. - Do not delete any legacy target until Project B automated PASS, human PASS, and explicit owner PASS are all recorded. --- ### Task 1: Bind the clean-replacement decision to the surveyed host **Files:** - Read: `/etc/passwd` - Read: `/etc/group` - Read: `/home/chirone/ThothII/compose.yaml` - Read: `/home/chirone/omics_portal/nginx/nginx.conf` - Record: protected Project A survey journal **Interfaces:** - Consumes: approved design `docs/superpowers/specs/2026-08-21-psd-clean-replacement-design.md`. - Produces: a redacted exact-target inventory and a `numeric_identity_unmapped=PASS` decision. - [ ] **Step 1: Prove that 10001 is not a host identity** ```bash if getent passwd 10001 >/dev/null || getent group 10001 >/dev/null; then printf '%s\n' 'numeric_identity_unmapped=FAIL' exit 1 fi printf '%s\n' 'numeric_identity_unmapped=PASS' ``` Expected: one PASS line. Do not continue if either lookup succeeds. - [ ] **Step 2: Revalidate the exclusive legacy containers and images** ```bash docker inspect --format '{{.Name}} project={{index .Config.Labels "com.docker.compose.project"}} image={{.Image}}' \ thothii-core-1 thothii-frontend-1 docker image inspect --format '{{.Id}} {{join .RepoTags ","}}' \ thothii-core:local thothii-frontend:local ``` Expected: exactly the two `thothii` project containers and two immutable image IDs. Record IDs, not environment variables or container configuration values. - [ ] **Step 3: Revalidate shared exclusions** ```bash docker network inspect --format '{{.Name}} project={{index .Labels "com.docker.compose.project"}}' \ omics_portal_omics_network localllm_default stat -c '%u:%g %a %n' /home/chirone/chirone/etl/docs/evidence ``` Expected: both networks exist and the external Evidence path remains outside the legacy data tree. - [ ] **Step 4: Record the survey checkpoint** Record only names, IDs, modes, ownership numbers, PASS/FAIL decisions, and timestamps in the protected journal. Never record container environment, auth files, API keys, or raw Nginx output. ### Task 2: Prepare the replacement roots without host accounts **Files:** - Create: `/srv/thothii/source` - Create: `/srv/thothii/operator` - Create: `/srv/thothii/data` - Create: `/srv/thothii/secrets` - Create: `/srv/thothii/pi-state` - Create: `/srv/thothii/workspace-registry` - Create: `/srv/thothii-backups` - Test: exact ownership/mode checks below **Interfaces:** - Consumes: `numeric_identity_unmapped=PASS` from Task 1. - Produces: isolated bind roots compatible with container UID/GID 10001 and operator UID/GID 1013:1006. - [ ] **Step 1: Create only the reviewed roots** ```bash sudo install -d -o 1013 -g 10001 -m 0750 /srv/thothii sudo install -d -o 1013 -g 1006 -m 0750 /srv/thothii/source sudo install -d -o 1013 -g 1006 -m 0750 /srv/thothii/operator sudo install -d -o 10001 -g 10001 -m 0750 /srv/thothii/data sudo install -d -o 10001 -g 1006 -m 0750 /srv/thothii/secrets sudo install -d -o 10001 -g 10001 -m 0750 /srv/thothii/pi-state sudo install -d -o 10001 -g 10001 -m 0750 /srv/thothii/workspace-registry sudo install -d -o root -g root -m 0700 /srv/thothii-backups ``` Expected: commands create directories only. They do not create identities. - [ ] **Step 2: Verify identity databases are unchanged and modes are exact** ```bash if getent passwd 10001 >/dev/null || getent group 10001 >/dev/null; then exit 1; fi stat -c '%u:%g %a %n' \ /srv/thothii /srv/thothii/source /srv/thothii/operator /srv/thothii/secrets \ /srv/thothii/data /srv/thothii/pi-state /srv/thothii/workspace-registry \ /srv/thothii-backups ``` Expected ownership/modes, in order: `1013:10001 750`, twice `1013:1006 750`, `10001:1006 750`, three times `10001:10001 750`, and `0:0 700`. - [ ] **Step 3: Commit documentation/code changes before runtime use** Replace the account-creation section of `docs/install/server.md` with the numeric ownership model: the invoking operator UID/GID owns source and operator paths, numeric 10001 owns only secrets and writable runtime paths, and the manual verifies both `getent` lookups remain empty. Remove every `useradd`, `groupadd`, `usermod`, `sudo -u thothii`, and `thothii-ops` instruction. Run the existing documentation gates, obtain review, commit, and push before Project A uses these roots. Runtime state under `/srv` is never committed. ### Task 3: Execute Project A with a stopped-but-intact legacy boundary **Files:** - Read: `docs/plans/2026-08-20-psd-server-project-a-standalone.md` - Record: protected Project A report and journal **Interfaces:** - Consumes: Task 2 roots and a separately approved Project A mutation gate. - Produces: Project A automated PASS and explicit human PASS while the old resources remain intact. - [ ] **Step 1: Close the old ThothII route using the separately approved exact route operation** Validate configuration before applying it. Do not change `/dwh/` or unrelated Omics routes. - [ ] **Step 2: Stop only the two old ThothII containers** Use the surveyed legacy Compose controller. Do not remove containers, images, networks, source, or data. Confirm Omics Portal, LocalLLM, DWH, `dwh-auth`, Supabase, Authentik, ETL, and Superset remain running. - [ ] **Step 3: Execute and close Project A** Follow the Project A plan and manual through its automated and human PASS decisions. On failure, stop the new stack and restart the still-present old containers; do not delete either installation. ### Task 4: Cut Aritmolab over in Project B **Files:** - Read: `docs/plans/2026-08-20-psd-server-project-b-authentik.md` - Read: `docs/testing/psd-server-project-b-manual.md` - Record: protected Project B report and journal **Interfaces:** - Consumes: accepted Project A candidate and the independent pre-Project-B gate. - Produces: a production route that no longer depends on the old container names. - [ ] **Step 1: Complete the mandatory pre-Project-B gates** Mac REST acceptance, the 48-hour/two-ETL observation, and `legacy-shared` revocation must be PASS. These DWH-key gates are independent from deleting the old ThothII application. - [ ] **Step 2: Execute Project B without deleting legacy resources** Follow the Project B plan. Keep the old containers stopped and intact until all automated checks pass. - [ ] **Step 3: Run the real Aritmolab acceptance** Prove the complete path from Aritmolab home and sidebar through authentication to frontend assets, API, SSE, and one completed workflow. Confirm the active route no longer resolves the legacy `thothii-core` or `thothii-frontend` services. - [ ] **Step 4: Record human and owner PASS** No cleanup command is authorized by technical success alone. Record the Project B human PASS and a separate owner decision explicitly authorizing the exact cleanup inventory from Task 5. ### Task 5: Delete only exclusive legacy ThothII resources **Files:** - Delete: `/home/chirone/ThothII` - Delete: `/home/chirone/thothii-data` - Record: protected final cleanup report **Interfaces:** - Consumes: Project B automated PASS, human PASS, owner PASS, and immutable IDs from Task 1. - Produces: no legacy ThothII application resources and no change to shared Chirone resources. - [ ] **Step 1: Revalidate the cleanup manifest immediately before deletion** Re-run Task 1. Stop if an image has another consumer, a legacy container is running, the production route still mentions a legacy service, or either filesystem path resolves outside its expected exact target. Record device/inode, ownership, and size; never record file contents. - [ ] **Step 2: Remove only the stopped legacy containers through their Compose project** Remove `thothii-core-1` and `thothii-frontend-1` without `--volumes`. Do not remove either shared network. - [ ] **Step 3: Remove only the two unreferenced legacy image IDs** Resolve tags to the immutable IDs recorded in Task 1 and prove no container references them before removal. Do not prune images globally. - [ ] **Step 4: Remove the two exact legacy filesystem trees** Delete only `/home/chirone/ThothII` and `/home/chirone/thothii-data` after their exact identities match the approved manifest. This operation is irreversible by design; no legacy session or state restore is promised after this point. - [ ] **Step 5: Verify shared resources and the production journey** Confirm both shared Docker networks, the external Evidence path, and every out-of-scope service still exist. Repeat the Aritmolab sidebar, authentication, frontend, API/SSE, and completed-workflow checks. Record `CLEAN_REPLACEMENT_PASS` only if all checks pass. ### Task 6: Commit the durable evidence references **Files:** - Modify: `PROJECT_STATE.md` - Modify: approved redacted report index only **Interfaces:** - Consumes: Project A, Project B, and cleanup evidence digests. - Produces: a secret-free durable state summary. - [ ] **Step 1: Update the state without secret-bearing evidence** Record candidate SHAs, image IDs, workspace SHA, report digests, gate decisions, deleted exact targets, and preserved shared resources. Protected journals and credentials stay outside Git. - [ ] **Step 2: Run documentation and secret gates** ```bash bash scripts/test-verify-workspace-install-docs.sh bash scripts/test-verify-dwh-auth-docs.sh bash scripts/auth-docs-smoke.sh git diff --check ``` Expected: every script exits zero and the diff check has no output. - [ ] **Step 3: Commit and push the secret-free state update** ```bash git add PROJECT_STATE.md git commit -m "docs: record PSD clean replacement completion" git push origin feat/dwh-rest-installation-auth ``` Expected: the push contains no `/srv` state, credential, protected journal, raw Nginx output, or legacy data.