type: create

title: deploy create should support external credential injection

type: feature

description: deploy create generates config.env but provides no mechanism to inject external credentials (API keys, tokens, etc.) at creation time. Operators must append to config.env after the fact, which mutates a build artifact. deploy create should accept --credentials-file or similar to include secrets in the generated config.env.


title: REGISTRY_TOKEN / imagePullSecret flow undocumented

type: bug

description: create_registry_secret() exists in deployment_create.py and is called during up(), but REGISTRY_TOKEN is not documented in spec.yml or any user-facing docs. The restart command warns "Registry token env var REGISTRY_TOKEN not set, skipping registry secret" but doesn't explain how to set it. For GHCR private images, this is required and the flow from spec.yml -> config.env -> imagePullSecret needs documentation.


title: Stack path resolution differs between deploy create and deployment restart

description: deploy create resolves --stack as a relative path from cwd. deployment restart resolves --stack-path as absolute, then computes repo_root as 4 parents up (assuming stack_orchestrator/data/stacks/name structure). External stacks with different nesting depths (e.g. stack-orchestrator/stacks/name = 3 levels) get wrong repo_root, causing --spec-file resolution to fail. The two commands should use the same path resolution logic.


title: deployment restart should update in place, not delete/recreate

description:
deployment restart deletes the entire namespace then recreates everything from scratch. This causes:

1. **Downtime** — nothing serves traffic between delete and successful recreate
2. **No rollback** — deleting the namespace destroys ReplicaSet revision history
3. **Race conditions** — namespace may still be terminating when up() tries to create
4. **Cascading failures** — if ANY container fails to start, the entire site is down with no fallback

Fix: three changes needed.

**A. up() should create-or-update, not just create.** Use patch/apply semantics for Deployments, Services, Ingresses. When the pod spec changes (new env vars, new image), k8s creates a new ReplicaSet, scales it up, waits for readiness probes, then scales the old one down. Old pods serve traffic until new pods are healthy.

**B. down() should never delete the namespace on restart.** Only on explicit teardown. The namespace owns the revision history. Current code: _delete_namespace() on every down(). Should: delete individual resources by label for teardown, do nothing for restart (let update-in-place handle it).

**C. All containers need readiness probes.** Without them k8s considers pods ready immediately, defeating rolling update safety. laconic-so should generate readiness probes from the http-proxy routes in spec.yml (if a container has an http route, probe that port).

With these changes, k8s native rolling updates provide zero-downtime deploys and automatic rollback (if new pods fail readiness, rollout stalls, old pods keep serving).

Source files:
- deploy_k8s.py: up(), down(), _create_deployment(), _delete_namespace()
- cluster_info.py: pod spec generation (needs readiness probes)
- deployment.py: restart() orchestration


title: Add credentials-files spec key for on-disk credential injection

description:
deployment restart regenerates config.env from spec.yml, wiping credentials that were appended from on-disk files (e.g. ~/.credentials/*.env). Operators must append credentials after deploy create, which is fragile and breaks on restart.

Fix: New top-level spec key credentials-files. _write_config_file() reads each file and appends its contents to config.env after writing config vars. Files are read at deploy time from the deployment host.

Spec syntax:
  credentials-files:
    - ~/.credentials/dumpster-secrets.env
    - ~/.credentials/dumpster-r2.env

Files:
- deploy/spec.py: add get_credentials_files() returning list of paths
- deploy/deployment_create.py: in _write_config_file(), after writing config vars, read and append each credentials file (expand ~ to home dir)

Also update dumpster-stack spec.yml to use the new key and remove the ansible credential append workaround from woodburn_deployer (group_vars/all.yml credentials_env_files, stack_deploy role append tasks, restart_dumpster.yml credential steps). Those cleanups are in the woodburn_deployer repo.