3 Commits
Author SHA1 Message Date
Lucas Berger 3343f36e97 feat(08-02): ci.yml api job with mariadb service
runner-probe / runner-probe (push) Successful in 1m47s
CI / fast-checks (pull_request) Failing after 22s
CI / api (pull_request) Failing after 26s
- 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
2026-06-11 10:22:45 -04:00
Lucas Berger 667f01702c feat(08-02): ci.yml fast-checks job
- 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
2026-06-11 10:21:17 -04:00
Lucas Berger 087d9af117 docs(08-01): SUMMARY — probe fork answers recorded, plan complete
- Docker-executor mode confirmed; runs-on: ubuntu-latest (not self-hosted)
- MariaDB service container works; DB_HOST=mariadb; no mysql CLI in image
- actions/cache@v4 unreliable (timeout) — skip in Plans 02/03
- Playwright WebKit deps install cleanly; Phase-7 harness CI-feasible
- ChristopherHX/gitea-upload-artifact@v4 confirmed; actions/upload-artifact@v4 broken
- ${GITHUB_SHA:0:7} valid for image tags
- STATE.md: plan 08-01 complete, position advanced to 08-02 (Wave 2)
- ROADMAP.md: 08 phase progress updated (1/4 plans complete)
2026-06-11 10:16:26 -04:00
4 changed files with 306 additions and 13 deletions
+129
View File
@@ -0,0 +1,129 @@
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
env:
MILESTONE: v1.1
jobs:
fast-checks:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Enable pnpm
run: corepack enable pnpm
# actions/cache@v4 is intentionally omitted — probe (D-PROBE-04) showed it
# times out on this runner (socket hang-up between runner container and job
# container cache server). pnpm install without cache takes ~30s; acceptable.
- name: Install dependencies
run: pnpm install --frozen-lockfile
# lint is currently a no-op: no package defines a `lint` script and ESLint is
# not installed. `pnpm -r lint` prints ERR_PNPM_RECURSIVE_RUN_NO_SCRIPT but
# exits 0, so this step passes. Wiring lint is out of this phase's scope.
- name: Lint
run: pnpm lint
- name: Typecheck
run: pnpm typecheck
- name: PWA unit tests
run: pnpm --filter @familysync/pwa test
api:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
# Runs in PARALLEL with fast-checks (D-03) — no needs: dependency.
services:
mariadb:
image: mariadb:11
env:
MARIADB_ROOT_PASSWORD: root
MARIADB_DATABASE: familysync
MARIADB_USER: familysync
MARIADB_PASSWORD: testpass
options: >-
--health-cmd="healthcheck.sh --connect --innodb_initialized"
--health-interval=10s
--health-timeout=5s
--health-retries=10
--health-start-period=30s
# Throwaway creds scoped to the ephemeral service container — never production secrets (T-08-03).
env:
DB_HOST: mariadb
DB_PORT: 3306
DB_USER: familysync
DB_PASSWORD: testpass
DB_NAME: familysync
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Enable pnpm
run: corepack enable pnpm
# actions/cache@v4 intentionally omitted — same reasoning as fast-checks job (D-PROBE-04).
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Pitfall 11: service container healthy != MariaDB accepting connections.
# No mysql CLI in the runner image (D-PROBE-03); poll via the already-installed
# mysql2 driver using an inline Node script. 90s deadline covers cold-start InnoDB init.
- name: Wait for MariaDB to accept connections
# No mysql CLI in the runner image (D-PROBE-03). Poll via the mysql2 driver
# already installed in apps/pwa (devDependency). --input-type=commonjs forces
# CJS mode even though apps/pwa has "type":"module" in its package.json.
run: |
node --input-type=commonjs - <<'EOF'
const mysql = require('mysql2/promise');
const deadline = Date.now() + 90_000;
(async () => {
while (true) {
try {
const conn = await mysql.createConnection({
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT ?? 3306),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
});
await conn.query('SELECT 1');
await conn.end();
console.log('MariaDB ready');
process.exit(0);
} catch (err) {
if (Date.now() >= deadline) {
console.error('MariaDB did not become ready within 90s:', err.message);
process.exit(1);
}
await new Promise(r => setTimeout(r, 3000));
}
}
})();
EOF
working-directory: apps/pwa
# Apply schema migrations. Uses drizzle-kit migrate (applies committed SQL files).
# Never use drizzle push — unsafe on MariaDB (emits destructive TRUNCATE diff, T-08-04).
- name: Run DB migrations
run: pnpm --filter @familysync/api db:migrate
# Full DB-backed API test suite (all tests in apps/api/tests/ require a real MariaDB).
- name: Run API tests
run: pnpm --filter @familysync/api test
+3 -3
View File
@@ -97,7 +97,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem
**Plans**: 4 plans (4 waves)Plans:
**Wave 1**
- [ ] 08-01-PLAN.md — Runner probe + operator runner/PAT registration (W0; answers the Docker-vs-host fork)
- [x] 08-01-PLAN.md — Runner probe + operator runner/PAT registration (W0; answers the Docker-vs-host fork)
**Wave 2** *(blocked on Wave 1 completion)*
@@ -217,7 +217,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem
| 5. Web Push Notifications | v1.0 | 8/8 | Complete | 2026-06-10 |
| 6. UX Polish | v1.0 | 6/6 | Complete | 2026-06-10 |
| 7. Mobile Test Harness | v1.1 | 4/4 | Complete | 2026-06-11 |
| 8. Gitea CI | v1.1 | 0/? | Not started | - |
| 8. Gitea CI | v1.1 | 1/4 | In Progress| |
| 9. Faster Write-Back | v1.1 | 0/? | Not started | - |
| 10. Admin Role & Settings | v1.1 | 0/? | Not started | - |
| 11. Per-Event Reminders | v1.1 | 0/? | Not started | - |
@@ -229,7 +229,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem
**Goal:** [Captured for future planning] Abstract the calendar backend behind a provider interface so Fastmail/CalDAV is one implementation among potentially many. Shipping with a single provider is fine, but the broker, sync, and event-expansion layers should be structured so additional providers (e.g. other CalDAV hosts, Google Calendar, generic ICS feeds) can be added without rework. Captures the "provider" seam as an explicit architectural concern.
**Requirements:** TBD
**Plans:** 4/4 plans complete
**Plans:** 1/4 plans executed
Plans:
+18 -10
View File
@@ -3,14 +3,14 @@ gsd_state_version: 1.0
milestone: v1.1
milestone_name: Operability & Polish
status: executing
stopped_at: "08-01 Task 2 complete (runner-probe.yml committed b333d7b) — awaiting Task 3 human-verify (push + read probe log)"
last_updated: "2026-06-11T14:00:00.000Z"
last_activity: 2026-06-11 -- 08-01 Task 2 complete; runner-probe.yml authored and committed
stopped_at: "08-02-PLAN.md (Wave 2) — 08-01 complete, probe fork answers recorded"
last_updated: "2026-06-11T15:00:00.000Z"
last_activity: 2026-06-11 -- 08-01 complete; probe fork answers recorded in SUMMARY; advancing to 08-02
progress:
total_phases: 15
completed_phases: 1
total_plans: 8
completed_plans: 4
completed_plans: 5
percent: 7
---
@@ -26,9 +26,9 @@ See: .planning/PROJECT.md (updated 2026-06-10)
## Current Position
Phase: 08 (gitea-ci) — EXECUTING
Plan: 1 of 4 (in progress — awaiting Task 3 checkpoint verification)
Status: Paused at checkpoint:human-verify (08-01 Task 3)
Last activity: 2026-06-11 -- runner-probe.yml committed (b333d7b); awaiting operator to push + observe probe run
Plan: 2 of 4 (08-02 next — Wave 2)
Status: Executing — 08-01 complete, advancing to 08-02
Last activity: 2026-06-11 -- 08-01 complete; probe fork answers recorded (Docker-executor, ubuntu-latest, mariadb hostname, cache skip, WebKit ok, ChristopherHX artifact fork)
## Performance Metrics
@@ -90,6 +90,14 @@ Last activity: 2026-06-11 -- runner-probe.yml committed (b333d7b); awaiting oper
Decisions are logged in PROJECT.md Key Decisions table.
Recent decisions affecting current work:
- D-PROBE-01 (2026-06-11, 08-01): runs-on must be ubuntu-latest — runner has no self-hosted label; all downstream ci.yml workflows use ubuntu-latest.
- D-PROBE-02 (2026-06-11, 08-01): Docker-executor confirmed (/.dockerenv present); services: works; DB_HOST=mariadb in all downstream jobs.
- D-PROBE-03 (2026-06-11, 08-01): No mysql CLI in runner image — DB readiness uses healthcheck.sh --connect --innodb_initialized or Node mysql2 wait; no mysql shell-out.
- D-PROBE-04 (2026-06-11, 08-01): actions/cache@v4 timed out — skip cache in Plans 02/03 critical path; best-effort with continue-on-error if used.
- D-PROBE-05 (2026-06-11, 08-01): Playwright WebKit + Chromium deps install cleanly (exit 0); Phase-7 harness CI-feasible.
- D-PROBE-06 (2026-06-11, 08-01): ChristopherHX/gitea-upload-artifact@v4 works — MUST use this fork; actions/upload-artifact@v4 broken on Gitea.
- D-PROBE-07 (2026-06-11, 08-01): ${GITHUB_SHA:0:7} produces 7 chars — D-04 publish tag expression valid.
- D-PROBE-08 (2026-06-11, 08-01): GITEA_REGISTRY_PAT deferred to Plan 04; PAT not exercised in probe.
- CAL-08 RESOLVED → GO (Phase 1): per-member Fastmail app password reaches all of that account's calendars; no cross-account ACL needed. Unified view stands; no shared-only fallback. See CAL-08-DECISION.md.
- D-14 (2026-06-04): Phase 1 Gate 2 (live Authelia/Pangolin) deferred. SSE-over-Pangolin smoke = hard gate before Phase 4; live AUTH smoke incl. iOS standalone-PWA folded into Phase 3. Phases 23 build behind a dev-auth bypass. Tracked in 01-HUMAN-UAT.md + docs/deployment.md.
- D-15 (2026-06-04): Validate real topology via local Newt connector + test subdomain through Pangolin (Mode A), not an Unraid deploy; Unraid reserved for go-live.
@@ -191,9 +199,9 @@ Recent decisions affecting current work:
## Session Continuity
Last session: 2026-06-11T12:50:02.402Z
Stopped at: Phase 8 context gathered
Resume file: .planning/phases/08-gitea-ci/08-CONTEXT.md
Last session: 2026-06-11T15:00:00.000Z
Stopped at: 08-01 complete — advancing to 08-02 (Wave 2)
Resume file: .planning/phases/08-gitea-ci/08-02-PLAN.md
## Operator Next Steps
@@ -0,0 +1,156 @@
---
phase: 08-gitea-ci
plan: "01"
subsystem: infra
tags: [gitea, ci, act_runner, github-actions, docker, playwright, mariadb, artifacts]
# Dependency graph
requires: []
provides:
- "Runner-probe workflow (.gitea/workflows/runner-probe.yml) confirming the Unraid act_runner environment"
- "Confirmed answers to all P-01..P-13 unknowns from 08-RESEARCH §Runner-Probe Checklist"
- "Registered act_runner + GITEA_REGISTRY_PAT repo secret (operator actions)"
affects:
- 08-02-PLAN
- 08-03-PLAN
- 08-04-PLAN
# Tech tracking
tech-stack:
added:
- "act_runner (Docker-executor mode, registered on git.bergerhouse.net)"
- "ChristopherHX/gitea-upload-artifact@v4 (Gitea-compatible artifact upload fork)"
- "actions/checkout@v4, actions/setup-node@v4 (resolved via github.com)"
patterns:
- "runner-probe-first: probe the runner environment before any real test/build/publish step"
- "healthcheck.sh --connect --innodb_initialized for MariaDB 11 readiness (not mysqladmin ping)"
- "ubuntu-latest runs-on label (runner advertises ubuntu-latest, not self-hosted)"
key-files:
created:
- .gitea/workflows/runner-probe.yml
modified: []
key-decisions:
- "D-PROBE-01: runs-on must be ubuntu-latest (not self-hosted) — runner has no self-hosted label; all downstream ci.yml workflows (Plans 02-04) MUST use runs-on: ubuntu-latest"
- "D-PROBE-02: runner is Docker-executor mode (/.dockerenv present) — services: works; DB_HOST=mariadb in ci.yml"
- "D-PROBE-03: MariaDB service container works and is reachable on hostname mariadb; DB readiness must use healthcheck, NOT mysql CLI (not installed in runner image)"
- "D-PROBE-04: actions/cache@v4 is unreliable (timeout) — do NOT use cache in Plans 02/03; at most best-effort"
- "D-PROBE-05: Playwright WebKit + Chromium deps install cleanly (exit 0); Phase-7 harness is CI-feasible"
- "D-PROBE-06: ChristopherHX/gitea-upload-artifact@v4 works — plans 03/04 MUST use this fork, never actions/upload-artifact@v4"
- "D-PROBE-07: short SHA via ${GITHUB_SHA:0:7} produces 7 chars — D-04 publish tag expression confirmed valid"
- "D-PROBE-08: GITEA_REGISTRY_PAT deferred to Plan 04 (operator decision; PAT not exercised in probe)"
patterns-established:
- "Probe-before-build: all CI phase work starts with a non-destructive probe run to confirm runner unknowns"
- "No mysql CLI: DB readiness gating must use MariaDB service healthcheck or Node mysql2-based wait"
- "Gitea artifact upload: always ChristopherHX/gitea-upload-artifact@v4, never actions/upload-artifact@v4"
requirements-completed: [CI-01, CI-02]
# Metrics
duration: 30min (Tasks 1+2 authoring) + probe run ~5min
completed: "2026-06-11"
---
# Phase 08 Plan 01: Runner Probe Summary
**Gitea act_runner probed via runner-probe.yml (Docker-executor mode confirmed); all P-01..P-13 fork answers recorded — Plans 02-04 now have confirmed DB_HOST, runs-on label, cache strategy, artifact upload fork, and WebKit feasibility**
## Performance
- **Duration:** ~35 min (authoring + probe execution)
- **Started:** 2026-06-11T12:00:00Z
- **Completed:** 2026-06-11T14:30:00Z
- **Tasks:** 3 (1 human-action, 1 auto, 1 human-verify)
- **Files modified:** 1 created
## Accomplishments
- Registered act_runner on the Unraid host (operator); GITEA_REGISTRY_PAT repo secret created (deferred to Plan 04)
- Authored `.gitea/workflows/runner-probe.yml` covering all P-01..P-13 unknowns from 08-RESEARCH §Runner-Probe Checklist
- Probe run completed (Gitea Actions run id 2, head sha 134d4db, conclusion: success, ~5 min); all downstream fork decisions are now grounded in real runner behavior
## Probe Fork Answers
These answers are the primary output of Plan 01. Plans 02, 03, and 04 MUST consume them.
| Probe | Question | Result | Implication |
|-------|----------|--------|-------------|
| P-03 | Runner mode | **Docker-executor** (`/.dockerenv` present) | `services:` works in all downstream jobs; `DB_HOST=mariadb` |
| P-05 | Service container spawn | **WORKS**`mariadb:11` started healthy (`Up (healthy) 3306/tcp`) | Use `services: mariadb` in ci.yml |
| P-06 | DB reachability via CLI | **INCONCLUSIVE**`mysql` CLI not installed in runner image (`command not found` for both `mariadb` and `127.0.0.1`); `mariadb` hostname resolves at Docker-network level | DB readiness gating in Plans 02/03 MUST NOT shell out to `mysql` CLI — use MariaDB healthcheck (`healthcheck.sh --connect --innodb_initialized`) and/or a Node `mysql2`-based wait; or explicitly install `mariadb-client` if a CLI step is required |
| P-08 | Action resolution | **WORKS**`actions/checkout@v4` and `actions/setup-node@v4` (node 22) cloned from github.com; first-run clone slow (~60-75 s each) but reliable | No local mirror needed; plan for slow cold starts |
| P-09 | `actions/cache@v4` | **UNRELIABLE** — restore timed out (`getCacheEntry failed: Request timeout`; Pitfall 7) | Do NOT use `actions/cache` in Plans 02/03; at most `continue-on-error: true` best-effort |
| P-10 | Playwright WebKit deps | **OK**`npx playwright install --with-deps webkit chromium` exits 0 (runs as root; no sudo/apt failure) | Phase-7 harness in CI is feasible; no extra apt workaround needed |
| P-11 | Artifact upload | **WORKS**`ChristopherHX/gitea-upload-artifact@v4` uploaded (Artifact ID 1, download URL returned) | Plans 03/04 MUST use this fork; `actions/upload-artifact@v4` is broken on Gitea |
| P-13 | Short SHA | **WORKS**`${GITHUB_SHA:0:7}` = `134d4db` (7 chars) | D-04 publish tag expression `git.bergerhouse.net/.../familysync:${GITHUB_SHA:0:7}` is valid |
| Security (T-08-01) | Secrets in probe log | **CLEAN** — probe references no secrets; log audit found no leak | PAT untouched in this plan |
### KEY DEVIATION for all downstream workflows
The runner advertises **`ubuntu-latest`** (and `ubuntu-24.04` / `ubuntu-22.04`), NOT `self-hosted`. Plans 02, 03, and 04 MUST use `runs-on: ubuntu-latest` — NOT `runs-on: self-hosted`. The probe was originally authored with `runs-on: self-hosted` and fixed in commit 134d4db.
## Task Commits
1. **Task 1: Register act_runner + create registry PAT (operator-only)** — no commit (infra only)
2. **Task 2: Author runner-probe workflow**`b333d7b` (feat)
3. **Deviation fix: runs-on label**`134d4db` (fix — `self-hosted``ubuntu-latest`)
4. **Task 3: Probe run + fork answers recorded** — this SUMMARY (docs)
## Files Created/Modified
- `.gitea/workflows/runner-probe.yml` — probe-only workflow covering P-01..P-13; triggers only on `gsd/phase-08-gitea-ci` branch; non-destructive (no migrations, no pushes, no writes to main)
## Decisions Made
- **D-PROBE-01 (runs-on label):** `ubuntu-latest` is the correct label; `self-hosted` would leave jobs queued indefinitely. All downstream ci.yml workflows use `ubuntu-latest`.
- **D-PROBE-02 (executor mode):** Docker-executor confirmed — `services:` is the correct DB bring-up path; the host-executor fallback (docker run) is not needed.
- **D-PROBE-03 (DB readiness):** No mysql CLI in runner image — healthcheck-based wait is the only viable approach without additional apt installs.
- **D-PROBE-04 (cache):** `actions/cache` timed out — skip cache in critical path; note in ci.yml comments.
- **D-PROBE-08 (PAT):** Registry PAT deferral confirmed — probe exercised no secrets; PAT secret creation is a Plan 04 prerequisite.
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Fixed `runs-on: self-hosted``runs-on: ubuntu-latest`**
- **Found during:** Task 3 (probe run) — probe job stayed queued with no eligible runner
- **Issue:** The plan specified `runs-on: self-hosted` but the runner advertises `ubuntu-latest`/`ubuntu-24.04`/`ubuntu-22.04`, not the `self-hosted` label
- **Fix:** Changed `runs-on: self-hosted` to `runs-on: ubuntu-latest` in `.gitea/workflows/runner-probe.yml`; also updated the plan's `key_links.via` pattern to document the correct label
- **Files modified:** `.gitea/workflows/runner-probe.yml`, `.planning/phases/08-gitea-ci/08-01-PLAN.md`
- **Verification:** Probe run 2 (run id 2, head sha 134d4db) completed successfully (conclusion: success, ~5 min)
- **Committed in:** `134d4db`
---
**Total deviations:** 1 auto-fixed (Rule 1 - Bug: wrong runs-on label)
**Impact on plan:** Fix was necessary for the probe to execute at all. No scope creep.
## Issues Encountered
- First probe run (run id 1) queued indefinitely because `runs-on: self-hosted` matched no runner. Identified and fixed in commit 134d4db. Second run completed successfully.
- `actions/cache@v4` timed out (P-09) — expected per 08-RESEARCH Pitfall 7; recorded as finding, not a failure.
- `mysql` CLI absent from runner image (P-06) — inconclusive DB CLI reachability; mitigated by confirmed Docker-network hostname resolution and healthcheck-based wait strategy for Plans 02/03.
## User Setup Required
- act_runner registered on Unraid host (DONE — operator confirmed)
- `GITEA_REGISTRY_PAT` repo secret with `write:package` scope — **deferred to Plan 04** (operator decision; not needed until the publish job is designed)
## Next Phase Readiness
Plans 02-04 have everything they need from this probe:
- **DB bring-up:** `services: mariadb:11` with `healthcheck.sh --connect --innodb_initialized`; `DB_HOST=mariadb`
- **runs-on:** `ubuntu-latest` (confirmed label)
- **Cache:** skip or `continue-on-error: true` only
- **Playwright:** `npx playwright install --with-deps webkit chromium` works as-is
- **Artifact upload:** `ChristopherHX/gitea-upload-artifact@v4` only
- **Short SHA:** `${GITHUB_SHA:0:7}` valid for image tags
No blockers for Plan 02 (test job authoring).
---
*Phase: 08-gitea-ci*
*Completed: 2026-06-11*