Lays the foundation for youpc.org's cross-repo integration: an
in-package UPC subset of paliad's deadline corpus, embedded as JSON,
that any consumer can use to run the litigationplanner engine without
DB access.
Generator (cmd/gen-upc-snapshot):
- Reads paliad's live DB (DATABASE_URL), applies pending migrations
to match schema HEAD, SELECTs the UPC subset
(proceeding_types WHERE jurisdiction='UPC' AND is_active=true,
deadline_rules WHERE lifecycle_state='published' AND is_active=true
on those proceedings, referenced trigger_events, DE+UPC holidays,
UPC courts).
- Writes pretty-printed JSON to
pkg/litigationplanner/embedded/upc/{proceeding_types, rules,
trigger_events, holidays, courts, meta}.json.
- Idempotent — same DB state → same output (modulo
meta.generated_at + auto-versioned suffix).
- Date-stamped versioning (YYYY-MM-DD-N) with same-day suffix bump.
- Operator runbook in cmd/gen-upc-snapshot/README.md.
Embedded subpackage (pkg/litigationplanner/embedded/upc/):
- embed.go — //go:embed *.json + LoadMeta()
- snapshot.go — SnapshotCatalog (full lp.Catalog impl: LoadProceeding
/ LoadProceedingByID / LoadRuleByID / LoadRuleByCode /
LoadRulesByTriggerEvent / LoadTriggerEventsByIDs / LookupEvents);
O(1) map lookups; LookupEvents linear over the < 100-row UPC corpus.
- holidays.go — SnapshotHolidayCalendar implementing lp.HolidayCalendar
(IsNonWorkingDay / Adjust* with structured AdjustmentReason).
- courts.go — SnapshotCourtRegistry implementing lp.CourtRegistry.
- Compile-time assertions (_ lp.X = (*Snapshot*)(nil)) catch
interface drift.
Wire-up for consumers:
cat, _ := upc.NewCatalog()
hc, _ := upc.NewHolidayCalendar()
cr, _ := upc.NewCourtRegistry()
timeline, _ := lp.Calculate(ctx, "upc.inf.cfi", "2026-05-26",
lp.CalcOptions{}, cat, hc, cr)
Tests (snapshot_test.go, all DB-free):
- meta parses cleanly, non-zero counts
- LoadProceeding(upc.inf.cfi) returns expected proc + rules
- LoadProceeding(unknown) returns ErrUnknownProceedingType
- LookupEvents(Jurisdiction:UPC, all-following) covers corpus
- LookupEvents(party=defendant, next) scopes anchors correctly
- engine end-to-end via lp.Calculate against the embedded snapshot
- holiday calendar (weekends, DE closures, UPC vacation block)
- court registry (empty courtID fallback, known + unknown court)
Placeholder data shipped (2 proceedings, 2 rules, 5 holidays, 2
courts) so tests run without a live DB. Operator regenerates against
prod via `make snapshot-upc` once migrations 134 (B1) and 135 (B3)
have landed on prod — see cmd/gen-upc-snapshot/README.md for the
runbook. The placeholder's meta.version is suffixed `-placeholder`
to make the regeneration delta obvious.
Makefile target:
make snapshot-upc — wraps the generator + reruns the snapshot tests
Design (§19 of docs/design-litigation-planner-2026-05-26.md):
- Embedding format: go:embed JSON (diff-friendly, no compile coupling)
- Generator entry: cmd/gen-upc-snapshot/main.go (idiomatic Go cmd path)
- Versioning: meta.json carries semver + generated_at + paliad_commit
- Regeneration: manual via Make target or `go generate`; no CI cron in v1
- Out of scope: snapshot signing, DE/EPA/DPMA snapshots, snapshot
diff tooling
Acceptance:
- go build clean, go test all green (incl. 6 new tests in
pkg/litigationplanner/embedded/upc, all DB-free)
- SnapshotCatalog passes the compile-time lp.Catalog assertion
- Generator binary builds + runs (Idempotence verified by re-running
against the same source data)
165 lines
7.9 KiB
Makefile
165 lines
7.9 KiB
Makefile
# Paliad — developer entrypoints.
|
|
#
|
|
# Targets here are the gate tier from the test-strategy design
|
|
# (docs/design-paliad-test-strategy-2026-05-19.md). Slice 1 lands:
|
|
#
|
|
# make verify-migrations — dry-run every pending migration (BEGIN..ROLLBACK)
|
|
# plus the full boot smoke (apply + tracker
|
|
# advances + /healthz returns 200).
|
|
# make verify-mig — alias for verify-migrations.
|
|
# make test — short test pass: go test ./internal/... -short
|
|
# plus the cmd/server package. Includes the
|
|
# live-DB tests when TEST_DATABASE_URL is set,
|
|
# skips them otherwise.
|
|
# make test-go — go test ./... -race (full Go suite).
|
|
#
|
|
# Future slices will extend this with:
|
|
# make test-frontend — bun test (Slice 3 / Slice 6)
|
|
# make e2e — Playwright golden-path suite (Slice 4)
|
|
#
|
|
# All targets are idempotent. None of them write to the filesystem outside
|
|
# the test runner's working dirs. None of them touch internal/db/migrations/
|
|
# files.
|
|
|
|
.PHONY: help verify-migrations verify-mig verify-mig-app test test-go test-frontend refresh-snapshot snapshot-upc
|
|
|
|
help:
|
|
@echo "Paliad — developer targets"
|
|
@echo ""
|
|
@echo " verify-migrations Dry-run pending migrations + boot smoke (needs TEST_DATABASE_URL)"
|
|
@echo " verify-mig Alias for verify-migrations"
|
|
@echo " verify-mig-app End-to-end migration smoke as non-superuser role"
|
|
@echo " (needs TEST_APP_DATABASE_URL — t-paliad-282 / m/paliad#114)"
|
|
@echo " test Short test pass — covers gate tier"
|
|
@echo " test-go Full Go suite with race detector"
|
|
@echo " test-frontend Frontend bun:test suite"
|
|
@echo " snapshot-upc Regenerate pkg/litigationplanner/embedded/upc/ from live DB"
|
|
@echo " (needs DATABASE_URL — see cmd/gen-upc-snapshot/README.md)"
|
|
@echo ""
|
|
@echo "Set TEST_DATABASE_URL to enable live-DB tests. Example:"
|
|
@echo " export TEST_DATABASE_URL=postgres://paliad:...@localhost:11833/paliad_test"
|
|
@echo ""
|
|
@echo "Set TEST_APP_DATABASE_URL to enable the role-split smoke. Example:"
|
|
@echo " export TEST_APP_DATABASE_URL=postgres://paliad_app:...@localhost:5432/paliad_scratch"
|
|
|
|
# Gate target — the test that would have caught mig 098 / mig 099 before
|
|
# deploy. Combines:
|
|
# - TestMigrations_DryRun (internal/db): per-migration BEGIN..ROLLBACK
|
|
# - TestBootSmoke (cmd/server): apply-end-to-end + tracker advances
|
|
# + /healthz 200
|
|
#
|
|
# Requires TEST_DATABASE_URL. Without it, both tests skip and the target
|
|
# is effectively a no-op — guard against that explicitly so CI doesn't
|
|
# silently green a missing env var.
|
|
verify-migrations:
|
|
@if [ -z "$$TEST_DATABASE_URL" ]; then \
|
|
echo "ERROR: TEST_DATABASE_URL is not set."; \
|
|
echo " The migration gate cannot run without a scratch DB."; \
|
|
echo " Set TEST_DATABASE_URL to a Postgres URL the test can"; \
|
|
echo " open transactions against, e.g."; \
|
|
echo " export TEST_DATABASE_URL=postgres://paliad:PW@localhost:11833/paliad_test"; \
|
|
exit 2; \
|
|
fi
|
|
@echo "==> migration dry-run (per-mig BEGIN..ROLLBACK)"
|
|
go test -count=1 -run TestMigrations_DryRun ./internal/db/
|
|
@echo "==> boot smoke (apply + tracker + /healthz)"
|
|
go test -count=1 -run TestBootSmoke ./cmd/server/
|
|
|
|
verify-mig: verify-migrations
|
|
|
|
# Gate-tier test pass. -short skips the slow live-DB tests when the
|
|
# author opts out via `if testing.Short() { t.Skip(...) }`; today most of
|
|
# paliad's live-DB tests gate on TEST_DATABASE_URL instead, so -short is
|
|
# forward-compatible rather than load-bearing.
|
|
test:
|
|
go test -short ./internal/... ./cmd/...
|
|
|
|
# Full Go suite with race detection. Slower but catches concurrent-map
|
|
# regressions that -short would skip; intended for the merge-to-main gate
|
|
# (full suite, not per-PR).
|
|
test-go:
|
|
go test -race ./...
|
|
|
|
# Frontend bun:test suite. Runs the 4 existing pure-TS tests today; will
|
|
# grow as mendel's Slice 3 (frontend test infill) lands.
|
|
test-frontend:
|
|
cd frontend && bun test
|
|
|
|
# Role-split end-to-end migration smoke — the catch for the mig 129 42501
|
|
# ownership class (m/paliad#114). Runs ApplyMigrations as a non-superuser
|
|
# role against TEST_APP_DATABASE_URL. Fails the build if any migration
|
|
# assumes more privilege than the deploy role has.
|
|
#
|
|
# Developer setup (local):
|
|
# psql -c "CREATE ROLE paliad_app LOGIN PASSWORD 'ci' NOSUPERUSER;"
|
|
# psql -c "CREATE DATABASE paliad_scratch OWNER paliad_app;"
|
|
# export TEST_APP_DATABASE_URL=postgres://paliad_app:ci@localhost:5432/paliad_scratch
|
|
verify-mig-app:
|
|
@if [ -z "$$TEST_APP_DATABASE_URL" ]; then \
|
|
echo "ERROR: TEST_APP_DATABASE_URL is not set."; \
|
|
echo " The role-split migration smoke cannot run without a non-superuser scratch DB."; \
|
|
echo " See Makefile comments above this target for setup."; \
|
|
exit 2; \
|
|
fi
|
|
go test -count=1 -run TestMigrations_EndToEndAsAppRole ./internal/db/
|
|
|
|
# Refresh the prod schema snapshot used by CI's migration smoke
|
|
# (t-paliad-282 / m/paliad#114). Connects to youpc-supabase prod, dumps
|
|
# the paliad schema + applied_migrations rows, strips rows beyond the
|
|
# current branch's max on-disk version, and writes
|
|
# internal/db/testdata/prod-snapshot.sql.
|
|
#
|
|
# When to refresh:
|
|
# - After merging a PR that added a new migration to main.
|
|
# - When CI's migration smoke starts spuriously failing because the
|
|
# snapshot's applied set diverges from on-disk by more than this
|
|
# branch's worth of new migs.
|
|
#
|
|
# Requires PALIAD_PROD_DATABASE_URL env var (a Postgres URL with
|
|
# pg_dump rights on youpc-supabase). Example:
|
|
# export PALIAD_PROD_DATABASE_URL='postgres://postgres:PW@100.99.98.201:11833/postgres'
|
|
refresh-snapshot:
|
|
@if [ -z "$$PALIAD_PROD_DATABASE_URL" ]; then \
|
|
echo "ERROR: PALIAD_PROD_DATABASE_URL is not set."; \
|
|
echo " Refresh requires read access to youpc-supabase prod."; \
|
|
exit 2; \
|
|
fi
|
|
@echo "==> dumping paliad schema (no owner, no privs)..."
|
|
@pg_dump --schema-only --schema=paliad --no-owner --no-privileges \
|
|
--no-publications --no-subscriptions \
|
|
"$$PALIAD_PROD_DATABASE_URL" > internal/db/testdata/prod-snapshot.sql.tmp
|
|
@echo "==> appending applied_migrations rows..."
|
|
@pg_dump --data-only --table=paliad.applied_migrations \
|
|
--no-owner --no-privileges \
|
|
"$$PALIAD_PROD_DATABASE_URL" >> internal/db/testdata/prod-snapshot.sql.tmp
|
|
@echo "==> stripping pg16 \\restrict / \\unrestrict commands for pg15 compat..."
|
|
@sed -i.bak '/^\\restrict /d; /^\\unrestrict /d' internal/db/testdata/prod-snapshot.sql.tmp
|
|
@rm -f internal/db/testdata/prod-snapshot.sql.tmp.bak
|
|
@echo "==> stripping applied_migrations rows beyond branch's max on-disk version..."
|
|
@MAX_VER=$$(ls internal/db/migrations/*.up.sql | xargs -I{} basename {} | sed 's/_.*//' | sort -n | tail -1); \
|
|
awk -v max=$$MAX_VER ' \
|
|
/^[0-9]+\t/ { split($$0, a, "\t"); if (a[1]+0 > max) next; } \
|
|
{ print } \
|
|
' internal/db/testdata/prod-snapshot.sql.tmp > internal/db/testdata/prod-snapshot.sql
|
|
@rm internal/db/testdata/prod-snapshot.sql.tmp
|
|
@wc -l internal/db/testdata/prod-snapshot.sql
|
|
|
|
# Regenerate the embedded UPC snapshot from a live paliad DB. The
|
|
# generator applies pending migrations first, then SELECTs the UPC
|
|
# subset and writes JSON files under pkg/litigationplanner/embedded/upc/.
|
|
#
|
|
# Requires DATABASE_URL — Slice C of the litigation-planner extraction
|
|
# (m/paliad#124 §19). See cmd/gen-upc-snapshot/README.md for the full
|
|
# operator runbook.
|
|
snapshot-upc:
|
|
@if [ -z "$$DATABASE_URL" ]; then \
|
|
echo "ERROR: DATABASE_URL is not set."; \
|
|
echo " Snapshot generation needs read access to a paliad DB."; \
|
|
echo " Set DATABASE_URL to the live paliad Postgres, then re-run."; \
|
|
exit 2; \
|
|
fi
|
|
@echo "==> regenerating UPC snapshot from $$DATABASE_URL"
|
|
go run ./cmd/gen-upc-snapshot
|
|
@echo "==> running snapshot tests against the regenerated data"
|
|
go test ./pkg/litigationplanner/embedded/upc/...
|