Skip to content
Merged
Changes from all commits
Commits
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 CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Migrated from the dobby memory repo (`encryption4all/dobby`). This file is the h

## Workspace & CI

- Workspace members: `pg-core` (lib), `pg-ffi` (C ABI), `pg-pkg` (PKG service), `pg-cli`, `cryptify` (file-transfer service, merged in 2026-07-31). `pg-wasm` is a sibling crate the root `Cargo.toml` lists under `exclude`, so it is not part of the workspace and is built separately with wasm-pack (see Release & configuration). Sub-crates share workspace files. Build the workspace from repo root with `cargo build`. A bare `cargo test --workspace` FAILS to compile: `pg-core`'s tests are gated behind its `test` feature (also `rust`/`stream`), so the item is configured out and imports like `crate::test::TestSetup` don't resolve. CI (`.github/workflows/build.yml`) runs tests per crate: `cargo test --manifest-path pg-core/Cargo.toml --features test,rust,stream` for core, `--all-targets` for `cryptify` (it declares no features of its own, so that is the equivalent invocation), `--all-features` for `pkg`/`cli`/`ffi`. None of these cover `pg-wasm`. The `test`/`format`/`clippy` matrices key on the crate **directory** rather than a `pg-` suffix, because `cryptify` doesn't carry that prefix — so the check contexts are `Test workspace (pg-core)`, not `Test workspace (core)`. Nothing required points at them today, but whatever adds to the required list later must use the current names. Where that list lives is not obvious and an agent cannot read it: required checks come from **classic branch protection** (`gh api repos/encryption4all/postguard/branches/main/protection`, currently exactly `Wire compat`), *not* from the `main` ruleset, which carries only `deletion`/`non_fast_forward`/`pull_request` and no `required_status_checks` rule at all. `dobby-coder` gets 403 on the protection endpoint, so reading the ruleset alone concludes nothing is required, which is wrong — ask a maintainer rather than inferring. `pg-core` uses CGWKV + MKEM for multi-recipient encryption (production feature set `["cgwkv", "mkem"]`). [#262](https://github.com/encryption4all/postguard/issues/262) (merged `0343369`, #295) replaced the two per-language `Wire compat (published pg-core)` / `Wire compat (published pg-wasm/pg-js)` required checks with this single `wire-compat` job (`needs: [wire-compat-rust, wire-compat-js]`, `permissions: contents: read`); the two old names are no longer required and the underlying per-language jobs still exist and still run, just aren't required individually anymore.
- Workspace members: `pg-core` (lib), `pg-ffi` (C ABI), `pg-pkg` (PKG service), `pg-cli`, `cryptify` (file-transfer service, merged in 2026-07-31). `pg-wasm` is a sibling crate the root `Cargo.toml` lists under `exclude`, so it is not part of the workspace and is built separately with wasm-pack (see Release & configuration). Sub-crates share workspace files. Build the workspace from repo root with `cargo build`. Two test invocations are worth knowing, and the obvious reading of each is wrong. **`cargo test --workspace` passes** — 296 tests over 10 targets (9 binaries plus `pg-core`'s doc-tests), verified 2026-08-09 — but only by accident, so don't read it as the workspace being self-consistent. `pg-core`'s tests really are gated behind its `test` feature (also `rust`/`stream`), and `cargo test -p pg-core` alone still fails exactly as it always did, with `unresolved import crate::test` on `crate::test::TestSetup`. What rescues the workspace build is feature unification: `cryptify`'s dev-dependency asks for `pg-core` with `features = ["rust", "stream", "test"]` (`cryptify/Cargo.toml`), so the feature is on for every member — confirm with `cargo tree -e features -p pg-core --workspace`. That has only been true since `cryptify` joined the workspace on 2026-07-31; it is a side effect of one member's dev-deps rather than a property of the workspace, and it reverts to the old compile failure the moment that line changes. **`cargo test --workspace --all-features` does not compile at all**, on any host: it switches on `pg-core`'s `web`, whose `compile_error!` fires off wasm32 — `error: "web" feature should only be enabled on wasm32 targets`, `pg-core/src/client/web/mod.rs:19`. The axis is whether `pg-core` is in the selected set, **not** how the invocation is scoped: `cargo test -p pg-core --all-features` fails identically, so this is not a workspace-wide problem that scoping fixes. `--all-features` is correct only for the members that declare no features of their own — `pkg`, `cli` and `ffi` in the CI matrices, and the api_gate suite further down, which lives in `pg-pkg` — where it is a no-op. `pg-core` is the sole member with a `[features]` section, so it is the sole member `--all-features` can break. CI (`.github/workflows/build.yml`) runs tests per crate: `cargo test --manifest-path pg-core/Cargo.toml --features test,rust,stream` for core, `--all-targets` for `cryptify` (it declares no features of its own, so that is the equivalent invocation), `--all-features` for `pkg`/`cli`/`ffi`. None of these cover `pg-wasm`. The `test`/`format`/`clippy` matrices key on the crate **directory** rather than a `pg-` suffix, because `cryptify` doesn't carry that prefix — so the check contexts are `Test workspace (pg-core)`, not `Test workspace (core)`. Nothing required points at them today, but whatever adds to the required list later must use the current names. Where that list lives is not obvious and an agent cannot read it: required checks come from **classic branch protection** (`gh api repos/encryption4all/postguard/branches/main/protection`, currently exactly `Wire compat`), *not* from the `main` ruleset, which carries only `deletion`/`non_fast_forward`/`pull_request` and no `required_status_checks` rule at all. `dobby-coder` gets 403 on the protection endpoint, so reading the ruleset alone concludes nothing is required, which is wrong — ask a maintainer rather than inferring. `pg-core` uses CGWKV + MKEM for multi-recipient encryption (production feature set `["cgwkv", "mkem"]`). [#262](https://github.com/encryption4all/postguard/issues/262) (merged `0343369`, #295) replaced the two per-language `Wire compat (published pg-core)` / `Wire compat (published pg-wasm/pg-js)` required checks with this single `wire-compat` job (`needs: [wire-compat-rust, wire-compat-js]`, `permissions: contents: read`); the two old names are no longer required and the underlying per-language jobs still exist and still run, just aren't required individually anymore.
- `cryptify` was a separate repo until `ba380a1` (#277) merged it as a workspace member, history-preserving, the deliberate yes decided in #255/#285. What that bought: one lockfile, which closes a real drift class — the two trees previously built `pg-core`'s container serializer against two different `bincode-next` versions with nothing comparing them. What it costs is a **standing dependency coupling, and it does not go away**: `pg-pkg` reaches `libsqlite3-sys` through `sqlx`, `cryptify` reaches it through `rusqlite`, and it is `libsqlite3-sys` itself that declares `links = "sqlite3"` (`rusqlite`, `sqlx` and `sqlx-sqlite` all declare none — check with `cargo metadata`, not by guessing which crate in the chain owns it). Only one package per resolve graph may claim a given `links` value, and optional dependencies sit in the graph whether their feature is enabled or not — so `sqlx-sqlite` is locked even though `pg-pkg` enables only `postgres`. The newest intersecting pair is **sqlx 0.9 + rusqlite 0.39** (`libsqlite3-sys 0.37` in the root lockfile), so every `rusqlite` bump waits on sqlx's `libsqlite3-sys` ceiling — and that block is live today, not merely future: `rusqlite` 0.40.0 wants `libsqlite3-sys ^0.38.0` and 0.40.1 wants `^0.38.1`, both published, neither yanked, and both outside `sqlx-sqlite` 0.9.0's `>=0.30.1, <0.38.0`, so a lone rusqlite bump does not resolve at all. Don't bump either half alone; check the intersection first.
- `pg-compat` is a second excluded sibling crate (root `Cargo.toml` `exclude`), and the exclusion is load-bearing: it depends on `pg-core` from **crates.io** (`=0.6.1`), not on `../pg-core`, so it can open bytes sealed by this tree with published readers. It has its own `Cargo.lock` (run it with `--locked`). Its input comes from `cargo run -p pg-core --features stream --example seal-samples -- <dir>`, a deterministic sealer whose output layout is documented in `pg-compat/README.md`. CI wires the two together: `wire-compat-rust` in `build.yml` seals with HEAD and opens with published pg-core on any PR touching the wire surface (pg-core/pg-wasm/pg-compat/pg-compat-js trees, the ROOT `Cargo.lock`/`Cargo.toml` — pg-core resolves from the root lockfile — and build.yml itself); `pg-compat-lint` covers the crate's fmt/clippy, which the per-crate matrices don't. The `=0.6.1` pin is currently one release behind: `pg-core` 0.6.2 published 2026-07-30 and neither the pin nor `COMPATIBILITY.md`'s `crates.io` reader row moved, because nothing reads those rows — the npm rows cannot drift this way, since `manifest.test.mjs` machine-reads them. Tracked in #268; move the row and the pin together.
- `pg-compat-js` is the Node half of the same gate: a private npm package (no build step, no lint/format tooling in the repo) that opens the sealer's output with the published npm readers, installed side by side through `npm:` aliases (`pg-wasm-0-6-1`, `pg-js-2-3-3`, `pg-js-1-11-0`) because several versions of one package have to coexist. Run it locally with `npm --prefix pg-compat-js ci` then `PG_COMPAT_ARTIFACTS=<dir> npm --prefix pg-compat-js test`; in CI the `wire-compat-js` job in `build.yml` downloads the artifact `wire-compat-rust` sealed and runs the same suite, gated on `needs.wire-compat-rust.outputs.sealed` rather than a second copy of the path filter. `node --test test/` does NOT work (Node reads the bare directory as a module path and dies with `Cannot find module .../test`) — the `test` script passes the glob `"test/*.test.mjs"` instead. Its reader list is not free to edit on its own: `test/manifest.test.mjs` parses the fenced `Reader list` block in root `COMPATIBILITY.md` (`<registry> <package> <versions...>` rows) and compares the `npm` rows against `readers()`, so that block is machine-read and reformatting it into prose or a table breaks the test. It also compares each declared `package` and `version` against the installed alias's own `package.json`, read off disk because neither published package exports `package.json` (`import('<alias>/package.json')` is `ERR_PACKAGE_PATH_NOT_EXPORTED`).
Expand Down
Loading