carlos / platform Public

Flagship cutover to `carlos ops litestream` is blocked on kass's db_path (and the unperformed §5 migration, #58) Issue open

Migrated from github.com/carlosframework/platform issue #216, opened 2026-08-16. GitHub issues are closed for this repo; see AGENTS.md, "Work is tracked on amadan, not GitHub".

Still outstanding: The litestream cutover is blocked on a multi-database db_path data-model decision that has not been made.

---

Recording where the generator takeover got to, with the evidence, so the next person starts from facts rather than a re-investigation.

Where it stands

#213 and #215 give carlos ops litestream everything it needs to own a box: unit-tenant DB trees, a refusal to shrink the replication set, per-path replica keys, and the registry-claims filter. The remaining blocker is data, not code.

The evidence

I staged a build on carlos-flagship-ie and generated to a temp path — nothing touched:

| current /etc/litestream.yml (hand-written, 5) | what the generator produces today (2) | | --- | --- | | /var/lib/carlos-app/home.kass.training/registry.db | — | | .../instances/5vepbveytb8y.db | — | | .../instances/eafu5brhjs26.db | — | | .../instances/m5tnnphtnm23.db | — | | /data/registry.db | /data/registry.db | | — | /data/console/console.db ✅ (new, see #200) |

Cutting over today would stop replicating four kass databases. Writing to /etc/litestream.yml would have been refused by #213's shrink guard — the guard doing exactly its job — but the underlying cause needs fixing either way.

Why

The kass route carries db_path=/data/home.kass.training.db, which does not exist. The data lives in the tenant's state directory:

/var/lib/carlos-app/home.kass.training/registry.db
/var/lib/carlos-app/home.kass.training/instances/{5vepbveytb8y,eafu5brhjs26,m5tnnphtnm23,ma248ch8zrg7}.db

That's the pre-migration path from the app-capabilities design §5, and stampDBPaths (internal/host/caps_pass.go) is deliberately conservative about it:

> An existing NON-EMPTY db_path this pass does not recognise ... is an operator's -db, pointing at where the data lives RIGHT NOW ... overwriting it with the post-migration path would point litestream at a file that does not exist yet and silently stop replicating a live database.

Sound rule. It just assumes the pre-migration file exists, and here neither does — the migration (#58) was never performed.

A second, smaller finding

instances/ma248ch8zrg7.db (created 2026-08-07) is not in the hand-written config and is therefore not replicated at all. A human wrote the list once; the tenant kept creating instances. This is the argument for generating it, in one line.

What would unblock it

Options, roughly in order of how well they fit the existing design:

  1. Finish the §5 migration for kass (#58), letting stampDBPaths stamp the real path — but note d.DBs[0] stamps only the FIRST declared database, and kass has five. A tenant whose data is a tree needs more than one column.
  2. Point the route at the tree: db_path = /var/lib/carlos-app/home.kass.training, which #213's tree walk then expands to all five. One registry write, no migration — but it makes db_path mean "file or directory" depending on backing, which wants a deliberate blessing.
  3. Teach stampDBPaths about multi-database apps — the manifest already carries data.dbs as a list; only the stamp is single-valued.

I stopped rather than pick, because it's a data-model decision on a live tenant, and the guard makes the status quo safe.

Not blocked on this

carlos-tito-ie has the same shape for different reasons (its config comes from the legacy titogo ops litestream, 27 databases under /data/titogo/) and wants its own decision.