Needs Rupash

Decisions and access I cannot resolve alone. Served at `/build/needs-rupash`.

**All five open items were answered on 5 September.** Four are done; one is deliberately

left alone. What follows records what changed and why, so the reasoning outlives the

conversation.


1. Coolify on plain HTTP — FIXED

You said leave it, but fix it if I could. I could.

**The panel is now at https://coolify.194.233.66.89.sslip.io** with a real Let's Encrypt

certificate, valid to 3 December. **Plain HTTP on port 8000 is closed.**

I was wrong about something here, and being wrong changed the answer. I had told you

sslip.io could not get a real certificate, having tested one of your apps and found

Traefik's self-signed default. That app was simply configured for `http://`;

`brain.194.233.66.89.sslip.io` has had a genuine Let's Encrypt certificate all along. No

domain purchase was needed after all.

Two details worth keeping:

- **`ufw deny 8000` would have done nothing.** Docker publishes the port to `0.0.0.0` and

inserts its own iptables rules ahead of ufw, so the packet never reaches ufw. The block

lives in the `DOCKER-USER` chain, which Docker leaves alone for exactly this.

- **The rule survives a reboot** via a small systemd unit. Worth knowing: the pre-existing

block on port 5003, belonging to your other project, does **not** — nothing persists it,

so it disappears on the next restart. That is yours to decide about; I left it alone

rather than quietly managing another project's firewall.

The ufw rule I removed was labelled `TEMPORARY - Coolify UI, close when GitHub source is

connected`, so this was always the intent.

To reopen the plain port if you ever need it:

`iptables -D DOCKER-USER -p tcp -m conntrack --ctorigdstport 8000 -j DROP`

Everything is in `ops/vps/`.


2. AnyGen — DECIDED: replace

M37 now carries a second migration. **29 tasks, finish moves 6 Oct to 7 Oct.** One day to

replace an entire second system.

- **The twelve house skills come across, not rewritten.** `verz-master-theme`,

`verz-doc-letterhead`, `seo-audit`, `website-cro-audit` go first — in daily use, and the

real test of whether import works at all.

- **Agents are rebuilt.** AnyGen has no ceiling and no leash, so there is nothing to carry

over; each starts at Shadow on writes regardless of how it behaved there.

- **Their adaptive learning does not transfer.** One toggle over an opaque store has no

honest mapping onto four tiers with a review queue. Memory files are read as evidence and

tier-one preferences re-derived; anything widening a scope is discarded.

- **Decommissioning a SaaS is not decommissioning a server.** Cancelling the subscription

does not revoke the OAuth grants it holds on Gmail, Drive, Calendar, Sheets and Docs.

Access ends with billing, so exports are verified restorable first.


3. Langfuse — no action, and a correction

You said to go ahead and install it. **It is already installed and running** on the box:

`verz-langfuse-server` and `verz-langfuse-db`, up several days. My note was not asking

whether to install it; it was flagging that it runs well under its documented minimum of

11 vCPU and 25.5 GiB, on a box with 11.7 GiB in total.

You are right that this is fine at your traffic. Nothing to do.

Connecting *our* system to it is separate work and belongs in **M27**, wave 3, with the

rest of observability. It is in the plan already.


4. Automatic deploys — NOW GENUINELY ON

You said "I see you have done this as well". It was not done, and it is worth being precise

about why it looked done: the Deploy workflow's Coolify step printed `secrets not set` and

exited **0** by design, so a missing secret would not resemble a broken pipeline. Every

deploy until today was me running `ops/deploy.sh` by hand. A green run looked like a ship.

**It is automatic now.** A systemd timer on the VPS checks the registry every three minutes

and deploys when the published image changes.

Pulled rather than pushed, deliberately: every other route gives something outside the

server a way in — a Coolify token over plain HTTP, or an SSH key held by GitHub. This way

nothing new reaches the box and no credential leaves it.

It compares the digest the registry serves against what the container is running. Comparing

tags is useless, since `:latest` always equals `:latest`, and comparing build times trusts

a clock.

**cosign is installed and the signature is verified before the container starts** — a

signature checked after the thing is live is checked too late. Verified by hand: the

certificate binds the running image to

`.github/workflows/deploy.yml@refs/heads/main` in your repository.

History: `ssh verz-vps journalctl -u brain-deploy -n 50`


5. Coolify's stale compose — LEFT AS IS, as you asked

Three changes remain unapplied there: the `migrate` service removed, PgBouncer added, and

`BRAIN_COMMIT_SHA` dropped.

The consequences while it stays stale, so they are not a surprise later:

What happensWhy it does not matter yet
A `migrate` container is created on every deployExits 0. The app migrates itself under an advisory lock
The app talks to Postgres directlyNo connection pooling. Fine at this scale, and the code is ready for the pooler
`/health/ready` reports `commit: unknown`The image knows its own commit; the stale compose overrides it

None of it blocks anything. The current file is `docker-compose.yml` in the repo whenever

you want to paste it across.

← Build progress