Files
ThothII/.superpowers/sdd/container-task-3-report.md

8.1 KiB

Container Packaging Task 3 Report

Status

Implemented the multi-stage core application image, non-root runtime, pinned Pi installation, container entrypoint, context exclusions, and an in-image health smoke test.

TDD / Build Evidence

Initial RED:

docker build -f docker/core.Dockerfile -t thothii-core:test .
ERROR: failed to build: resolve : lstat docker: no such file or directory

The first sandboxed attempt could not access the Docker socket; the authorized rerun reached the builder and failed for the expected reason: the Dockerfile did not exist.

GREEN build:

sh -n docker/core-entrypoint.sh docker/smoke/core-smoke.sh
docker build --progress=plain -f docker/core.Dockerfile -t thothii-core:test .

Result: shell syntax exited 0; Docker build exited 0. A final rebuild after tightening .dockerignore also exited 0 and transferred only 17.60 kB of changed context (the initial clean build transferred 1.02 MB).

Runtime and Entrypoints

  • Runtime user is 10001:10001 (thoth), never root.
  • Runtime contains Node v22.19.0 and Python 3.12.13. Python 3.12 is intentional because the harness declares requires-python = ">=3.12" and also satisfies the deployment floor of 3.11+.
  • Pi is installed exactly as @earendil-works/pi-coding-agent@0.80.3; its build-time and runtime version probes both reported 0.80.3.
  • server starts /app/backend/dist/server.js; doctor routes to tht doctor; preprocess routes to the future-facing tht preprocess command; explicit tht ... and arbitrary CLI arguments route to the installed tht binary.
  • The gate extension's typebox runtime dependency is installed from the harness lockfile.

Smoke and Diagnostic Results

docker run --rm thothii-core:test doctor
config: error - configuration is invalid or unreadable
data_root: ok

Result: expected exit 1 for absent mounted workspace configuration, with no traceback and no secret-bearing validation detail.

docker run --rm --entrypoint /app/docker/smoke/core-smoke.sh thothii-core:test
backend listening on http://127.0.0.1:8787
v22.19.0
Python 3.12.13
core smoke: ok

Result: exit 0. The script asserted non-root execution, tht --help, pi --version, runtime version floors, and GET /health through curl. Fastify's returned display address was loopback; the inspected container environment is HOST=0.0.0.0, and the compiled server passes that value to app.listen.

docker run --rm thothii-core:test tht --version
0.1.0

Result: arbitrary tht entrypoint exited 0.

An explicit runtime assertion checked UID 10001, exact Node and Pi versions, Python 3.11+, and the absence of /app/harness/.env and /app/harness/workspaces; it exited 0.

Image Size and Containment Inspection

docker image inspect thothii-core:test --format '{{.Size}} {{json .Config.User}} {{json .Config.Env}}'
221419008 "10001:10001" [...runtime paths and version metadata only...]

Image size: 221,419,008 bytes (about 211.2 MiB).

docker history --no-trunc thothii-core:test was inspected. It contains only Dockerfile commands, the pinned public package name/version, base-image metadata, and non-sensitive runtime variables; no credentials or customer paths were found. An in-image filename scan found only /app/harness/.pi/settings.json among .env, key/certificate, and settings-name candidates; that tracked Pi file contains theme/startup preferences, not secrets. The build asserts .env and workspace directories are absent.

.dockerignore excludes VCS/agent state, all environment files except examples, package-manager credential files, SSH/private-key and certificate formats, local virtualenvs/node_modules/caches, backend runtime data, customer workspaces, sessions, artifacts, indexes, corpus, and deployment mount content.

Self-review

  • git diff --check is clean.
  • Entrypoint processes use exec, preserving container signal handling.
  • Backend production dependencies are pruned; TypeScript build tools remain in the build stage.
  • The writable /data root is owned by UID 10001; application payload remains root-owned and read-only to the runtime user.
  • CA certificates and curl are present for HTTPS integrations and health probing.
  • No existing source, customer workspace, secret, or unrelated progress-ledger change is included in the task commit.

Concerns

  • The tht preprocess command is deliberately a future-facing routing contract; its CLI group is scheduled in the Evidence/preprocessing plan and is not implemented in the current harness.
  • Python dependencies are range-resolved because the existing harness has no Python lockfile. The Pi package, Node runtime, and package-lock-backed Node dependency sets are pinned/reproducible.
  • The image was built and smoked on Docker Desktop arm64. The chosen official multi-arch base images and Pi package are architecture-neutral at the package level, but amd64 still needs a CI build/smoke before being advertised as verified.

Reproducibility Review Fix

The original image pinned Pi's direct version in the Dockerfile but resolved its transitives at build time, and pip resolved all harness dependencies from ranges. Both paths now consume committed locks.

Lock generation

Pi uses the minimal docker/pi-runtime/package.json and its committed npm v3 lock. It was generated with:

npm install --package-lock-only --ignore-scripts --no-audit --no-fund \
  --prefix docker/pi-runtime

The package manifest specifies exact @earendil-works/pi-coding-agent version 0.80.3; a lock inspection confirmed that same resolved package version. Docker installs it with:

npm ci --omit=dev --ignore-scripts --no-audit --no-fund

The Python lock was generated directly from the harness production metadata plus one explicit, pinned PEP 517 build-backend input—not from a host pip freeze:

uv pip compile harness/pyproject.toml docker/python-runtime/build-requirements.in \
  --universal \
  --python-version 3.12 \
  --no-emit-package tht \
  --generate-hashes \
  --custom-compile-command \
    'uv pip compile harness/pyproject.toml docker/python-runtime/build-requirements.in --universal --python-version 3.12 --no-emit-package tht --generate-hashes --output-file docker/python-runtime/requirements.lock' \
  --output-file docker/python-runtime/requirements.lock

pytest, ruff, and testcontainers are absent. All production direct and transitive packages are exact and hashed. setuptools==80.9.0 is explicit so the local harness install can use --no-build-isolation without an unpinned build-time resolution. Refresh instructions are in docker/LOCKS.md.

No-cache rebuild and verification

Final build command:

docker build --no-cache -f docker/core.Dockerfile -t thothii-core:test .

Result: exit 0. The logs showed Pi 0.80.3, Node v22.19.0, a hash-enforced Python dependency install, explicit setuptools==80.9.0, and a non-isolated local tht wheel build. No isolated build-dependency download occurred.

Fresh runtime checks:

docker run --rm --entrypoint /app/docker/smoke/core-smoke.sh thothii-core:test
backend listening on http://127.0.0.1:8787
v22.19.0
Python 3.12.13
core smoke: ok

docker run --rm thothii-core:test tht --version
0.1.0

/opt/venv/bin/pip check
No broken requirements found.

An in-container package inspection reconfirmed Pi 0.80.3. Non-root UID, runtime version floors, doctor's expected concise exit 1/no traceback, /health, and arbitrary tht routing all passed.

The full filename containment scan found no .env, PEM, private-key, P12, or PFX file in /app; /app/harness/workspaces remains absent. Image environment and docker history --no-trunc were re-inspected and contain only public package/build commands and non-sensitive runtime metadata.

Final locked image size:

220003986 10001:10001

That is 220,003,986 bytes (about 209.8 MiB), 1,415,022 bytes smaller than the original image.

Remaining concern: the universal lock is resolved for Python 3.12 and includes hashes/markers for all supported platforms, but only Linux arm64 has been built and smoked locally; amd64 remains a CI verification gate.