Status
This page is authoritative. Anywhere else that something is described in the present tense, including the README, this page is the one that is right.
Verified
Section titled “Verified”Everything in this table has been stood up and exercised, not just reasoned about.
target=k3d, tier=light | Stood up, serves /health/ready, migrations ran |
| Bundled Postgres | 25 tables, app connects |
| Registering and signing in | Registered at /auth/register, self-verified at registration (fountain ADR 0011; just verify-email remains the escape hatch), reached /onboarding/step_1 and /conversations |
| The first admin | The first verified account is promoted in-app (FIRST_USER_ADMIN=true, fountain ADR 0011), audit-recorded as admin.role.granted. E2e-asserted via just promote-admin reporting it already admin; the admin pages themselves have not been driven by anything here |
| Provisioning a sandbox | Against the emulated data plane: a sprite is created and populated with the fountain skill and a /home/sprite/.env written into its filesystem |
| Completing a turn | Every time, and it stopped being a race. 34 of 34 conversations completed at fountain v0.6.1 + spritzer 0.5.0, including batches fired back to back (the pin is now v0.7.0, which has been through just e2e’s single conversation rather than a rerun of that batch — v0.7.0 changes nothing on this path) — the pacing that used to fail most. The prompt is written as stdin and comes back on stdout, so the round trip is real, not just an exit code. What completes is the echo — the emulator working as designed, which is why just verify-conversation strict refuses to run against it. Three fixes closed it: fountain#603 (a lost stdin write crashed the ConversationServer, and its restart orphaned the turn behind a reattach), spritzer#19 (an unupgraded GET on the exec path answered 426 instead of the session list), and spritzer#20 (an unrecognised command now holds its exec session open until stdin EOF). #67 holds the history of getting this wrong |
pg-dump → floci | Taken and restored, against every postgres mode. The CronJob dumps, uploads and size-verifies; just restore-drill restores the newest object into a throwaway database, matches its table count against live, and drops it. Non-destructive: the live database is untouched and only fountain remains afterwards. Exercised against the bundled Postgres (every just e2e), the CNPG cluster, and a referenced Postgres in another namespace — the last two once, by hand, after the dump learned to read the same DATABASE_URL source the app does (it was silently broken at cnpg) |
target=kubernetes on k3d | Applied and served, twice, against two different ingress controllers. postgres=reference against a Postgres in another namespace that chant never created, ingress=ingress in front of a real nginx controller, /health/ready answering {"database":"ok"} through the Ingress rather than a port-forward. Re-checked by just e2e-k8s on a three-node stand-in with k3s’s bundled Traefik as the class. Not yet applied to a managed cluster (#23) |
postgres=cnpg | The operator reconciles a real database. just operators, then postgres=cnpg: CNPG reports Cluster in healthy state, fountain migrates 23 tables into it, and /health/ready answers {"database":"ok"} |
k3d + tier=ha | Stands up, as one command. just operators, then the four-parameter just up on Make it durable: two app replicas that form an Erlang cluster (libcluster logs the connect), backed by a CNPG cluster at 2/2 ready, a PDB on each. Serves /health through just verify and /health/ready with the database ok. The app pods wait for the CNPG primary before starting; on a brand-new database one replica may restart once, losing the race to create the migrations table and winning the retry |
kubernetes + tier=ha | Applied and served, on the stand-in. just e2e-k8s on a three-node k3d cluster: two replicas land on different nodes, form an Erlang cluster through the headless Service (libcluster logs the connect), the PodDisruptionBudget applies, and /health/ready answers {"database":"ok"} through the Traefik Ingress against the referenced Postgres. Applied over a running light, so the in-place light→ha upgrade is exercised too. Still never a managed cluster (#23), and the data plane was never real — SPRITES_TOKEN stayed a placeholder |
Every target × tier builds, and the refused pairs refuse | Asserted in the unit tests on every push: kubernetes+ha and both lights build on their default seams; k3d+ha refuses seam by seam (bundled Postgres, then the spritzer emulator, then floci) until all three are overridden, then builds |
backups=barman-pitr | Taken and restored, repeatably. With postgres=cnpg + storage=floci on k3d: ContinuousArchiving reports True, an on-demand Backup through the barman plugin completes (base backup + WAL stream, real objects in the bucket), and just pitr-drill bootstraps a throwaway recovery Cluster from the ObjectStore, matches its table count against live, and deletes it — the drill is a recipe now, not a one-off. Not proven: the nightly ScheduledBackup firing on its own, and any of it against a real S3 bucket |
Does not work
Section titled “Does not work”Nothing, at these pins. The last entry — completing a turn — moved up to
Verified when spritzer 0.5.0 closed the race behind it. This section has
carried something for most of this repo’s life and will again; it is empty
because that one was fixed, not because nothing is ever broken here.
Builds, unexercised
Section titled “Builds, unexercised”monitoring=prometheus-operator | Builds only. Emitted nothing at all until the tier.metrics fix |
tls=cert-manager (issuance) | cert-manager installs and is Available, but no certificate has been issued, because a local cluster has no domain to issue against |
ingress=traefik, secrets=infisical, monitoring=prometheus-operator | Build, and a real API server accepts the output. No controller has reconciled any of them: Traefik ships with k3s but nothing routes through it here, Infisical needs a server to talk to, and kube-prometheus-stack is not installed (#22) |
ops/ | One Op: fountain-apply. behold discovers it and offers Run. The other eleven verbs in #3 do not exist |
Why the table reads like this
Section titled “Why the table reads like this”A documented claim rots the moment nothing re-checks it. So the specific claims here are asserted in tests where they can be, and this page prefers Builds only to a word that sounds better. The backup row in particular says “taken and restored” only because a restore has actually run; an unrestored backup is a hypothesis.
Most of the Verified table is re-asserted on every push, not just true at
the time it was written. just e2e, which is the whole of CI’s e2e job and
runnable on a laptop, stands up from nothing and checks readiness through to
the database, the master key surviving a re-run, the backup restoring and
matching live, the account path end to end, and every seam against a real API
server. The target=kubernetes rows have their own loop: just e2e-k8s
stands up a separate three-node stand-in, treats it as foreign, and re-checks
light and ha through a real Ingress — on every merge to main, on demand from
the Actions tab, and on any laptop. The rows neither loop covers are the ones
needing operators or a cluster this repo did not create, and those rows say
so.
The conversation gate is worth a note, because this page got it wrong three
times running. It asserted a result, then a pairing, then gave up and only
observed — each retreat because the outcome was a race no one could pin. It
now asserts the turn completes, which is not a return to optimism: the race is
closed upstream and 34 of 34 conversations completed at these pins. An orphaned
turn or a :command_exited fails the build and names the pin that must have
moved.