0000_easy_slipstream already created lists/list_shares/list_items and the
calendars unique constraint, but 0001_lists_schema re-created those tables and
0001_calendars_user_url_unique was an orphan (not in _journal) — so a cold
`drizzle-kit migrate` against an empty DB failed with ERROR 1050 'Table lists
already exists'. Dev only survived because its DB was built incrementally; CI
is the first cold migrate and exposed it.
Regenerated a single 0000_baseline.sql from schema.ts. Verified on a fresh
mariadb:11: migrate succeeds, schema is structurally identical to the running
dev DB, `drizzle-kit generate` reports no drift, and all 238 API tests pass.
Local dev DBs must be rebuilt (drop + db:migrate); no prod exists.
- api job: runs-on ubuntu-latest, if pull_request, parallel with fast-checks (no needs:)
- services: mariadb:11 with healthcheck.sh --connect --innodb_initialized options
(--health-start-period=30s for MariaDB 11 InnoDB cold-start, --health-retries=10)
- DB_HOST: mariadb (Docker-executor confirmed by D-PROBE-02)
- Throwaway creds: familysync/testpass scoped to ephemeral service container (T-08-03)
- No actions/cache (D-PROBE-04)
- Node mysql2 readiness poll via --input-type=commonjs inline script, 90s deadline
(no mysql CLI in runner image per D-PROBE-03; Pitfall 11 belt-and-suspenders)
- db:migrate (drizzle-kit migrate); drizzle push never used (T-08-04, MariaDB unsafe)
- pnpm --filter @familysync/api test: full DB-backed API test suite
- on: pull_request + push branches:[main]; workflow env MILESTONE: v1.1
- fast-checks job: runs-on ubuntu-latest, if pull_request
- Node 22 via actions/setup-node@v4 + corepack enable pnpm
- No actions/cache (D-PROBE-04: times out on this runner)
- pnpm install --frozen-lockfile, lint (no-op), typecheck, PWA unit tests
- DB-backed pnpm test intentionally absent from this job
The act_runner advertises ubuntu-latest/ubuntu-24.04/ubuntu-22.04; runs-on:
self-hosted matched no runner and the probe job stayed queued. Switch the
probe (and the plan key-link) to ubuntu-latest. ci.yml (Plans 02-04) must
use the same label.
- Probe-only workflow triggering on gsd/phase-08-gitea-ci branch only
- Answers P-01..P-11 + P-13: Node version, pnpm, runner mode (critical
fork Docker vs host), Docker socket, MariaDB service container spawn
and reachability on both hostnames, actions/cache, Playwright WebKit
deps, gitea-upload-artifact fork, and GITHUB_SHA short-SHA expression
- Uses healthcheck.sh --connect --innodb_initialized for MariaDB (never
the binary removed from mariadb:11 — Pitfall 11)
- Uses ChristopherHX/gitea-upload-artifact@v4 (not the official action
which aborts on Gitea with GHES detection — Pitfall 6 / T-08-SC)
- P-12 (docker login) deferred to Plan 04 — probe never references any
secret (T-08-01 compliant)
- All steps that may fail use continue-on-error: true so probe reports
findings instead of red-failing on expected unknowns
Deep review found the calendar 'populated state' assertions were vacuous:
- getByText('Nothing here').toHaveCount(0) targeted CalendarShell's EmptyState,
which CalendarShell NEVER renders (success branch always mounts ScheduleXCalendar;
EmptyState.tsx is dead code, imported by nothing). The check was permanently green
regardless of the seed — a regression dropping all events would have shipped green.
- .sx-react-calendar-wrapper renders on any successful auth, with or without events,
so it never proved the seed reached the UI.
Replaced the dead-EmptyState check with a real DB→UI proof: assert the seeded event
title 'Seeded Test Event' is rendered in the grid. Verified non-vacuous — passes with
the seed on both profiles; with /api/events mocked to [] the title is absent (would fail).
BL-02: the seed anchored the event at now+24h. Both phone profiles render the
month-agenda view of the CURRENT month, so on a month's last day 'tomorrow' falls into
the next month and vanishes from the grid, making the new visibility assertion date-fragile.
Re-anchored to noon-today (UTC) — always today's local date, always in the current-month view.
Verified: full 58-test suite passes both profiles; typecheck clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
global-setup.ts TRUNCATEs four tables against whatever DB_* points at, with no
production guard — an operator with prod DB_* still exported could wipe lists/
list_items/list_shares/calendar_events. The README promised a DEV_AUTH_BYPASS
guardrail the code never enforced. Adds a fail-closed guard mirroring
apps/api/src/auth/devBypass.ts: hard NODE_ENV==='production' check first, then
require DEV_AUTH_BYPASS==='true' before opening any DB connection. README updated
with the test-process env requirement (run command + CI runner env).
Verified: guard throws without DEV_AUTH_BYPASS; full 58-test suite passes with it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Playwright transpiles specs without typechecking (esbuild), so layout.spec.ts ran
green while `tsc -p tsconfig.e2e.json` failed: page.evaluate(() => document...)
callbacks need the DOM lib, and styleHandle.evaluate((el) => el.remove()) typed el as
Node (no .remove()). Phase 8 CI runs the typecheck gate, so this would have broken CI.
Adds DOM/DOM.Iterable to the e2e tsconfig (also covers 07-04 specs) and casts el to Element.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Replace ISO 8601 'T' separator with space in dtstart_utc value
- MariaDB TIMESTAMP requires 'YYYY-MM-DD HH:MM:SS', not 'YYYY-MM-DDTHH:MM:SSZ'
- Was causing 'Incorrect datetime value' error blocking all e2e harness runs
- Documents pnpm test:e2e run commands and single-profile / headed variants
- Documents DEV_AUTH_BYPASS=true must be set before API starts (Pitfall 5)
- States production compose MUST NOT set DEV_AUTH_BYPASS (Elevation of Privilege)
- Lists PLAYWRIGHT_BASE_URL and DB_* env vars (all credentials env-only, never hardcoded)
- States no storageState file is used (D-01 — no expiring session cookie)
- Describes globalSetup readiness gate + seed anchors (Milk/Eggs/Seeded Test Event)
- Notes Phase 8 CI scope and --with-deps WebKit requirement
- Add exclude: ['e2e/**', 'node_modules/**'] to vitest.config.ts test block
to prevent Playwright specs from being picked up by Vitest jsdom runner
- Add tsconfig.e2e.json extending main tsconfig with node types for
playwright.config.ts and e2e/**/* typecheck coverage
- Add @types/node to pwa devDependencies (required by playwright.config.ts)
- Update typecheck script to run both src and e2e tsc passes
- 191 unit tests still pass; no e2e import errors in vitest run
- Two projects: iphone/WebKit (iPhone 14) + pixel/Chromium (Pixel 7)
- serviceWorkers: 'block' on both profiles per D-02/Pitfall 15
- env-driven baseURL via PLAYWRIGHT_BASE_URL (D-08/Rule 8)
- globalSetup ref to e2e/global-setup.ts (Plan 02 implements)
- webServer manages vite only with reuseExistingServer (D-10)
- no storageState, no toHaveScreenshot per D-01/UI-SPEC Rule 6
- add e2e/global-setup.ts placeholder (stub) so config path resolves
Adds 07-UI-SPEC.md for Phase 7 (Mobile Test Harness). Documents the
assertable mobile-UI quality bar the harness enforces: touch-target
thresholds (≥44px), no-horizontal-overflow rule, two-profile viewport
matrix (iPhone 14/WebKit + Pixel 7/Chromium), role-based accessible name
requirements, empty/error-state copy anchors, screenshot omission rationale,
and CI portability rules. Locks D-01 through D-10 from CONTEXT.md as the
assertion contract.