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).
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/configbind-mount; config baked into frozen image446e5807(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. EnvWT_CONFIG_HOST(defaultinfra-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
:3000both 403). Repo CREATE went via ana-docker localhost API (ssh infra-ops@10.250.50.70→curl localhost:3000/api/v1/user/repos, vh token from~/.config/tea/config.yml, operator-authorized one-time). PUSH went over internal git-SSHssh://git@10.250.50.70:222(works from nh3-dev; auths as vh).git initdefaulted tomaster→ renamedmainto 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: imageconfig/= 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/keysmint, 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: demoworldtree-worldtree-api-1:8080, personalworldtree-personal-worldtree-api-1:8081, pinnedworldtree-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_architectrole [Soong/soong-lab] in model_roles.yaml +ratatoskr-affect-full-allowin 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.yamlall 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.