promote: uat → main — pnpm-offline Docker hardening + accumulated UAT fixes (GRO-1985) #136

Merged
Scrubs McBarkley merged 67 commits from uat into main 2026-06-01 18:07:31 +00:00
Owner

Production Promotion — uat → main

Promotes the accumulated UAT-validated work to production. Primary driver is the pnpm-offline Docker hardening (GRO-1985) which has passed UAT regression and security review.

Key changes promoted

  • GRO-1985 / GRO-1981Dockerfile hardening: pnpm installed via npm (no Corepack shim), COREPACK_ENABLE_DOWNLOAD_FALLBACK=0, ENV HOME=/tmp for init-stage containers under readOnlyRootFilesystem: true
  • GRO-2000UAT_PLAYBOOK.md canonical source-of-truth for UAT seed passwords documented
  • GRO-1999 / GRO-2004pet_size_category extra_large enum registered via migration 0038; enum coverage extended
  • Supporting UAT playbook and CI workflow updates

Sign-off checklist

Gate Status Reference
UAT regression PASS GRO-2015
Security review PASS GRO-2024 (Barkley Trimsworth)
UAT CI — Test green run #2313
UAT CI — Lint & Typecheck green run #2313
UAT CI — Build & Push (incl. offline smoke tests) green run #2313
UAT_PLAYBOOK.md present & updated yes uat branch

UAT branch SHA

6a81a52a50ea098a0989fb42a75aeb0c5060703f

cc @cpfarhood

## Production Promotion — uat → main Promotes the accumulated UAT-validated work to production. Primary driver is the pnpm-offline Docker hardening (GRO-1985) which has passed UAT regression and security review. ### Key changes promoted - **GRO-1985 / GRO-1981** — `Dockerfile` hardening: pnpm installed via npm (no Corepack shim), `COREPACK_ENABLE_DOWNLOAD_FALLBACK=0`, `ENV HOME=/tmp` for init-stage containers under `readOnlyRootFilesystem: true` - **GRO-2000** — `UAT_PLAYBOOK.md` canonical source-of-truth for UAT seed passwords documented - **GRO-1999 / GRO-2004** — `pet_size_category` `extra_large` enum registered via migration 0038; enum coverage extended - Supporting UAT playbook and CI workflow updates ### Sign-off checklist | Gate | Status | Reference | |------|--------|-----------| | UAT regression | **PASS** | GRO-2015 | | Security review | **PASS** | GRO-2024 (Barkley Trimsworth) | | UAT CI — Test | **green** | run [#2313](https://git.farh.net/groombook/api/actions/runs/2313/jobs/4779) | | UAT CI — Lint & Typecheck | **green** | run [#2313](https://git.farh.net/groombook/api/actions/runs/2313/jobs/4778) | | UAT CI — Build & Push (incl. offline smoke tests) | **green** | run [#2313](https://git.farh.net/groombook/api/actions/runs/2313/jobs/4780) | | `UAT_PLAYBOOK.md` present & updated | **yes** | uat branch | ### UAT branch SHA `6a81a52a50ea098a0989fb42a75aeb0c5060703f` cc @cpfarhood
Scrubs McBarkley added 67 commits 2026-06-01 18:07:22 +00:00
feat(GRO-1177): add GET /api/pets/:id/profile-summary endpoint
CI / Lint & Typecheck (pull_request) Successful in 9s
CI / Test (pull_request) Successful in 9s
CI / Build & Push Docker Images (pull_request) Successful in 37s
8c62ce2368
Returns aggregated pet profile with:
- All pet fields (basic + extended)
- recentGroomingHistory: last 10 entries from groomingVisitLogs with staff name join
- lastVisitDate: most recent groomedAt timestamp
- visitCount: count of completed appointments
- upcomingAppointment: next scheduled/confirmed appointment with service/staff name

