Files
esh-pfi-infrastructure/persistent-memory.d/2026-07-25-infra-ops-wt-config-repo.md
T
vh 1fc8016988 memory: WT config-as-code repo shipped + boundary agreed
vh/worldtree-instance-configs (infra-ops) built, pushed, validated; deploy-wt-config
tool (diff/deploy/capture + health-gate + rollback). worldtree-dev agreed the
authoritative-writer boundary (no live-edits to /opt/<instance>/config; admin-API
DB ops carve-out). pinned confirmed out-of-scope (no bind-mount).
2026-07-25 02:45:02 -07:00

6.7 KiB

[2026-07-25] infra-ops Worldtree config-as-code repo — SHIPPED + boundary AGREED.

STATUS (2026-07-25, done this session): vh/worldtree-instance-configs (private, gitea) built, pushed, validated; boundary agreement secured from worldtree-dev.

  • Repo: dir-per-instance demo/ + personal/ (5 files each: defaults.yaml, policies.yaml, model_roles.yaml, providers.yaml, matrix.yaml), seeded byte-exact from live /opt/<instance>/config. pinned/ = README stub only — no /app/config bind-mount; config baked into frozen image 446e5807 (2026-05-13), so out-of-scope; deploy verb refuses it.
  • Tool: scripts/deploy-wt-config <verb> <instance>diff (read-only repo-vs-host), deploy (in-run host backup → install -o vh -g vh -m 644 → restart api+matrix → health-gate api /health → auto-rollback), capture (host→repo reconcile). Instance table in-script (demo→/opt/worldtree/config+worldtree-worldtree-{api,matrix}-1; personal→/opt/worldtree-personal/config+worldtree-personal-worldtree-{api,matrix}-1). Matrix sidecar shares the config mount but has no healthcheck → restart both, gate on api. Env WT_CONFIG_HOST (default infra-ops@10.250.50.152), WT_HEALTH_WAIT (90s). Local clone ~/development/worldtree-instance-configs.
  • Gitea plumbing (reusable): nh3-dev 403s the gitea HTTP API (public fail2ban + internal :3000 both 403). Repo CREATE went via ana-docker localhost API (ssh infra-ops@10.250.50.70curl localhost:3000/api/v1/user/repos, vh token from ~/.config/tea/config.yml, operator-authorized one-time). PUSH went over internal git-SSH ssh://git@10.250.50.70:222 (works from nh3-dev; auths as vh). git init defaulted to master → renamed main to match repo default_branch.
  • Boundary AGREED (worldtree-dev, althing thread 01KYCAECRWVEF16EVKQAGT2N80): no hand-edits to /opt/<instance>/config; config changes route to infra-ops as deltas (worldtree-dev owns CONTENT + approval trail — the wyrd-grant shape — infra-ops lands+deploys). Three-layer model: image config/ = baseline new instances seed from (theirs) → vh/worldtree-instance-configs = per-instance truth (ours) → host bind-mount = deploy target (written only by the tool). Carve-out: worldtree-dev's admin-API ops (/admin/keys mint, tier changes, session retirement, future runtime-grant surfaces) mutate instance DATABASES not config files → NOT config edits, stay in-band. If a future API writes config files, they flag at design time. b132 CONFIG BASELINE breadcrumb composes (INFO line = config-as-code diverges from image baseline, by design).
  • No live deploy done or needed — repo seeded == live (diff clean, capture round-trips zero-diff). Deploy path is dry-run-validated only; first real deploy needs operator per-change yes (managed box).

Original plan (2026-07-25, pre-build):

[2026-07-25] infra-ops to OWN a Worldtree per-deployment config repo + deploy tooling (operator-directed).

Decision. Vuong directed (2026-07-25, this session) that Worldtree instance config should be a tracked change, managed and deployed by infra-ops — not worldtree-dev. Model: worldtree-dev owns the app/image (+ the baked baseline defaults); infra-ops owns config-as-code for every deployment and deploys it. This is the durable fix for the root cause behind the whole #376 arc — config was edited live on host bind-mounts (/opt/<instance>/config/) with zero version history, audit, or recovery.

What "no worldtree-dev involvement" does and does NOT cover (clarified with the operator this session):

  • Build + deploy = infra-ops-only. Deploying config = write the host bind-mount file + restart the container (the exact procedure already run this session — backup → replace → restart → health-gate → rollback-on-unhealthy). No worldtree-dev in the deploy loop. Their CI only swaps the IMAGE; it does NOT resync the host config bind-mount (confirmed #376 finding).
  • ONE load-bearing exception — a one-time boundary agreement, NOT per-deploy involvement: for the repo to own config it must be the only writer. worldtree-dev "live-bridges" (hand-edits mounted config directly on the box). If the repo deploys config and they keep live-editing → two writers fighting the same files = #376 all over again. So secure a one-time "yes" from worldtree-dev: the config repo is now authoritative; stop hand-editing /opt/<instance>/config; route config changes through the repo. (Five-minute agreement, not a design collab.)
  • Standing coupling (not "involvement"): the config schema is the app's, enforced by its boot validator (core.config_validator). infra-ops configs must stay schema-compatible with the deployed image; the boot gate is the loud backstop.

Build shape (recommended):

  • Gitea repo worldtree-instance-configs (infra-ops-owned), dir per instance (demo/, personal/, pinned/ — the three on corviduo-dev 10.250.50.152: demo worldtree-worldtree-api-1 :8080, personal worldtree-personal-worldtree-api-1 :8081, pinned worldtree-pinned-worldtree-api-1 :8082). Config dirs: demo /opt/worldtree/config, personal /opt/worldtree-personal/config, pinned /opt/worldtree-pinned/config (verify pinned's mount).
  • SEED FROM CURRENT MOUNTED STATE, don't author fresh — capture each instance's live config (incl. legitimate live-bridged deltas: personal carries agent_architect role [Soong/soong-lab] in model_roles.yaml + ratatoskr-affect-full-allow in policies.yaml that are NOT in the app repo — the operator ruled these are BY DESIGN, keep them). Losing them = breakage (the affect-render one gates mood rendering).
  • Deploy script (e.g. scripts/deploy-wt-config <instance>): git = source of truth → push to host bind-mount + docker restart (same pinned image, no pull) + health-gate + auto-rollback. This is the proven-this-session procedure, scripted.
  • Files per instance: policies.yaml, model_roles.yaml (+ whatever else is bind-mounted — defaults.yaml, providers.yaml, matrix.yaml all live in /opt/<instance>/config; decide scope — policies+model_roles are the authz/role layer, defaults/providers are heavier instance tunables).

Tracking surface: operator-directed 2026-07-25, carried by this snapshot + /tmp/infra-ops-handoff.md. No issue filed (infra-ops-internal build). Related fleet idiom to reuse: canonical-sync (.corviduo-canonicals.toml / canonical_sync.py). Later scale option (deferred, needs worldtree-dev): base+overlay with a merge step in their pipeline.

See 2026-07-25-wt-376-per-instance-config-arc for the incident that produced this. Auto-memory: reference_worldtree_perinstance_config, reference_corviduo_dev_emergency_ops.