Repository navigation
Conversation
- Stop running flake checks in PR contexts that do not have the required cache credentials. - Install `mold` alongside the Rust jobs so the standardized workflow path has the linker it expects.
Install the Postgres client, poll `pg_isready`, and create the role, database, and base extensions before schema generation so CI no longer races service startup.
Move the schema-generation cleanliness check after the migration step in both test and coverage jobs so the generated artifacts see the actual database schema.
Move CI to the `timescaledb-ha:pg16` image for pgvector support. Create the `vector`, `pg_jsonschema`, and `ulid` extensions in the test database before schema generation and tests run.
Only create `pg_jsonschema` when the extension is present in the CI image, matching the `timescaledb-ha` service chosen in the preceding workflow change.
… workflow bootstrap Harden GitHub Actions database bootstrap in both CI jobs by probing `pg_available_extensions` before running `CREATE EXTENSION ulid`. If the extension is missing in the selected timescaledb-ha image, the workflow now logs a skip instead of failing setup. This mirrors the neighboring pg_jsonschema optionalization and makes the CI path resilient to image variants that ship different extension sets.
Replace the older multi-job cargo workflow with a devenv-based CI path that boots a local Postgres instance, runs migrations, enforces the forbidden-pattern guard, regenerates schemas, and executes the test suite from the shell. Update the surrounding schema/property tests and ULID-extension handling to match the new CI environment.
…allback Bring back the package, task, environment, and process definitions after the CI migration reduced `devenv.nix` to a bootstrap stub. Keep the optional-input fallback in place.
Switch the fallback from tracking `master.tar.gz` to a fixed fenix revision and `narHash` so the dev shell remains reproducible without the flake input.
Replace the structured `builtins.getFlake` attrset with the GitHub URL form that Nix accepts, keeping the fallback fenix input usable when `inputs.fenix` is absent.
- Move the migration/test sequence into a `nix develop` shell so it sees the same tools and environment as local `devenv` usage. - Keep the Postgres bootstrap and task execution in one supported shell context.
Add `--no-pure-eval` to the GitHub Actions `nix develop` invocation so the devenv-based workflow can evaluate the local flake in CI.
Tighten the main CI workflow to quote `pg_ctl` socket flags correctly and run an explicit `psql` probe after startup. This closes the immediate startup race uncovered by the explicit SQL bootstrap change.
Replace `createuser` and `createdb` calls in the main CI workflow with direct `psql` blocks that create the role and database when missing. This makes the main CI job match the more explicit bootstrap style used in the sibling workflows.
Replace GitHub service-container Postgres with locally bootstrapped Nix-managed clusters in the schema-validation and SQLx workflows. This is the large pivot that the following commits keep hardening around permissions, sockets, and startup behavior.
- Push schema and SQLx workflow commands through explicit Nix shell wrappers instead of open-coded shell blocks. - Reduce drift between jobs while the bootstrap path is being standardized.
Pass `DEVENV_ROOT` into the workflow environment before invoking the Nix and devenv wrappers. This keeps the root calculation stable across the ongoing CI shell refactors.
Set `devenv.root` to the workspace path by default so both local shells and workflows agree on the repository root. This is an enabling tweak for the wrapper-based CI invocations.
Temporarily run the role and database creation steps as `PGUSER=postgres` across the workflows. This is a short corrective step in the bootstrap iteration before the local-user approach replaces it.
Capture the current local Unix user and use it as the Postgres superuser when creating the application role and database. This adapts the socket-based workflow bootstrap to how `initdb --auth=trust` provisions local clusters.
Swap the bootstrap `DO $$` blocks for direct existence checks followed by `CREATE ROLE` and `CREATE DATABASE` calls when needed. This makes setup failures easier to localize in workflow logs.
Replace the `devenv tasks run db:migrate` indirection with a direct `cargo run -- up` from `crate/lib/sinex-schema` in the relevant workflows. This removes one more layer from the bootstrap path while it is being debugged.
Have the workflows explicitly create the required extensions and keep `listen_addresses = ''` for the socket-based clusters. This makes the new extension-enabled Postgres build visible to CI.
Use the custom `postgresqlWithExtensions` package in the dev environment instead of plain `postgresql_16`. This wires the bundled extension work into actual local and CI usage.
Add an `ensure_extension()` helper with `pgx_ulid` and `ulid` fallback logic plus explicit checks for `pg_jsonschema`, `timescaledb`, and vector support. This makes extension setup failures surface earlier in workflow logs.
Package `pg_jsonschema` from the Debian artifact into a custom Postgres derivation used by the dev shell. This gives local and CI bootstrap flows the extension set that the schema and SQLx jobs require.
Add `shared_preload_libraries = 'timescaledb'` to the CI Postgres configs so migrations and tests can create the extension correctly. This keeps the local workflow cluster consistent with the pinned Timescale environment.
Point the migration step at the superuser connection rather than the anonymous socket URL so extension and schema setup succeed reliably. This is another bootstrap correction in the same chain.
Introduce a small Python-based helper to build the encoded socket URI before passing it into database URLs. This is the first follow-up after the socket bootstrap switch.
Encode the Unix-socket path when constructing `DATABASE_URL` so clients parse it correctly. This is a targeted follow-up to the socket-based bootstrap phase.
Run the local CI Postgres instances on `127.0.0.1:55432` and update the connection handling accordingly. This is the pivot away from socket-only bootstrap that the surrounding commits keep refining.
Switch CI and SQLx and schema workflows to `pg_ctl start -w` so they block until Postgres is actually ready. This removes the race that earlier bootstrap steps had to work around.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 7 minutes and 14 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (16)
Note
|
…ioning (#104) Standardize CI and local devenv Postgres bootstrap around an extension-capable cluster so migrations, schema generation, and SQLx validation all run against the same database shape instead of a patchwork of service containers and implicit local assumptions. GitHub Actions workflows: - Rework `.github/workflows/ci.yml`, `schema-validation.yml`, `sqlx-cache.yml`, and `sqlx-check.yml` to run through `nix develop --no-pure-eval`, bootstrap a local Postgres instance, and provision the `sinity` role plus `sinex_dev` database before running migrations, schema regeneration, or SQLx preparation. - Fix the ordering bugs in those jobs so database readiness checks, migrations, and schema generation happen in the right sequence, which removes the earlier “generate first, migrate later” failure mode. - Make extension setup explicit for Timescale, vector/pgvector, ULID, and optional `pg_jsonschema`, and add availability checks/fallback logic where CI images differ in what they ship. devenv and Nix packaging: - Restore the full `devenv` configuration behind the fenix fallback, then switch the dev shell to a `postgresqlWithExtensions` package so the local shell and the workflow bootstrap agree on which extensions are supposed to exist. - Keep the workflow execution path inside the devenv shell and fix the root/env propagation (`DEVENV_ROOT`, `DEVENV_DOTFILE`) so nested Nix/devenv commands stop depending on fragile current-directory assumptions. - Add smaller reliability fixes such as `pg_ctl -w`, explicit socket/TCP probing, and build dependency installation (`mold`, ripgrep, PostgreSQL client`) so bootstrap failures become deterministic instead of timing-sensitive. schema/tests and supporting code: - Update `crate/core/sinex-ingestd/tests/validator_schema_order_tests.rs` with an `ensure_ulid_extension()` helper that can work with either `ulid` or `pgx_ulid`, which keeps the test suite compatible with the extension set available in the running Postgres build. - Carry the small `sinex-test-utils` and property-test adjustments required by the new CI/devenv execution path so the workflows exercise the same harness shape developers use locally. - Preserve the schema regeneration check in CI and keep the migrations anchored in `crate/lib/sinex-schema`, which makes the workflow explicit about the only supported migration entrypoint.
There was a problem hiding this comment.
Pull request overview
Standardizes Postgres bootstrap + extension provisioning so CI workflows and the local devenv environment run migrations/schema generation/SQLx checks against the same extension-capable Postgres setup, and adjusts test utilities/macros to better capture failure context and handle ULID extension variants.
Changes:
- Reworks CI + schema/SQLx workflows to run DB-dependent steps inside
nix developand provision a consistent Postgres cluster + extensions. - Extends
devenvPostgres packaging to include required extensions (Timescale/vector/ULID/pg_jsonschema) and updates schema/tests to tolerateulidvspgx_ulid. - Improves test failure artifact capture (snapshot context + proptest runner configuration).
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| rustfmt.toml | Ignores rustfmt on large property test files. |
| devenv.nix | Adds extension-aware Postgres package + pinned fenix fallback + devenv root wiring. |
| crate/lib/sinex-test-utils/src/test_context.rs | Adds failure snapshot type to persist context/logs across moves. |
| crate/lib/sinex-test-utils/src/snapshot_helper.rs | Extends failure persistence API to accept borrowed or snapshotted context. |
| crate/lib/sinex-test-utils/src/property_testing.rs | Centralizes proptest runner config + regression file path selection. |
| crate/lib/sinex-test-utils/src/lib.rs | Exposes proptest runner config helper + re-exports failure snapshot. |
| crate/lib/sinex-test-utils/macros/src/lib.rs | Updates sinex_prop config/seed handling and failure persistence calls. |
| crate/lib/sinex-schema/src/migrations/m20241028_000001_create_canonical_schema.rs | Adds ulid → pgx_ulid fallback when provisioning extensions. |
| crate/lib/sinex-core/tests/property/ulid_property_test.rs | Fixes/adjusts proptest block structure. |
| crate/lib/sinex-core/tests/property/schema_property_test.rs | Makes proptest returns explicit with Report turbofish. |
| crate/lib/sinex-core/tests/property/event_model_fuzzing_test.rs | Makes proptest returns explicit and adjusts macro block structure. |
| crate/core/sinex-ingestd/tests/validator_schema_order_tests.rs | Adds helper to create whichever ULID extension is available. |
| .github/workflows/sqlx-check.yml | Runs SQLx check inside nix develop with local Postgres bootstrap + extensions. |
| .github/workflows/sqlx-cache.yml | Validates SQLx cache inside nix develop with standardized Postgres bootstrap. |
| .github/workflows/schema-validation.yml | Validates schema generation inside nix develop with standardized Postgres bootstrap. |
| .github/workflows/ci.yml | Consolidates CI to a devenv-driven integration-style job with standardized Postgres bootstrap. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| )); | ||
| }; | ||
|
|
||
| let stmt = format!(r#"CREATE EXTENSION IF NOT EXISTS "{extension}""#); |
There was a problem hiding this comment.
The CREATE EXTENSION statement is malformed: format!(r#"CREATE EXTENSION IF NOT EXISTS "{extension}""#) produces an extra trailing quote and no semicolon, so this will error at runtime. Build the statement without the trailing quote (and ideally add ;).
| let stmt = format!(r#"CREATE EXTENSION IF NOT EXISTS "{extension}""#); | |
| let stmt = format!(r#"CREATE EXTENSION IF NOT EXISTS "{extension}";"#); |
| lib.filter (pkg: pkg != null) [ | ||
| (if ps ? timescaledb then ps.timescaledb else null) | ||
| (if ps ? pgvector then ps.pgvector else null) | ||
| pgJsonschemaPkg |
There was a problem hiding this comment.
pgJsonschemaPkg fetches a prebuilt .deb for pg16-amd64-linux-gnu, but it’s included unconditionally in postgresqlWithExtensions. This will fail to evaluate/build on non-x86_64 Linux systems (and likely macOS). Consider guarding this derivation/package with a system == "x86_64-linux" check (or using ps.pg_jsonschema when available) so devenv remains usable cross-platform.
| pgJsonschemaPkg | |
| (if ps ? pg_jsonschema then ps.pg_jsonschema else if system == "x86_64-linux" then pgJsonschemaPkg else null) |
| export DATABASE_URL="postgresql://${SUPERUSER}@${PGHOST}:${PGPORT}/sinex_dev" | ||
|
|
||
| pushd crate/lib/sinex-schema >/dev/null | ||
| cargo run -- up | ||
| popd | ||
|
|
||
| psql -h "$PGHOST" -p "$PGPORT" -U sinity -d sinex_dev -v ON_ERROR_STOP=1 -c "INSERT INTO sinex_schemas.event_payload_schemas (source, event_type, schema_version, schema_content, content_hash) VALUES ('test.source', 'test.event', '1.0.0', '{}'::jsonb, md5(random()::text)) ON CONFLICT (source, event_type, schema_version) DO NOTHING;" | ||
| psql -h "$PGHOST" -p "$PGPORT" -U sinity -d sinex_dev -v ON_ERROR_STOP=1 -c "UPDATE sinex_schemas.event_payload_schemas SET is_active = true WHERE source = 'test.source' AND event_type = 'test.event';" | ||
| psql -h "$PGHOST" -p "$PGPORT" -U sinity -d sinex_dev -v ON_ERROR_STOP=1 -c "SELECT COUNT(*) FROM sinex_schemas.event_payload_schemas WHERE source = 'test.source';" |
There was a problem hiding this comment.
This workflow runs migrations with DATABASE_URL as the initdb superuser (line 89-93) but then verifies schema registry writes by connecting as sinity (line 95-97). Since migrations create schemas/tables owned by the migration role, sinity is likely to hit permission errors unless ownership/grants are explicitly handled. To make this check reliable, run migrations as sinity after extension provisioning (or add explicit ALTER ... OWNER TO sinity / GRANTs in the migration/bootstrap).
| jobs: | ||
| check: | ||
| name: Nix Flake Check | ||
| test: | ||
| name: Devenv Integration Test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install Nix | ||
| uses: cachix/install-nix-action@v24 | ||
| - uses: actions/checkout@v5 | ||
|
|
||
| - uses: cachix/install-nix-action@v31 | ||
| with: | ||
| nix_path: nixpkgs=channel:nixos-unstable | ||
| extra_nix_config: | | ||
| experimental-features = nix-command flakes | ||
|
|
||
| - name: Setup Cachix | ||
| uses: cachix/cachix-action@v14 | ||
| with: | ||
| name: sinex | ||
| skipPush: ${{ github.event_name == 'pull_request' }} | ||
|
|
||
| - name: Nix Flake Check | ||
| run: nix flake check --accept-flake-config | ||
|
|
||
| test: | ||
| name: Cargo Test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| services: | ||
| postgres: | ||
| image: timescale/timescaledb:2.15.2-pg16 # Pin exact Timescale/Postgres versions for deterministic CI | ||
| env: | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: postgres | ||
| POSTGRES_DB: postgres | ||
| ports: | ||
| - 5432:5432 | ||
| options: >- | ||
| --health-cmd pg_isready | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
| - uses: cachix/cachix-action@v16 | ||
| with: | ||
| name: sinity | ||
| authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' | ||
| skipPush: true | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install ripgrep | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y ripgrep | ||
|
|
||
| - name: Enforce forbidden pattern guards | ||
| run: bash scripts/check_forbidden_patterns.sh | ||
| - name: Install devenv.sh | ||
| shell: bash | ||
| run: nix profile install nixpkgs#devenv | ||
|
|
||
| - name: Regenerate schemas and ensure repository is clean | ||
| # Treat schemas/ like a generated artifact (similar to cargo fmt). | ||
| - name: Run migrations and tests | ||
| shell: 'nix develop --no-pure-eval --command bash --noprofile --norc -euo pipefail {0}' | ||
| env: | ||
| DATABASE_URL: postgres://sinex_test:test_password@localhost/sinex_test | ||
| DEVENV_ROOT: ${{ github.workspace }} | ||
| DEVENV_DOTFILE: ${{ github.workspace }}/.devenv | ||
| run: | | ||
| ./scripts/schema-dev.sh generate | ||
| if ! git diff --quiet -- schemas; then | ||
| echo "::error::Schema artifacts are stale. Run './scripts/schema-dev.sh generate' and commit the results." | ||
| git status schemas | ||
| exit 1 | ||
| devenv test |
There was a problem hiding this comment.
CI is now a single Devenv Integration Test job. If the previous Nix flake checks and coverage reporting are still required quality gates, they appear to have been dropped rather than moved into devenv test/dev:test. Consider re-adding equivalent steps (or documenting that these checks are intentionally removed/replaced) so CI coverage doesn’t regress silently.
| export PGDATA="$PWD/postgres_data" | ||
| rm -rf "$PGDATA" | ||
| mkdir -p "$PGDATA" | ||
| export PGHOST=127.0.0.1 | ||
| export PGPORT=55432 | ||
| initdb --auth=trust --no-locale --encoding=UTF8 | ||
| echo "unix_socket_directories = '$PWD'" >> "$PGDATA/postgresql.conf" | ||
| echo "listen_addresses = '127.0.0.1'" >> "$PGDATA/postgresql.conf" | ||
| echo "port = $PGPORT" >> "$PGDATA/postgresql.conf" | ||
| echo "shared_preload_libraries = 'timescaledb'" >> "$PGDATA/postgresql.conf" | ||
| pg_ctl start -w -l postgres.log -o "-k $PWD -p $PGPORT" | ||
| trap 'pg_ctl stop' EXIT | ||
|
|
||
| SUPERUSER=$(id -un) | ||
| if ! PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'sinity'" | grep -q 1; then | ||
| PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d postgres -v ON_ERROR_STOP=1 -c "CREATE ROLE sinity LOGIN CREATEDB;" | ||
| fi | ||
| if ! PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = 'sinex_dev'" | grep -q 1; then | ||
| PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE sinex_dev OWNER sinity;" | ||
| fi | ||
|
|
||
| ensure_extension() { | ||
| local db="$1" | ||
| shift | ||
| for candidate in "$@"; do | ||
| if PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d "$db" -tAc "SELECT 1 FROM pg_available_extensions WHERE name = '${candidate}'" | grep -q 1; then | ||
| PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d "$db" -v ON_ERROR_STOP=1 -c "CREATE EXTENSION IF NOT EXISTS ${candidate};" | ||
| return 0 | ||
| fi | ||
| done | ||
| echo "::error::None of the requested extensions ($*) are available in this PostgreSQL build." | ||
| PGUSER="$SUPERUSER" psql -h "$PGHOST" -p "$PGPORT" -d "$db" -tAc "SELECT name FROM pg_available_extensions ORDER BY name;" | ||
| exit 1 | ||
| } | ||
|
|
||
| ensure_extension sinex_dev pgx_ulid ulid | ||
| ensure_extension sinex_dev pg_jsonschema | ||
| ensure_extension sinex_dev timescaledb | ||
| ensure_extension sinex_dev vector | ||
|
|
||
| export DATABASE_URL="postgresql://${SUPERUSER}@${PGHOST}:${PGPORT}/sinex_dev" |
There was a problem hiding this comment.
The Postgres bootstrap shell (initdb/pg_ctl/role+db creation/ensure_extension) is duplicated inline here and in other workflows (sqlx-check.yml, sqlx-cache.yml, schema-validation.yml). This increases the risk of drift and subtle inconsistencies over time; consider extracting it into a shared script (e.g. scripts/ci/postgres-bootstrap.sh) or a composite action and invoking it from each workflow.
…ioning (#104) Standardize CI and local devenv Postgres bootstrap around an extension-capable cluster so migrations, schema generation, and SQLx validation all run against the same database shape instead of a patchwork of service containers and implicit local assumptions. GitHub Actions workflows: - Rework `.github/workflows/ci.yml`, `schema-validation.yml`, `sqlx-cache.yml`, and `sqlx-check.yml` to run through `nix develop --no-pure-eval`, bootstrap a local Postgres instance, and provision the `sinity` role plus `sinex_dev` database before running migrations, schema regeneration, or SQLx preparation. - Fix the ordering bugs in those jobs so database readiness checks, migrations, and schema generation happen in the right sequence, which removes the earlier “generate first, migrate later” failure mode. - Make extension setup explicit for Timescale, vector/pgvector, ULID, and optional `pg_jsonschema`, and add availability checks/fallback logic where CI images differ in what they ship. devenv and Nix packaging: - Restore the full `devenv` configuration behind the fenix fallback, then switch the dev shell to a `postgresqlWithExtensions` package so the local shell and the workflow bootstrap agree on which extensions are supposed to exist. - Keep the workflow execution path inside the devenv shell and fix the root/env propagation (`DEVENV_ROOT`, `DEVENV_DOTFILE`) so nested Nix/devenv commands stop depending on fragile current-directory assumptions. - Add smaller reliability fixes such as `pg_ctl -w`, explicit socket/TCP probing, and build dependency installation (`mold`, ripgrep, PostgreSQL client`) so bootstrap failures become deterministic instead of timing-sensitive. schema/tests and supporting code: - Update `crate/core/sinex-ingestd/tests/validator_schema_order_tests.rs` with an `ensure_ulid_extension()` helper that can work with either `ulid` or `pgx_ulid`, which keeps the test suite compatible with the extension set available in the running Postgres build. - Carry the small `sinex-test-utils` and property-test adjustments required by the new CI/devenv execution path so the workflows exercise the same harness shape developers use locally. - Preserve the schema regeneration check in CI and keep the migrations anchored in `crate/lib/sinex-schema`, which makes the workflow explicit about the only supported migration entrypoint.
Summary
I moved the repository’s workflow validation onto a single extension-aware Postgres bootstrap story shared by CI and the local
devenvshell. Instead of juggling GitHub service containers in one place, shell-initialized local clusters in another, and a dev shell that did not guarantee the same extension set, the workflows now run migrations/schema generation/SQLx checks insidenix developagainst a deliberately provisionedsinex_devdatabase andsinityrole. I also tightened extension setup for Timescale, vector, ULID, and optionalpg_jsonschema, and updated the few tests that needed to tolerateulidvspgx_uliddifferences. The branch is essentially a long stabilization loop that ends with CI and the dev shell describing the same database.Motivation
The repository had a real “works in one environment, fails in another” problem around Postgres.
Migrations and schema/sqlx jobs need more than vanilla PostgreSQL: they rely on Timescale, vector, ULID support, and sometimes
pg_jsonschema. Different workflow jobs were provisioning those extensions differently, some used GitHub Actions service images, some tried to emulate the local shell, and the dev shell itself was not guaranteeing the full extension set in one explicit package. That made failures hard to classify. Was the migration broken, or did the job just not haveulid? Did schema generation fail because the DB was wrong, or because the cluster was not ready yet?The branch went through several approaches because the exact bootstrap point mattered. I tried leaning harder on GitHub service containers, then moved the work inside
devenv, then had to fix pure-eval issues, role creation, socket readiness, extension availability, and superuser-vs-application-role behavior. I’m mentioning that because the final shape is the result of those pivots, not a first-pass design.Changes grouped by concern
1. Run workflow database work inside
nix developThe decisive structural change is that the important database-aware jobs now run inside
nix develop --no-pure-evalrather than relying on a looser outer shell plus a partially separate Postgres story.That gives us a single environment in which to:
devenv test,sinity/sinex_dev,crate/lib/sinex-schema,I also made
DEVENV_ROOTandDEVENV_DOTFILEexplicit where nested bootstrap commands need them. That turns an implicit “hope the current directory and child shell agree” assumption into a real contract.2. Make the Postgres cluster extension-aware everywhere
The workflows now provision the database with the extension set the repo actually needs. Over the course of the branch I tightened this from broad “CREATE EXTENSION” attempts to availability-aware logic and a local/dev shell that ships the extensions directly.
The key devenv-side change is the
postgresqlWithExtensionspackage:That matters because it stops the local shell from lagging behind the workflow expectations. If CI and the dev shell are both talking about an extension-capable PostgreSQL package, the remaining failures are much easier to trust.
3. Fix bootstrap sequencing and role behavior
Several of the mid-branch fixes were about ordering and permissions rather than architecture, but they are the difference between a reproducible bootstrap and a flaky one.
The workflows now:
pg_ctl -wor explicit probes instead of timing assumptions,I also corrected the “who runs migrations?” story. The branch briefly tried running migrations as the application role and then reassigning ownership, but the cleaner outcome was to keep the migration/bootstrap path explicit and then make sure the application role can connect and operate normally afterward. That is less magical and easier to debug in CI logs.
4. Adjust schema-related tests to the real extension matrix
validator_schema_order_tests.rsnow has anensure_ulid_extension()helper that accepts eitherulidorpgx_ulid. This is a small change, but it is exactly the kind of thing that keeps test intent focused on schema ordering rather than on whichever extension name the current Postgres build exposes.I also carried a few harness/property-test touch-ups that were required by the new execution path so that the workflows continue to use the same
sinex_test_utilsshape as local development.Testing
The branch’s strongest validation is the workflows themselves: CI, schema validation, SQLx cache, and SQLx check now all exercise the standardized bootstrap path. The schema regeneration check remains in place, so the branch does not just boot a DB—it proves the migration/generation ordering against the actual supported toolchain.
At the Rust-test level,
validator_schema_order_tests.rsnow explicitly handles theulid/pgx_ulidsplit, which covers one of the more annoying extension-availability edge cases exposed by the branch.The main gap is that the bootstrap logic is mostly exercised through workflow execution rather than through a standalone unit-test suite. That is acceptable here because the behavior is inherently operational and tightly coupled to the shell/database environment.
Notes
This branch is full of “fix(ci)” commits because the problem only really showed up once the workflows were forced onto a single path. I think that is a feature rather than a weakness: each fix removed one more silent assumption about extensions, readiness, or role ownership.
The final result I cared about was simple: if a developer or workflow says “run migrations, regenerate schemas, and validate SQLx,” they should all be talking to the same kind of PostgreSQL cluster with the same extension story.
Ref #103