Enforces same groomer RBAC as GET /:id. Returns 404 for non-existent pets.
Adds PetProfileSummary, GroomingHistoryEntry, and UpcomingAppointment types.
Adds unit tests covering: 404, 403, aggregated profile, empty history, no upcoming appt.
Updates UAT_PLAYBOOK.md §3 with TC-API-3.8 and TC-API-3.9.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-authored-by: Lint Roller <lint@groombook.dev>
Co-committed-by: Lint Roller <lint@groombook.dev>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(ci): remove duplicate provenance keys causing YAML parse error
CI / Lint & Typecheck (push) Failing after 4s
CI / Test (push) Successful in 15s
CI / Build & Push Docker Images (push) Has been skipped
b796d36aed
Duplicate 'provenance: false' in each docker/build-push-action step caused
Gitea to reject the workflow file, breaking push CI and workflow_dispatch.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(rbac): guard noUncheckedIndexedAccess in name derivation and newStaff insert
CI / Lint & Typecheck (push) Successful in 12s
CI / Test (push) Successful in 14s
CI / Build & Push Docker Images (push) Successful in 46s
3b9e82adff
With noUncheckedIndexedAccess:true, split("@")[0] returns string|undefined,
making `name` typed as string|undefined and failing the notNull staff.name
insert constraint. Fix by using ?? fallback on the array access.

Also add newStaff null guard after .returning() destructure — array
destructuring yields T|undefined with noUncheckedIndexedAccess enabled.
- Replace .select({ count: appointments.id }).limit(1) + .length with
  sql<number>`count(*)::int` pattern per project standard (references invoices.ts:86)
- Add gte(appointments.startTime, new Date()) to upcomingAppointment query
  so past appointments in scheduled/confirmed status are excluded
- Add visitCount regression tests: 2+ completed appointments → visitCount >= 2,
  no completed → visitCount = 0

