From 503a775b9ff76ea69768e257b77cf92810d8d494 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 31 Jul 2026 19:27:40 +0000 Subject: [PATCH] fix(cloud): ensure-postgres bootstrap before teqo readiness check Warm Cloud snapshots often have PostgreSQL online without the teqo role/DBs. start_postgres previously gated on teqo_ready, exited before bootstrap_databases, and marked the environment INSTALL_FAILED even though agents still ran. Also pin DATABASE_URL and assert migrations in cloud-setup so a silent no-op migrate cannot slip through. Co-authored-by: Francisco Solla --- .cursor/cloud-setup.sh | 27 +++++++++++++++++--- .cursor/ensure-postgres.sh | 52 ++++++++++++++++++++++++++++++-------- docs/CHANGELOG-AGENTS.md | 2 ++ 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/.cursor/cloud-setup.sh b/.cursor/cloud-setup.sh index 334be2aa..9a50046f 100755 --- a/.cursor/cloud-setup.sh +++ b/.cursor/cloud-setup.sh @@ -20,16 +20,35 @@ if [ ! -f .env ]; then echo "[cloud-setup] wrote .env from .env.example (local-only values)" fi +TEQO_URL='postgresql://teqo:teqo@localhost:5432/teqo' +TEQO_TEST_URL='postgresql://teqo:teqo@localhost:5432/teqo_test' + +assert_migrated() { + local db_url="$1" + local label="$2" + local count + count="$(PGPASSWORD=teqo psql "${db_url}" -Atc 'SELECT COUNT(*) FROM payload_migrations' 2>/dev/null || echo 0)" + if [ "${count}" -lt 1 ]; then + echo "[cloud-setup] ERROR: ${label} has no payload_migrations after migrate (got '${count}')" >&2 + exit 1 + fi + echo "[cloud-setup] ${label}: ${count} migrations applied" +} + # Dev database (teqo) and test database (teqo_test). +# Pin DATABASE_URL on both — do not rely on dotenv alone (JIT snapshots have +# seen a silent no-op migrate when the URL was only in a freshly written .env). echo "[cloud-setup] migrating teqo..." -pnpm migrate +DATABASE_URL="${TEQO_URL}" pnpm migrate +assert_migrated "${TEQO_URL}" teqo echo "[cloud-setup] migrating teqo_test..." -DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo_test pnpm migrate +DATABASE_URL="${TEQO_TEST_URL}" pnpm migrate +assert_migrated "${TEQO_TEST_URL}" teqo_test echo "[cloud-setup] seeding teqo..." -pnpm db:seed:minimal +DATABASE_URL="${TEQO_URL}" pnpm db:seed:minimal echo "[cloud-setup] seeding teqo_test..." -DATABASE_URL=postgresql://teqo:teqo@localhost:5432/teqo_test pnpm db:seed:minimal +DATABASE_URL="${TEQO_TEST_URL}" pnpm db:seed:minimal echo "[cloud-setup] OK — minimal database ready (dev + test)." echo "[cloud-setup] gate:fast/gate:push need no DB; use pnpm push (not raw git push --no-verify)." diff --git a/.cursor/ensure-postgres.sh b/.cursor/ensure-postgres.sh index aaaf4832..60eddbc0 100755 --- a/.cursor/ensure-postgres.sh +++ b/.cursor/ensure-postgres.sh @@ -1,15 +1,27 @@ #!/usr/bin/env bash # Cursor Cloud VMs have no Docker and cannot run docker compose (overlayfs fails inside # the agent container). Native PostgreSQL matches the local DATABASE_URL contract. +# +# Important: "server accepting connections" ≠ "teqo role/DBs exist". A warm snapshot +# often has the cluster online with no app databases yet. Never gate cluster start on +# teqo readiness — bootstrap runs after the server is up. set -euo pipefail PG_VERSION="${PG_VERSION:-16}" PG_CLUSTER="${PG_CLUSTER:-main}" +# pg_ctlcluster / systemctl can report "started" before the postmaster accepts TCP. +READY_ATTEMPTS="${PG_READY_ATTEMPTS:-15}" +READY_SLEEP_SECS="${PG_READY_SLEEP_SECS:-1}" -pg_ready() { +teqo_ready() { PGPASSWORD=teqo psql -h localhost -U teqo -d teqo -c 'SELECT 1' >/dev/null 2>&1 } +server_ready() { + pg_isready -h localhost -p 5432 >/dev/null 2>&1 \ + || sudo -u postgres psql -c 'SELECT 1' >/dev/null 2>&1 +} + detect_pg_version() { if [ -d "/etc/postgresql" ]; then ls /etc/postgresql/ 2>/dev/null | sort -nr | head -1 @@ -18,8 +30,19 @@ detect_pg_version() { echo "${PG_VERSION}" } +wait_for_server() { + local attempt + for attempt in $(seq 1 "${READY_ATTEMPTS}"); do + if server_ready; then + return 0 + fi + sleep "${READY_SLEEP_SECS}" + done + return 1 +} + start_postgres() { - if pg_ready; then + if server_ready; then return 0 fi @@ -28,15 +51,17 @@ start_postgres() { if command -v pg_ctlcluster >/dev/null 2>&1 && [ -n "${version}" ]; then sudo pg_ctlcluster "${version}" "${PG_CLUSTER}" start 2>/dev/null || true - sleep 2 - pg_ready && return 0 + if wait_for_server; then + return 0 + fi fi if command -v systemctl >/dev/null 2>&1; then sudo systemctl start "postgresql@${version}-${PG_CLUSTER}" 2>/dev/null || \ sudo systemctl start postgresql 2>/dev/null || true - sleep 2 - pg_ready && return 0 + if wait_for_server; then + return 0 + fi fi echo "[ensure-postgres] ERROR: postgres is installed but not accepting connections" >&2 @@ -59,10 +84,17 @@ WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'teqo_test')\gexec SQL } -if command -v psql >/dev/null 2>&1 && [ -d "/etc/postgresql" ]; then +ensure_ready() { start_postgres bootstrap_databases - pg_ready + if ! teqo_ready; then + echo "[ensure-postgres] ERROR: teqo databases exist but connection as teqo/teqo failed" >&2 + exit 1 + fi +} + +if command -v psql >/dev/null 2>&1 && [ -d "/etc/postgresql" ]; then + ensure_ready echo "[ensure-postgres] OK (existing cluster)" exit 0 fi @@ -70,7 +102,5 @@ fi echo "[ensure-postgres] installing postgresql-${PG_VERSION} (Ubuntu package; local dev uses PG 17 via Docker)..." sudo apt-get update -qq sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "postgresql-${PG_VERSION}" "postgresql-client-${PG_VERSION}" -start_postgres -bootstrap_databases -pg_ready +ensure_ready echo "[ensure-postgres] OK" diff --git a/docs/CHANGELOG-AGENTS.md b/docs/CHANGELOG-AGENTS.md index 86482849..9ab99811 100644 --- a/docs/CHANGELOG-AGENTS.md +++ b/docs/CHANGELOG-AGENTS.md @@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente --- +**Recently resolved (2026-07-31):** **Cloud `ensure-postgres` falso negativo no start** — o script tratava “role/DBs `teqo` prontos” como “Postgres aceitando conexões”. Em snapshot warm o cluster já está `online` sem role/DBs; `start_postgres` falhava com `postgres is installed but not accepting connections` **antes** de `bootstrap_databases`, o `start` do `environment.json` saía ≠0 e a UI marcava `INSTALL_FAILED` mesmo com o agente utilizável. Fix: separar `server_ready` (`pg_isready` / peer) de `teqo_ready`, bootstrap após o server up, retry no wait; `cloud-setup.sh` pina `DATABASE_URL` e asserta `payload_migrations` pós-migrate (no-op silencioso visto no JIT). Ruído cosmético no mesmo log (dirs de recording, `.installed` de plugins ENOENT) é race do exec-daemon — não é do Teqo. + **Recently resolved (2026-07-31):** **Pass 4 — auditoria de engenharia autônoma + guardrails das misses** — primeira execução em modo autônomo (Cursor Cloud) da skill engineering-audit, com precheck solitário (pool desligado) e primeiro harvest de `kind:agent-miss` (escopo OPS2: nasce `docs/GUARDRAILS.md`). **P0:** os 4 globals públicos (`site-settings`/`home`/`metadata`/`privacy-policy`) aceitavam qualquer autenticado no `update` — JWT de campanha (liderança inclusa) editava o site público via `/api/globals/*`; lockdown `payloadAdminOnly` + pins + guarda ([PR #91](https://github.com/fsolla/teqo/pull/91); editores perdem escrita nos globals de config deliberadamente). **P1:** `seed-posts.mjs` chamava `dieWithLabel` sem importar ([PR #92](https://github.com/fsolla/teqo/pull/92), com guarda de presença de import + `DAY_MS` single-source + ESLint lib→utilities sem type-import + guarda de `overrideAccess` omitido). **Misses:** #73 (deadlock `municipality_rels` — classe reproduzida: 7 violações int + 11 deep links e2e; migração para o alocador com teste de classe reescrito classe-agnóstico + guarda de 3 regras, [PR #93](https://github.com/fsolla/teqo/pull/93)); #52 (Drawer por célula em 3 listas de chips → `CampaignListSheetProvider` + invariante dev + guarda, [PR #94](https://github.com/fsolla/teqo/pull/94)); #53 (portão de readiness do autenticador virtual) + #54 (guarda de goto não assentado + convenção TESTING.md) em [PR #95](https://github.com/fsolla/teqo/pull/95); #83 fechada (guarda `agent:ship` já viva). **Registrado, não retry-fixed:** spec de chips de `campaignLeaderships` falha deterministicamente em dev na árvore limpa (nenhum POST dispara; prod 48/48 verde) — causa raiz via debug workflow (P4-L). Artefatos: seção Pass 4 no plano de qualidade, 15 linhas novas no ledger (2 stale fechadas: P3-A/P3-B), plano [`entrega-engenharia-p4.md`](docs/plans/entrega-engenharia-p4.md) com ondas P4-A→P4-L + mapa de guardas + defer+gatilho. **Recently resolved (2026-07-31):** **CI build skip para diffs fora da árvore buildável** — `scripts/build-affected.mjs` + `classifyBuildScope` (núcleo em `test-affected-core.mjs`) decidem `run|none`; job `build-scope` barato no `ci-pr.yml` e o job `build` (Postgres + `pnpm build`) só roda em `mode=run`. Docs/tests/tooling/workflows pulam o build; `src/`, `public/` e configs do Next (`next.config`/`tsconfig`/`tailwind`/`postcss`/`components.json`/lockfile) forçam. `gate:ci` espelha. Push em `main` (`ci.yml`) continua sempre full.