Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
c424e2e
build: harden v3 dep ordering (LC_ALL=C sort, cross-platform cycle ga…
tobyhede Jul 8, 2026
7cf5f40
codegen: emit deterministic topo-ordered manifest for the generated S…
tobyhede Jul 8, 2026
0cb8c63
build: order generated surface from codegen manifest; tsort now a who…
tobyhede Jul 8, 2026
0eabc47
build: add referenced-vs-defined symbol cross-check over the installe…
tobyhede Jul 8, 2026
76fcdc2
ci/docs: gate symbol-order + build-ordering helpers; document codegen…
tobyhede Jul 8, 2026
3455561
build: address review — fail-loud strip_require_lines (propagate grep…
tobyhede Jul 8, 2026
0e72905
style: cargo fmt + silence clippy::type_complexity in property test s…
tobyhede Jul 9, 2026
a7651be
build: teach the symbol-order checker the eql_v3 CREATE DOMAIN form
tobyhede Jul 9, 2026
965dce2
build: order the whole v3 surface from one walk, not two enumerations
tobyhede Jul 9, 2026
fccd712
build: harden the symbol-order gate and correct the ordering diagnostics
tobyhede Jul 9, 2026
8b5a116
test: gate the installer against the order, not just the order agains…
tobyhede Jul 9, 2026
fb7c096
build: drop the one-shot monolith reorder-only check
tobyhede Jul 9, 2026
e8b261b
build: address review — invalidate the build cache on gate edits, fai…
tobyhede Jul 17, 2026
2fd6bd3
build: report what the symbol gate cannot resolve; reject self-edges;…
tobyhede Jul 17, 2026
f9de116
build: describe the query-domain schema split without a private track…
tobyhede Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ All jobs run on `blacksmith-16vcpu-ubuntu-2204`. "PG set" follows the event
| **schema** | `test:schema` | v2.2 / v2.3 payload JSON-schema validation | no | no |
| **rust-crates** | `test:crates` + `types:check` | `cargo fmt --check`, clippy + `cargo test` for `eql-domains` / `eql-codegen` / `eql-tests-macros` / `eql-bindings`; verify TS bindings + JSON schemas are fresh | no | no |
| **codegen** | `codegen:parity` | Regenerate encrypted-domain SQL in place + `git diff` drift gate (committed `src/v3/scalars/` matches the generator) | no | no |
| **self-contained-v3** | `test:self_contained_v3` | `eql_v3` surface has no `eql_v2` dependency | no | no |
| **self-contained-v3** | `test:self_contained_v3`, `test:installer_complete`, `test:symbol_order_v3`, `test:build_ordering_helpers` | `eql_v3` surface has no `eql_v2` dependency; installer contains every ordered file; singleton symbols defined before use (overloads are resolved exactly by the `clean-install` job's `test:clean_install_v3`) | no | no |
| **matrix-coverage** | `test:matrix:inventory` (+`:jsonb_entry`, `:v3-jsonb`) + `test:matrix:catalog-coverage` | Scalar-matrix test-name snapshots are not silently dropped; catalog surface is covered | no | no |
| **splinter** | `test:splinter` | Supabase/Splinter lints over the installed EQL | yes (PG17) | no |
| **ci-required** | — | aggregator: every needed job is `success`/`skipped` | no | no |
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/test-eql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ jobs:
run: mise run clean && mise run --force build
- name: Assert eql_v3 is self-contained
run: mise run test:self_contained_v3
- name: Assert the installer contains every ordered file
run: mise run test:installer_complete
- name: Symbol-order cross-check (v3)
run: mise run test:symbol_order_v3
- name: Build-ordering helper unit tests
run: mise run test:build_ordering_helpers

matrix-coverage:
name: "Matrix coverage inventory"
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ deps-ordered.txt
deps-supabase.txt
deps-ordered-supabase.txt

src/deps-v3.txt
src/deps-ordered-v3.txt
src/deps-ordered-v3.txt.tmp

# Generated by tasks/build.sh from src/v3/version.template (eql_v3.version()).
src/v3/version.sql
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This project uses `mise` for task management. Common commands:
- `cipherstash-encrypt.sql` - The sole installer: the self-contained `eql_v3` surface, globbed from `src/v3` only (no `eql_v2`; installable into a DB with no `eql_v2` present)
- `cipherstash-encrypt-uninstall.sql` - Matching uninstaller

There are no longer separate Main / Supabase / Protect / v3-only build variants. The combined `eql_v2` build that previously produced multiple artefacts has been removed; the v3 surface now ships as one self-contained installer under the canonical `cipherstash-encrypt.sql` name (`tasks/build.sh` globs `src/v3` only). Because the surface owns no `eql_v2` dependency, it is already Supabase / managed-Postgres compatible (functional indexes over extractors, no superuser-only operator classes) without a dedicated subset build. Self-containment — no `-- REQUIRE:` edge pointing outside `src/v3`, no `eql_v2.<symbol>` anywhere in the surface — is enforced at build time by `verify_v3_self_contained` in `tasks/build.sh` and CI-gated by `mise run test:self_contained_v3`.
There are no longer separate Main / Supabase / Protect / v3-only build variants. The combined `eql_v2` build that previously produced multiple artefacts has been removed; the v3 surface now ships as one self-contained installer under the canonical `cipherstash-encrypt.sql` name (`eql-codegen order` walks `src/v3` only). Because the surface owns no `eql_v2` dependency, it is already Supabase / managed-Postgres compatible (functional indexes over extractors, no superuser-only operator classes) without a dedicated subset build. Self-containment — no `-- REQUIRE:` edge pointing outside `src/v3`, no `eql_v2.<symbol>` anywhere in the surface — is enforced at build time by `surface_order`'s `OutsideSurface` error (`crates/eql-codegen/src/ordering.rs`) and CI-gated by `mise run test:self_contained_v3`.

## Project Architecture

Expand Down Expand Up @@ -189,7 +189,7 @@ HTML output is also generated in `docs/api/html/` for local preview only.

- SQL files are modular - put operator wrappers in `operators.sql`, implementation in `functions.sql`
- All SQL files must have `-- REQUIRE:` dependency declarations
- Build system uses `tsort` to resolve dependency order
- Build system resolves dependency order with `cargo run -p eql-codegen -- order`, which walks the whole `src/v3` surface once and topologically sorts it from the `-- REQUIRE:` edges. Dangling targets, edges leaving `src/v3`, and cycles all fail the build.
- **Documentation**: All functions/types must have Doxygen comments (see Documentation Standards above)

### Function Language Choice (SQL vs PL/pgSQL)
Expand Down
15 changes: 9 additions & 6 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ These are the important files and directories in the repo:
│ │ │ └── <T>/ <-- e.g. integer/, text/, boolean/ (generated, committed in place)
│ │ ├── jsonb/ <-- jsonb SteVec support
│ │ └── lint/ <-- structural lints
│ ├── deps-v3.txt <-- REQUIRE edges for the v3 surface
│ ├── deps-ordered-v3.txt <-- tsorted build order
│ ├── deps-ordered-v3.txt <-- install order, emitted by `eql-codegen order`
│ └── README.md
├── docs/ <-- reference, concept, and API documentation
├── tests/ <-- test framework and fixtures
Expand Down Expand Up @@ -223,10 +222,14 @@ At minimum, a file references the schema:
-- REQUIRE: src/v3/schema.sql
```

The build collects these edges into `src/deps-v3.txt`, resolves them with
`tsort` into `src/deps-ordered-v3.txt`, and concatenates the files in
dependency order to produce a single installer. The build fails loudly if a
file referenced in the dependency list does not exist.
`cargo run -p eql-codegen -- order` walks the whole `src/v3` tree once, collects
these edges, and topologically sorts them into `src/deps-ordered-v3.txt`; the
build then concatenates the files in that order to produce a single installer.
Generated and hand-written files are ordered together, so nothing can fall
between two enumerations and be dropped. The build fails loudly if a `-- REQUIRE:`
target does not exist, if an edge leaves `src/v3`, or if the edges form a cycle.
`mise run test:installer_complete` then asserts the installer actually contains
every ordered file's body.

The `eql_v3` surface is **self-contained**: no `eql_v2.<symbol>` reference
appears anywhere under `src/v3/`. This invariant is enforced in CI by
Expand Down
3 changes: 3 additions & 0 deletions crates/eql-codegen/src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,9 @@ pub fn generate_all(out_root: &Path) -> Result<i32, WriteError> {
}
}

// No ordering manifest is emitted here. The installer order is derived by
// `eql-codegen order` from a single walk of the whole src/v3 surface, so the
// generator has no say in — and cannot disagree with — what gets ordered.
let names: Vec<&str> = eql_domains::families_with_scalar_domains()
.map(|s| s.name)
.collect();
Expand Down
1 change: 1 addition & 0 deletions crates/eql-codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod context;
pub mod dump;
pub mod generate;
pub mod operator_surface;
pub mod ordering;
pub mod writer;

/// The repository root, derived from this crate's manifest dir (the generator
Expand Down
32 changes: 32 additions & 0 deletions crates/eql-codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,37 @@ fn main() -> ExitCode {
}
}

// `order`: print the install order of the whole src/v3 SQL surface, one
// repo-relative path per line, dependency before dependent. Consumed by
// tasks/build.sh (`> src/deps-ordered-v3.txt`), which concatenates the files
// in this order into release/cipherstash-encrypt.sql.
//
// The walk is the ONLY enumeration of the surface — hand-written and
// generated files are ordered together from their `-- REQUIRE:` edges, with
// no marker classifier and no separate codegen manifest to fall out of sync
// with. Missing REQUIRE targets, targets outside src/v3, and cycles are all
// hard errors here, so build.sh needs no post-hoc verification of the order.
if args.len() == 2 && args[1] == "order" {
let root = out_root();
let result = eql_codegen::ordering::walk_v3_surface(&root)
.map_err(|e| format!("walking {}/src/v3: {e}", root.display()))
.and_then(|files| {
eql_codegen::ordering::surface_order(&files).map_err(|e| e.to_string())
});
match result {
Ok(order) => {
for path in &order {
println!("{path}");
}
return ExitCode::SUCCESS;
}
Err(e) => {
eprintln!("error: {e}");
return ExitCode::FAILURE;
}
}
}

// `clean`: remove the generated SQL surface (marker-aware) under every
// src/v3/scalars/* type dir. Replaces build.sh's filename-pattern sweep;
// hand-written files (no AUTO-GENERATED marker) are preserved.
Expand Down Expand Up @@ -102,6 +133,7 @@ fn main() -> ExitCode {
}

eprintln!("Usage: eql-codegen (generate all types)");
eprintln!(" eql-codegen order (print the src/v3 install order, one path per line)");
eprintln!(" eql-codegen clean (remove the generated SQL surface)");
eprintln!(" eql-codegen list-types (print catalog tokens)");
eprintln!(" eql-codegen list-schemas (print owned schemas, public first)");
Expand Down
Loading
Loading