Updated UAT_PLAYBOOK.md §profile-summary (visitCount regression + date filter)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs: add TC-API-3.18 and TC-API-3.19 to UAT_PLAYBOOK for visitCount regression + date filter
CI / Lint & Typecheck (pull_request) Successful in 12s
CI / Test (pull_request) Successful in 12s
CI / Build & Push Docker Images (pull_request) Successful in 1m4s
a25b2fe281
Updated UAT_PLAYBOOK.md §3.3 — new visitCount cap and past appointment filter test cases

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge pull request 'feat(GRO-1177): add pet profile summary endpoint' (#30) from flea-flicker/pet-profile-summary into dev
CI / Lint & Typecheck (push) Successful in 12s
CI / Test (push) Successful in 12s
CI / Build & Push Docker Images (push) Successful in 2m52s
9622b109d0
feat(GRO-1177): add pet profile summary endpoint (#30)

Adds GET /api/pets/:id/profile-summary with aggregated pet profile,
grooming history, visit count, and upcoming appointment.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge dev into promote/dev-to-uat-gro-1790
CI / Lint & Typecheck (pull_request) Successful in 11s
CI / Test (pull_request) Successful in 11s
CI / Build & Push Docker Images (pull_request) Successful in 1m9s
ed3d7df1c9
Resolve .ci-trigger conflict preferring dev version.
fix: restore pet profile summary endpoint from dev (GRO-1177)
CI / Lint & Typecheck (pull_request) Successful in 13s
CI / Test (pull_request) Successful in 12s
CI / Build & Push Docker Images (pull_request) Successful in 41s
32156e9a45
Merge pull request 'promote: dev → uat (GRO-1790 pet profile summary fixes)' (#91) from promote/dev-to-uat-gro-1790 into uat
CI / Lint & Typecheck (push) Successful in 12s
CI / Test (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 35s
45b3d4343d
promote: dev → uat (GRO-1790 pet profile summary fixes)

Merged by CTO after QA approval.
Refs: GRO-1798, GRO-1790
feat(db): add migration 0034 for extended pet profile columns
CI / Lint & Typecheck (pull_request) Successful in 11s
CI / Test (pull_request) Successful in 11s
CI / Build & Push Docker Images (pull_request) Successful in 50s
63ed91e5f3
GRO-1850: Adds temperament_score, temperament_flags, medical_alerts,
and preferred_cuts to the pets table.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge pull request 'feat(db): add migration 0034 for extended pet profile columns (GRO-1850)' (#92) from fix/gro-1850-pet-profile-migration into dev
CI / Lint & Typecheck (push) Successful in 14s
CI / Test (push) Successful in 13s
CI / Build & Push Docker Images (push) Successful in 1m20s
b050fb9a5f
Adds POST /api/portal/session-from-auth which bridges a valid Better Auth
customer session (from SSO login) to a portal impersonation session, so
real SSO customers can access the client portal.

The endpoint is registered before the validatePortalSession catch-all so it
is not subject to that middleware. It validates the Better Auth session
from request cookies, looks up the client by email, creates an active
impersonation session, and returns { sessionId, clientId, clientName }.

Also adds "role" to the genericOAuth scopes so Authentik propagates the
role claim into Better Auth user objects (GRO-1862 root cause fix).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds manual test cases covering:
- TC-API-8.8: valid Better Auth session → portal session (201)
- TC-API-8.9: no session → 401
- TC-API-8.10: no matching client → 404
- TC-API-8.11: returned sessionId works on subsequent portal calls

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Fixes two bugs found in QA review:
- ReferenceError: getAuth not defined in beforeEach - add import
- TypeError: wrong mock chain insert().into().values() vs insert().values()

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(gro-1866): add session-from-auth portal endpoint + role scope' (#93) from fix/gro-1866-sso-bridge into dev
CI / Test (push) Successful in 34s
CI / Lint & Typecheck (push) Successful in 38s
CI / Build & Push Docker Images (push) Failing after 1m46s
7bdb92999a
fix(gro-1866): add session-from-auth portal endpoint + role scope (#93)

Bridges Better Auth SSO sessions to portal sessions for real customers.
Adds role to genericOAuth scopes for Authentik role propagation.

Closes GRO-1866
fix(gro-1866): address QA review failures — portalSession null-guard,
CI / Test (push) Successful in 32s
CI / Lint & Typecheck (push) Successful in 34s
CI / Build & Push Docker Images (push) Successful in 2m34s
2e0d63f7f6
email null-dereference guard, externalize DEMO_STAFF_ID

1. portal.ts:138 — add null guard for portalSession before accessing .id
   (TS18048: 'portalSession' is possibly 'undefined')
2. rbac.ts:130 — guard jwt.email before split() to prevent runtime throw
3. portal.ts:39,105 — externalize DEMO_STAFF_ID as env var
   (process.env.DEMO_STAFF_ID ?? "00000000-...")

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge origin/uat into promote/dev-to-uat-gro-1866
CI / Lint & Typecheck (pull_request) Successful in 36s
CI / Test (pull_request) Successful in 33s
CI / Build & Push Docker Images (pull_request) Successful in 3m11s
17b44e3b00
Conflicts resolved:
- src/middleware/rbac.ts: keep dev version (email null-guard, type assertion, single null-check)
- .gitea/workflows/ci.yml: keep uat version (branches: [main, dev, uat])

Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(gro-1889): bake pnpm into reset stage to avoid runtime DNS (#97)
CI / Lint & Typecheck (push) Successful in 20s
CI / Test (push) Successful in 26s
CI / Build & Push Docker Images (push) Successful in 3m2s
543d9560ec
feat(seed): populate extended pet profile fields for UAT regression
CI / Test (pull_request) Successful in 20s
CI / Lint & Typecheck (pull_request) Successful in 21s
CI / Build & Push Docker Images (pull_request) Failing after 1m35s
612c0467a1
GRO-1898: Ensure UAT seed data includes clients and pets with extended
profile fields (temperamentScore, temperamentFlags, medicalAlerts,
preferredCuts, coatType).

- Add data pools for extended profile fields in pet batch generation
- Populate all 5 extended fields for randomly generated pets
- Update UAT test client pets with fully populated extended profiles
- Fix type mismatches: medicalAlerts uses MedicalAlert[] with
  {type, description, severity} shape per @groombook/types

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
docs(UAT_PLAYBOOK): add TC-API-3.20 through TC-API-3.24 for seed data verification
CI / Lint & Typecheck (pull_request) Successful in 21s
CI / Test (pull_request) Successful in 35s
CI / Build & Push Docker Images (pull_request) Failing after 4m57s
dff0e17a63
Updated UAT_PLAYBOOK.md §4.3 — new seed data verification tests.

GRO-1898: After populating extended profile fields in the UAT seed, add
test cases to verify the data is actually present and shaped correctly.
Test cases cover:
- /api/clients returns seed data
- /api/pets/{id} returns all 5 extended fields for UAT test pets
- medicalAlerts shape is correct ({type, description, severity})
- Deterministic UAT pets (Charlie = behavioral alert, Delta = skin alert)
  are verifiably populated

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/seed/extended-profile-fields-gro-1898' into dev
CI / Test (push) Successful in 19s
CI / Lint & Typecheck (push) Successful in 31s
CI / Build & Push Docker Images (push) Failing after 1m52s
4cc0676d52
feat(seed): populate extended pet profile fields for UAT verification (#99)
CI / Lint & Typecheck (push) Successful in 1m53s
CI / Test (push) Successful in 1m55s
CI / Build & Push Docker Images (push) Failing after 3m24s
aee82efbac
fix(seed): use typeof on enum.enumValues for db build (#100)
CI / Lint & Typecheck (push) Successful in 21s
CI / Test (push) Failing after 13m48s
CI / Build & Push Docker Images (push) Has been skipped
86a6e3245c
fix(test): mock db to handle sql count(*) queries (GRO-1917) (#102)
CI / Test (push) Successful in 14s
CI / Lint & Typecheck (push) Successful in 18s
CI / Build & Push Docker Images (push) Successful in 37s
CI / Test (pull_request) Successful in 11s
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Build & Push Docker Images (pull_request) Successful in 36s
b5f964c1ff
Use `corepack install -g` instead of `corepack prepare --activate` to write
pnpm to a stable global path (/usr/local/bin/pnpm) rather than relying on
corepack shims that re-validate against npmjs.org at runtime.

Set COREPACK_ENABLE_DOWNLOAD_PROMPT=0 and COREPACK_ENABLE_STRICT=0 to suppress
the interactive download prompt and strict version checks that also trigger
network access.

Remove the dead `RUN mkdir -p /home/node/.cache/node/corepack` line from the
builder stage (vestigial cache-location configuration).

Fixes: GRO-1916 (prod migrate-schema EAI_AGAIN on registry.npmjs.org)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
feat(pets): add GET /:id/profile-summary endpoint
CI / Test (pull_request) Successful in 11s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Failing after 36s
53677b1420
Adds profile-summary endpoint for groombook web to display:
- Basic pet fields (name, species, breed, coatType, etc.)
- Recent grooming history (last 10 completed appointments with staff names)
- Visit count (completed appointments)
- Upcoming appointment (next scheduled/confirmed)

Groomer RBAC: groomers can only see pets they've had appointments with.
Non-groomer staff (admin/super) can see all pets.

Fixes GRO-1802 (UAT regression: profile-summary route never deployed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge pull request 'fix(docker): bake pnpm into image to avoid runtime corepack downloads (GRO-1909)' (#101) from fix/GRO-1909-migrate-corepack-offline into dev
CI / Test (push) Successful in 10s
CI / Lint & Typecheck (push) Successful in 16s
CI / Test (pull_request) Successful in 9s
CI / Lint & Typecheck (pull_request) Successful in 14s
CI / Build & Push Docker Images (push) Failing after 37s
CI / Build & Push Docker Images (pull_request) Failing after 36s
5d6bc06295
fix(seed): add uat-customer client record for SSO bridge UAT (GRO-1935) (#104)
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Test (pull_request) Successful in 10s
CI / Build & Push Docker Images (pull_request) Failing after 37s
CI / Lint & Typecheck (push) Successful in 14s
CI / Test (push) Successful in 2m19s
CI / Build & Push Docker Images (push) Failing after 33s
280c699d0d
fix(api): repair root src/routes/pets.ts visit-count query (GRO-1945)
CI / Test (pull_request) Successful in 11s
CI / Lint & Typecheck (pull_request) Successful in 14s
CI / Build & Push Docker Images (pull_request) Successful in 1m4s
a14bb5e17d
Use sql\`count(*)::int\` instead of selecting appointments.id, which was
causing TS2339 under noUncheckedIndexedAccess (arr[0] is T | undefined).

Import sql from @groombook/db. Use countRow?.count ?? 0 to stay
noUncheckedIndexedAccess-safe.

Matches the working implementation in apps/api/src/routes/pets.ts:365.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(api): repair root src/routes/pets.ts visit-count query (GRO-1945)' (#107) from flea/GRO-1945-pets-visitcount-hotfix into dev
CI / Test (push) Successful in 10s
CI / Lint & Typecheck (push) Successful in 14s
CI / Build & Push Docker Images (push) Successful in 21s
CI / Test (pull_request) Successful in 10s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Successful in 59s
981a257d2d
GRO-1921: Fix UAT reset CronJob to seed full UAT profile with extended pet fields (#106)
CI / Test (push) Successful in 11s
CI / Test (pull_request) Successful in 10s
CI / Lint & Typecheck (push) Successful in 16s
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Build & Push Docker Images (push) Successful in 57s
CI / Build & Push Docker Images (pull_request) Successful in 1m2s
0ab16b82e0
Promote: dev → uat (GRO-1945 visit-count hotfix + GRO-1921 UAT reset CronJob fix)
CI / Lint & Typecheck (push) Successful in 15s
CI / Test (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 30s
a5bd9c915c
Carries:
- a14bb5e17d — GRO-1945 visit-count query hotfix
- 981a257d2d — Merge of GRO-1945 hotfix into dev
- 0ab16b82e0 — GRO-1921 UAT reset CronJob full-seed fix (PR #106)

QA approved (PR #108, Lint Roller). CI green on head SHA 0ab16b82e0.
GRO-1949: add behavioral and skin medicalAlertPool types, deterministic seeding for TestCooper/TestRocky (#109)
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Failing after 15s
CI / Build & Push Docker Images (push) Has been skipped
1891b9c523
fix(db): add missing 'short' value to coat_type enum (GRO-1953) (#110)
CI / Lint & Typecheck (push) Failing after 14s
CI / Test (push) Successful in 14s
CI / Build & Push Docker Images (push) Has been skipped
e00cdc1321
GRO-1955: hotfix seed.ts broken uc reference in random pet batch (#112)
CI / Test (push) Failing after 9s
CI / Lint & Typecheck (push) Successful in 20s
CI / Build & Push Docker Images (push) Has been skipped
c588c94dcb
GRO-1939: Add CI smoke test for blackholed migrate runtime
CI / Test (pull_request) Successful in 15s
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Build & Push Docker Images (pull_request) Failing after 53s
e9aef5719f
Cherry-picked from fix/GRO-1909-migrate-corepack-offline (f007eca)
fix(ci): correct typo groombok->groombook and fix Reset image cache-from indentation
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Successful in 44s
5ec9e9a8fd
- Fix API image tag typo: groombok -> groombook (line 103)
- Fix Reset image cache-from/cache-to indentation: moved from under tags: (12 spaces) to under with: (10 spaces)
- This corrects the Reset image build failure in CI runs.
ci: add blackhole smoke for migrate image (GRO-1939) (#111)
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 16s
CI / Test (pull_request) Successful in 10s
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Build & Push Docker Images (push) Successful in 48s
CI / Build & Push Docker Images (pull_request) Successful in 27s
c99e2980a1
Adds smoke-test step after the migrate image build that runs the image with registry.npmjs.org pointed at 127.0.0.1; pnpm --version must succeed without npm access. Guards against corepack-offline regression from GRO-1916.

QA: Lint Roller APPROVED (commit 5ec9e9a8) — CI all-green.
CTO: signed off (self-approval blocked by Gitea — I authored).

Closes #GRO-1954
Closes #GRO-1957
Closes #GRO-1958
Relates #GRO-1939
ci: promote dev→uat (GRO-1939 smoke + GRO-1953/1955/1949 seed/db) (#113)
CI / Test (push) Successful in 11s
CI / Lint & Typecheck (push) Successful in 14s
CI / Build & Push Docker Images (push) Successful in 24s
f80f781b23
Promotes 6 dev commits to uat. PR #111 (latest dev tip) QA-approved by Lint Roller. CI all-green.

Follow-up: Shedward UAT regression task to be created.
GRO-1961: populate extended fields on UAT Pup Alpha/Beta on re-runs (#114)
CI / Test (push) Successful in 10s
CI / Lint & Typecheck (push) Successful in 22s
CI / Build & Push Docker Images (push) Successful in 59s
01cff9006a
GRO-1961: populate extended fields on UAT Pup Alpha/Beta on re-runs
fix(seed): remove stale uc.petName closure ref, correct medicalAlerts distribution to 30% (#115)
CI / Test (push) Successful in 11s
CI / Lint & Typecheck (push) Successful in 18s
CI / Build & Push Docker Images (push) Successful in 1m4s
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 14s
CI / Build & Push Docker Images (pull_request) Successful in 1m4s
bec7b014be
Merge pull request 'Promote dev→uat: expand UAT seed to 30+ pets with medicalAlerts 25-35% distribution (GRO-1962)' (#117) from dev into uat
CI / Lint & Typecheck (push) Successful in 14s
CI / Test (push) Successful in 12s
CI / Build & Push Docker Images (push) Successful in 1m9s
8cce9c4d35
fix: add missing coat_type enum values (GRO-1971) (#118)
CI / Test (push) Successful in 18s
CI / Lint & Typecheck (push) Successful in 24s
CI / Build & Push Docker Images (push) Successful in 36s
dd220598ca
Promote dev→uat: add missing coat_type enum values (GRO-1971) (#119)
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 39s
5390131a6a
fix(seed): update credential password on existing accounts — not skip (GRO-1977) (#120)
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 37s
b928acf5d6
fix(seed): update credential password on re-run instead of skipping (GRO-1977) (#121)
CI / Lint & Typecheck (push) Failing after 2s
CI / Test (push) Successful in 12s
CI / Build & Push Docker Images (push) Has been skipped
1faa7945c6
fix(seed): update credential password on re-run instead of skipping (GRO-1977)
fix(seed): restore deterministic alerts for TestCooper/TestRocky (GRO-1962)
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Build & Push Docker Images (pull_request) Successful in 1m7s
97da5f332e
Restore deterministic alerts so TC-API-3.23/3.24 no longer flaky:
- TestCooper always gets a behavioral alert
- TestRocky always gets a skin alert
- Their deterministic alerts (~0.4% of total pets) do not shift
  the overall 25-35% medicalAlerts distribution

Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(seed): restore deterministic alerts for TestCooper/TestRocky (GRO-1962) (#122)
CI / Test (push) Successful in 11s
CI / Lint & Typecheck (push) Successful in 17s
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Successful in 45s
CI / Build & Push Docker Images (push) Successful in 1m7s
b15a53a19b
Co-authored-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
Co-committed-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
Promote dev→uat: restore deterministic TestCooper/TestRocky alerts (GRO-1962) (#123)
CI / Lint & Typecheck (push) Successful in 16s
CI / Test (push) Successful in 12s
CI / Build & Push Docker Images (push) Failing after 36s
e5fe005986
Co-authored-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
Co-committed-by: The Dogfather <20+gb_dogfather@noreply.git.farh.net>
fix(docker): install pnpm via npm instead of corepack shim (GRO-1983)
CI / Test (pull_request) Successful in 18s
CI / Lint & Typecheck (pull_request) Successful in 24s
CI / Build & Push Docker Images (pull_request) Successful in 1m25s
17d261fa94
The seed/migrate/reset Jobs all invoke `pnpm` at runtime via the
`pnpm --filter @groombook/db ...` CMD. In the current image, `/usr/local/bin/pnpm`
is a symlink to corepack's pnpm.js shim, which delegates to corepack and
re-validates the package against https://registry.npmjs.org on first use.

The UAT pod network is air-gapped, so corepack fails with:
  Error: getaddrinfo EAI_AGAIN registry.npmjs.org
This causes every seed Job to fail, leaving the Better Auth credential
hashes frozen at their last successful seed run — even when the SealedSecret
`seed-uat-passwords` is rotated.

Replace `corepack install -g pnpm@9.15.4` with `npm install -g pnpm@9.15.4`
in the base and runner stages. `npm install -g` writes the real pnpm binary
to /usr/local/bin/pnpm, bypassing the corepack shim entirely. The seed,
migrate, and reset stages inherit from builder (which inherits from base)
so they all get the real pnpm without needing their own install line.

The reset stage had a redundant corepack install that can be removed.

GRO-1983, supersedes GRO-1909 (incomplete — corepack shim still tried to
download pnpm at runtime).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
feat(db): add 0037_add_extra_large_to_pet_size_category — register extra_large in journal
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Build & Push Docker Images (pull_request) Successful in 1m24s
f262c19561
GRO-1979: The pet_size_category enum created in 0031_buffer_rules.sql
contained ('small', 'medium', 'large', 'xlarge'), but the drizzle schema
and seed.ts both use 'extra_large'. The mismatch caused the UAT seed job
to fail with:
  invalid input value for enum pet_size_category: "extra_large"

This migration adds the 'extra_large' value to pet_size_category and
registers it at idx 37 in the drizzle journal (sequel to 0035/0036
which registered short/medium/silky in coat_type under GRO-1971).

Non-transactional per Postgres restriction on ALTER TYPE ADD VALUE.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(db): GRO-1979 add 0037 — register extra_large in pet_size_category enum' (#124) from fix/GRO-1979-coat-type-pet-size-enum-fix into dev
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 38s
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Successful in 30s
944a4e161f
Merge branch 'uat' into dev to sync before dev→uat promotion
CI / Test (push) Successful in 15s
CI / Lint & Typecheck (push) Successful in 17s
CI / Test (pull_request) Successful in 14s
CI / Lint & Typecheck (pull_request) Successful in 18s
CI / Build & Push Docker Images (push) Failing after 8s
CI / Build & Push Docker Images (pull_request) Successful in 1m2s
84d923a707
This merge resolves a journal conflict between dev's idx 37 entry (0037_add_extra_large_to_pet_size_category) and the diverged uat branch. Both branches want the idx 37 entry; keeping the dev version which adds the migration.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(docker): install pnpm via npm instead of corepack shim (GRO-1983)' (#125) from fix/gro-1983-seed-pnpm-baked into dev
CI / Test (push) Successful in 12s
CI / Test (pull_request) Successful in 13s
CI / Lint & Typecheck (push) Successful in 16s
CI / Lint & Typecheck (pull_request) Successful in 17s
CI / Build & Push Docker Images (push) Failing after 13s
CI / Build & Push Docker Images (pull_request) Successful in 1m29s
5fab813215
Merge pull request 'Promote dev→uat: GRO-1982 pet_size_category extra_large enum migration' (#126) from dev into uat
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 16s
CI / Build & Push Docker Images (push) Successful in 37s
8af5a49d14
Promote dev→uat: GRO-1983 seed-job pnpm fix + GRO-1982 extra_large enum migration

Carries the accumulated dev state into uat (PR #125 docker pnpm fix + 0037 migration).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
docs(UAT_PLAYBOOK): add TC-API-3.28 for pet_size_category enum (GRO-1999) (#127)
CI / Test (push) Successful in 13s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 36s
CI / Test (pull_request) Successful in 10s
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Build & Push Docker Images (pull_request) Successful in 37s
a9bac033fd
fix(docker): bake pnpm via npm to remove Corepack runtime downloads (GRO-1981)
CI / Test (pull_request) Successful in 17s
CI / Lint & Typecheck (pull_request) Successful in 23s
CI / Build & Push Docker Images (pull_request) Successful in 1m14s
3e547b8568
The GRO-1983 fast restoration swapped Corepack's pnpm shim for a real
`npm install -g pnpm@9.15.4` binary, which is the right move. But the
GRO-1997 evidence gate still showed the first `reset-demo-data` pod
(...-nh7vg) hitting `getaddrinfo EAI_AGAIN registry.npmjs.org` before a
retry succeeded — the cache was writable, the cold-cache registry
download wasn't eliminated. This is the durable fix:

1. `ENV COREPACK_ENABLE_DOWNLOAD_FALLBACK=0` in `base` and `runner`:
   defence in depth so a Corepack shim can never silently re-download
   pnpm, even if it is somehow re-introduced.

2. `ENV HOME=/tmp` in the `migrate`, `seed`, and `reset` stages:
   under `readOnlyRootFilesystem: true` + `runAsUser: 1000`, the
   default HOME path is read-only, and pnpm fails the first time it
   tries to write a config or state file. The job pods already mount a
   writable emptyDir at `/tmp`; point HOME there.

3. CI smoke tests for `seed` and `reset` images (matching the existing
   `migrate` smoke): point `registry.npmjs.org` at 127.0.0.1 in a
   throwaway container, assert `which pnpm` resolves to
   `/usr/local/bin/pnpm` (real binary, not shim), and that `pnpm
   --version` succeeds without network egress. If Corepack ever sneaks
   back in, CI catches it on every PR.

The vestigial `RUN mkdir -p /home/node/.cache/node/corepack` in the
`builder` stage (mentioned in the spec) was already removed in GRO-1909
(commit 0a3eb8a), so nothing to do there.

Follow-on cleanup of the per-job `COREPACK_HOME` env vars and
`node-cache` emptyDir mounts in `groombook/infra` is intentionally
deferred to a coordinated infra PR once the new image is deployed —
keeping the existing infra in place during the transition avoids a
flag-day.

GRO-1985, hardening follow-up to GRO-1984 / GRO-1983.
Closes parent: GRO-1981.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
fix(db): register extra_large via migration 0038 (GRO-1999)
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 16s
CI / Build & Push Docker Images (pull_request) Successful in 1m27s
423d4bf72d
GRO-1979 added 0037_add_extra_large_to_pet_size_category with a journal
'when' of 1751500000000 — below the 0033 high-water mark (1779500000000)
on existing UAT/persistent DBs. Drizzle only applies a migration when its
journal.when is strictly greater than max(applied created_at), so 0037
was silently skipped, leaving pet_size_category without 'extra_large'
and crashing the UAT seed-test-data job (22P02 enum error).

This adds 0038 with a monotonic 'when' (1780000000000) so it applies on
both existing UAT/persistent DBs and fresh DBs. Statement is idempotent
(ADD VALUE IF NOT EXISTS) and a single auto-commit DDL (ADD VALUE cannot
run inside a transaction block).

Do not modify 0033/0034/0036/0037 — re-registering extra_large is correct
since the drizzle PetSizeCategory type and seed.ts both use that value.

GRO-2004

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Merge pull request 'fix(db): register extra_large via migration 0038 (GRO-1999)' (#130) from flea/gro-1999-migration-0038 into dev
CI / Test (push) Successful in 13s
CI / Test (pull_request) Successful in 14s
CI / Lint & Typecheck (pull_request) Successful in 15s
CI / Build & Push Docker Images (pull_request) Successful in 37s
CI / Lint & Typecheck (push) Successful in 2m23s
CI / Build & Push Docker Images (push) Successful in 32s
7f8a1f4bcd
Merge pull request 'promote(db): register extra_large via migration 0038 to UAT (GRO-2004)' (#131) from dev into uat
CI / Test (push) Successful in 11s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 35s
f7f88156e1
Merge pull request 'fix(docker): bake pnpm via npm to remove Corepack runtime downloads (GRO-1981)' (#129) from flea-flicker/gro-1985-bake-pnpm-offline into dev
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 1m10s
CI / Test (pull_request) Successful in 12s
CI / Lint & Typecheck (pull_request) Successful in 14s
CI / Build & Push Docker Images (pull_request) Successful in 24s
1d28adb71a
Self-merge per SDLC Phase 1 Step 4 — CTO review approved by gb_dogfather, CI 3/3 green, QA approved by gb_lint. Closes GRO-1985.

cc @cpfarhood
Merge pull request 'promote(docker): bake pnpm via npm to remove Corepack runtime downloads (GRO-1981)' (#133) from dev into uat
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 14s
CI / Build & Push Docker Images (push) Successful in 40s
5a4b9a98bd
Promote GRO-1985 (parent GRO-1981) dev->uat. cc @cpfarhood
docs(UAT_PLAYBOOK): document canonical source-of-truth for UAT seed passwords (GRO-2000) (#132)
CI / Lint & Typecheck (push) Failing after 5s
CI / Test (push) Successful in 12s
CI / Build & Push Docker Images (push) Has been skipped
CI / Test (pull_request) Successful in 11s
CI / Lint & Typecheck (pull_request) Successful in 19s
CI / Build & Push Docker Images (pull_request) Failing after 19s
2251a172e3
Merge pull request 'Promote dev → uat: UAT seed-password source-of-truth playbook (GRO-2000)' (#134) from dev into uat
CI / Test (push) Successful in 12s
CI / Lint & Typecheck (push) Successful in 15s
CI / Build & Push Docker Images (push) Successful in 27s
CI / Test (pull_request) Successful in 11s
CI / Lint & Typecheck (pull_request) Successful in 13s
CI / Build & Push Docker Images (pull_request) Successful in 1m10s
6a81a52a50
Scrubs McBarkley merged commit 766728865e into main 2026-06-01 18:07:31 +00:00
Sign in to join this conversation.