From cace697fea67e073a08ee00c5759a05225ae089f Mon Sep 17 00:00:00 2001 From: User Date: Thu, 20 Aug 2026 16:13:09 +0200 Subject: [PATCH] docs: plan self-contained install docs fixtures --- ...e-install-docs-fixture-self-containment.md | 247 ++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 docs/superpowers/plans/2026-08-20-workspace-install-docs-fixture-self-containment.md diff --git a/docs/superpowers/plans/2026-08-20-workspace-install-docs-fixture-self-containment.md b/docs/superpowers/plans/2026-08-20-workspace-install-docs-fixture-self-containment.md new file mode 100644 index 00000000..fd4c5109 --- /dev/null +++ b/docs/superpowers/plans/2026-08-20-workspace-install-docs-fixture-self-containment.md @@ -0,0 +1,247 @@ +# Workspace Install Docs Fixture Self-Containment 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:** Make the workspace-install documentation verifier pass from a clean environment without inheriting `TMPDIR` or `THT_AUTH_CONFIG_ROOT`. + +**Architecture:** Keep the existing Bash verifier and test runner structure. The test runner removes both ambient variables at the production-verifier boundary; the verifier supplies its own safe temporary-root fallback and creates one empty authentication-config directory for each Compose-rendering fixture, then proves the rendered core mount has the exact source, target, and read-only mode. + +**Tech Stack:** Bash (`set -euo pipefail`), Docker Compose configuration rendering through `scripts/compose-with-preflight.sh`, inline Node.js JSON assertions, Git. + +## Global Constraints + +- Modify only `scripts/verify-workspace-install-docs.sh` and `scripts/test-verify-workspace-install-docs.sh` during implementation. +- Do not modify Compose, authentication runtime code, documentation examples, the PSD server, Docker resources, or the legacy stack. +- Every production-verifier `mktemp` call must use `/tmp` when `TMPDIR` is absent and must continue to honor an explicitly provided `TMPDIR`. +- Do not mutate or export the caller's environment. +- Each of the local installation, server installation, and canonical Compose fixtures must own a distinct empty authentication-config directory inside its fixture root. +- Each generated fixture environment must set `THT_AUTH_CONFIG_ROOT` explicitly. +- Each Compose fixture must assert the exact authentication mount source, target `/run/thothii-auth`, and `read_only: true` on the rendered core service. +- Temporary cleanup must remain bounded to directories returned by `mktemp`. +- No command in this plan starts, stops, reloads, builds, or modifies the PSD or legacy server stack. + +--- + +### Task 1: Make the verifier fixtures self-contained + +**Files:** +- Modify: `scripts/test-verify-workspace-install-docs.sh:11` +- Modify: `scripts/verify-workspace-install-docs.sh:917,1066,1865-1946,1948-2050,2133-2215` +- Test: `scripts/test-verify-workspace-install-docs.sh` + +**Interfaces:** +- Consumes: `compose.yaml` requires host variable `THT_AUTH_CONFIG_ROOT` and renders it as the core bind mount target `/run/thothii-auth` with read-only mode. +- Produces: `scripts/verify-workspace-install-docs.sh --fixtures-only` succeeds with `TMPDIR` and `THT_AUTH_CONFIG_ROOT` absent; every generated Compose fixture supplies and verifies its own authentication mount source. + +- [ ] **Step 1: Add the clean-environment regression boundary** + +Change only the production-verifier invocation near the beginning of `scripts/test-verify-workspace-install-docs.sh`: + +```diff +-"$root/scripts/verify-workspace-install-docs.sh" --fixtures-only >"$output" ++env -u TMPDIR -u THT_AUTH_CONFIG_ROOT \ ++ "$root/scripts/verify-workspace-install-docs.sh" --fixtures-only >"$output" +``` + +- [ ] **Step 2: Run the regression test and retain the first RED result** + +Run: + +```bash +env -u TMPDIR -u THT_AUTH_CONFIG_ROOT \ + bash scripts/test-verify-workspace-install-docs.sh +``` + +Expected: non-zero exit; stderr contains `TMPDIR: unbound variable`. This proves the test reaches the production verifier with no ambient temporary root. + +- [ ] **Step 3: Add the production-verifier temporary-root fallback** + +Replace the five unsafe `mktemp` calls in `scripts/verify-workspace-install-docs.sh`; leave the calls that already use `${TMPDIR:-/tmp}` unchanged: + +```diff +- update_fixture="$(mktemp -d "${TMPDIR%/}/thoth-source-update.XXXXXX")" ++ update_fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth-source-update.XXXXXX")" + +- repair_root="$(mktemp -d "${TMPDIR%/}/thoth-crlf-repair.XXXXXX")" ++ repair_root="$(mktemp -d "${TMPDIR:-/tmp}/thoth-crlf-repair.XXXXXX")" + +- fixture="$(mktemp -d "${TMPDIR%/}/thoth local install.XXXXXX")" ++ fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth local install.XXXXXX")" + +- fixture="$(mktemp -d "${TMPDIR%/}/thoth server install.XXXXXX")" ++ fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth server install.XXXXXX")" + +- fixture="$(mktemp -d "${TMPDIR%/}/thoth-install-fixtures.XXXXXX")" ++ fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth-install-fixtures.XXXXXX")" +``` + +- [ ] **Step 4: Run the test and retain the second RED result** + +Run: + +```bash +env -u TMPDIR -u THT_AUTH_CONFIG_ROOT \ + bash scripts/test-verify-workspace-install-docs.sh +``` + +Expected: non-zero exit after the earlier documentation fixtures progress; output contains `THT_AUTH_CONFIG_ROOT`. This isolates the remaining incomplete Compose-fixture input. + +- [ ] **Step 5: Make the local installation fixture own and verify its auth root** + +Apply these exact changes inside `verify_local_installation_example`: + +```diff +- local fixture source_copy operator_dir copied_example env_file ++ local fixture source_copy operator_dir copied_example env_file auth_config_root + fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth local install.XXXXXX")" + trap 'rm -rf "$fixture"' RETURN +@@ + source_copy="$fixture/ThothII source" + operator_dir="$fixture/operator files" +- mkdir -p "$source_copy/deploy/pi" "$operator_dir" ++ auth_config_root="$operator_dir/auth config" ++ mkdir -p "$source_copy/deploy/pi" "$operator_dir" "$auth_config_root" +@@ + "THT_WORKSPACE_GIT_SSH_KEY_FILE=$operator_dir/git-ssh-key" \ + "THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=$operator_dir/git-known-hosts" \ ++ "THT_AUTH_CONFIG_ROOT=$auth_config_root" \ + >"$env_file" +@@ +- node - "$rendered" <<'NODE' ++ node - "$rendered" "$auth_config_root" <<'NODE' + const fs = require("fs"); +-const config = JSON.parse(fs.readFileSync(process.argv[2], "utf8")); ++const [path, authConfigRoot] = process.argv.slice(2); ++const config = JSON.parse(fs.readFileSync(path, "utf8")); + if (Object.keys(config.services).sort().join(",") !== "core,embedding,embedding-model-init,frontend,qdrant") { + throw new Error("local installation example must render the internal semantic stack"); + } ++const authMount = (config.services.core.volumes || []).find( ++ (mount) => mount.target === "/run/thothii-auth", ++); ++if (!authMount || authMount.source !== authConfigRoot || authMount.read_only !== true) { ++ throw new Error("local installation example must mount its fixture auth root read-only"); ++} + const output = JSON.stringify(config); +``` + +- [ ] **Step 6: Make the server installation fixture own and verify its auth root** + +Apply these exact changes inside `verify_server_installation_example`: + +```diff +- local fixture source_copy operator_dir copied_example env_file backup_root ++ local fixture source_copy operator_dir copied_example env_file backup_root auth_config_root + fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth server install.XXXXXX")" + trap 'rm -rf "$fixture"' RETURN +@@ + operator_dir="$fixture/server operator files" + backup_root="$fixture/server backups" ++ auth_config_root="$operator_dir/auth config" + mkdir -p "$source_copy/deploy/pi" "$source_copy/deploy/workspaces" \ +- "$operator_dir/data/workspace-secrets" "$operator_dir/pi-state" "$operator_dir/workspace-registry" "$backup_root" ++ "$operator_dir/data/workspace-secrets" "$operator_dir/pi-state" "$operator_dir/workspace-registry" \ ++ "$auth_config_root" "$backup_root" +@@ + "THT_WORKSPACE_REGISTRY_ROOT=$operator_dir/workspace-registry" \ + "THT_BACKUP_ROOT=$backup_root" \ ++ "THT_AUTH_CONFIG_ROOT=$auth_config_root" \ + "THT_SERVER_WORKSPACE_CONFIG=$source_copy/deploy/workspaces/server-sessions.yaml.example" \ +@@ +- node - "$rendered" <<'NODE' ++ node - "$rendered" "$auth_config_root" <<'NODE' + const fs = require("fs"); +-const config = JSON.parse(fs.readFileSync(process.argv[2], "utf8")); ++const [path, authConfigRoot] = process.argv.slice(2); ++const config = JSON.parse(fs.readFileSync(path, "utf8")); + if (Object.keys(config.services).sort().join(",") !== "core,embedding,embedding-model-init,frontend,qdrant") { + throw new Error("server installation example must render the internal semantic stack"); + } + const core = config.services.core; + const frontend = config.services.frontend; ++const authMount = (core.volumes || []).find((mount) => mount.target === "/run/thothii-auth"); ++if (!authMount || authMount.source !== authConfigRoot || authMount.read_only !== true) { ++ throw new Error("server installation example must mount its fixture auth root read-only"); ++} +``` + +- [ ] **Step 7: Make the canonical local/server fixture own and verify its auth root** + +Apply these exact changes inside `verify_compose_fixtures`: + +```diff +- local fixture profile rendered ++ local fixture profile rendered auth_config_root + fixture="$(mktemp -d "${TMPDIR:-/tmp}/thoth-install-fixtures.XXXXXX")" + trap 'rm -rf "$fixture"' RETURN +- mkdir -p "$fixture/data/workspace-secrets" "$fixture/pi-state" "$fixture/workspace-registry" ++ auth_config_root="$fixture/auth-config" ++ mkdir -p "$fixture/data/workspace-secrets" "$fixture/pi-state" \ ++ "$fixture/workspace-registry" "$auth_config_root" +@@ + "THT_PI_STATE_ROOT=$fixture/pi-state" \ + "THT_WORKSPACE_REGISTRY_ROOT=$fixture/workspace-registry" \ ++ "THT_AUTH_CONFIG_ROOT=$auth_config_root" \ + "THT_SERVER_WORKSPACE_CONFIG=$fixture/server-sessions.yaml" \ +@@ +- node - "$rendered" "$profile" <<'NODE' ++ node - "$rendered" "$profile" "$auth_config_root" <<'NODE' + const fs = require("fs"); +-const [path, profile] = process.argv.slice(2); ++const [path, profile, authConfigRoot] = process.argv.slice(2); + const config = JSON.parse(fs.readFileSync(path, "utf8")); +@@ + const core = config.services.core; ++const authMount = (core.volumes || []).find((mount) => mount.target === "/run/thothii-auth"); ++if (!authMount || authMount.source !== authConfigRoot || authMount.read_only !== true) { ++ throw new Error(profile + ": core must mount its fixture auth root read-only"); ++} + for (const target of [ +``` + +- [ ] **Step 8: Run the focused regression test to GREEN** + +Run: + +```bash +env -u TMPDIR -u THT_AUTH_CONFIG_ROOT \ + bash scripts/test-verify-workspace-install-docs.sh +``` + +Expected: exit 0 with all existing positive and negative fixture checks accepted; no `TMPDIR` or `THT_AUTH_CONFIG_ROOT` error. + +- [ ] **Step 9: Run direct acceptance and syntax checks** + +Run: + +```bash +env -u TMPDIR -u THT_AUTH_CONFIG_ROOT \ + bash scripts/verify-workspace-install-docs.sh --fixtures-only +bash -n scripts/verify-workspace-install-docs.sh +bash -n scripts/test-verify-workspace-install-docs.sh +bash scripts/auth-docs-smoke.sh +``` + +Expected: both verifier commands and both syntax checks exit 0; `auth-docs-smoke.sh` prints its PASS summary. + +- [ ] **Step 10: Verify scope, whitespace, and absence of unsafe expansions** + +Run: + +```bash +git diff --check +git status --short +rg -n '\$\{TMPDIR%/\}' scripts/verify-workspace-install-docs.sh +git diff -- scripts/verify-workspace-install-docs.sh scripts/test-verify-workspace-install-docs.sh +``` + +Expected: `git diff --check` exits 0; `git status --short` lists only the two implementation scripts; the `rg` command exits 1 with no matches; the diff contains only the clean-environment regression call, five temporary-root fallbacks, three fixture-owned auth roots/environment entries, and three rendered-mount assertions. + +- [ ] **Step 11: Commit the verified fix** + +```bash +git add scripts/verify-workspace-install-docs.sh scripts/test-verify-workspace-install-docs.sh +git commit -m "test: make install docs fixtures self-contained" +``` + +Expected: one commit containing exactly the two implementation files. Do not push, merge, or change the detached-HEAD state.