Skip to content
Open
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
# a test too, and here for the same reason as the two above.
- run: cargo run -p xtask -- platforms
# And the table on the end of the release: what a tag publishes,
# which eight repositories fetch by version. release.yml assembles
# which twelve repositories fetch by version. release.yml assembles
# from it and verifies the directory back against it, so an
# artifact that stopped being produced fails the release that
# dropped it rather than the eight that wanted it.
Expand All @@ -123,7 +123,7 @@ jobs:
# floor catches is the order of magnitude, since a rewrite that
# allocates per block turns a release into a minute of hashing.
- run: ZU_GATE=1 cargo bench -p xtask --bench sha256
# And the table under all of it: the nine repositories the split
# And the table under all of it: the thirteen repositories the split
# created. The conductor dispatches to that list, the README
# publishes it, and the contract above names its consumers from
# it, so a repository joining or leaving the project is one row
Expand Down Expand Up @@ -559,7 +559,7 @@ jobs:
# them. It is not allowed on a branch heading for a release, so
# the gate lives here rather than in the runner's defaults.
- run: cargo run -p zu-cli --release -- corpus conformance/cases --strict
# The reader is read by nine repositories on every CI run of each
# The reader is read by thirteen repositories on every CI run of each
# of them, so its cost per case is asserted to stay linear as the
# corpus grows. The bench fails rather than reporting when it
# does not.
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/conductor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: conductor

# The dispatching half of the release train (dx/14 section 6). The tag
# on this repository builds and publishes the artifacts; this drives the
# eight repositories that build against them, collects what each reports
# twelve repositories that build against them, collects what each reports
# back, and fails the release if any of them fails a gate.
#
# Every dispatch here is a no-op, because none of the eight has a
Expand Down Expand Up @@ -40,7 +40,7 @@ on:

concurrency:
# One conductor per version. Two runs of one version dispatching to
# eight repositories is eight repositories building the same tag twice
# twelve repositories is twelve repositories building the same tag twice
# and reporting back in whichever order they finish.
group: conductor-${{ inputs.version }}
cancel-in-progress: false
Expand Down Expand Up @@ -74,6 +74,18 @@ jobs:
- repo: zu-dotnet
workflow: release.yml
reports: scorecard api-map corpus perf sizes
- repo: zu-kotlin
workflow: release.yml
reports: scorecard api-map corpus perf sizes
- repo: zu-scala
workflow: release.yml
reports: scorecard api-map corpus perf sizes
- repo: zu-swift
workflow: release.yml
reports: scorecard api-map corpus perf sizes
- repo: zu-dart
workflow: release.yml
reports: scorecard api-map corpus perf sizes
- repo: zu-kit
workflow: release.yml
reports: scorecard corpus
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: release

# The release train of dx/14 section 6: one version number, one day,
# one orchestrated run across nine repositories. This is the skeleton of
# one orchestrated run across thirteen repositories. This is the skeleton of
# it, and what is real here is deliberate. The build is the same matrix
# every pull request runs, the assemble step gathers exactly the rows of
# artifacts.toml, and the verify step reads the directory back against
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:
if-no-files-found: error
path: packaging

# The eight repositories, driven rather than releasing on their own
# The twelve repositories, driven rather than releasing on their own
# schedule, which is what keeps one version number meaning one thing.
# It runs after the artifacts exist because every one of them builds
# against those artifacts, and before the registries because a binding
Expand Down Expand Up @@ -141,5 +141,5 @@ jobs:
echo "no-op: deploy zu-web against this version, publish the notes, push the rendered Homebrew formula and Scoop manifest to the tap and the bucket, and bump AUR"
- name: What this run did not do
run: |
echo "The dispatches to the eight repositories ran and did nothing, because none of them has a release workflow yet."
echo "The dispatches to the twelve repositories ran and did nothing, because none of them has a release workflow yet."
echo "Every publish above is idempotent when it is real, so a partial release is resumed and not restarted."
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,12 @@ This repository holds the engine, the Rust SDK, the CLI, the C ABI and its gener
| [zu-python](https://github.com/tamnd/zu-python) | `zudb` on PyPI. PyO3, three wheels per platform | 1 |
| [zu-node](https://github.com/tamnd/zu-node) | `zudb` on npm. napi-rs, plus the WASM build, for Node, Bun, Deno, and the browser | 1 |
| [zu-go](https://github.com/tamnd/zu-go) | `github.com/tamnd/zu-go`. cgo, with a `purego` path | 1 |
| [zu-java](https://github.com/tamnd/zu-java) | `dev.zudb` on Maven Central. Panama, with a JNI fallback, plus Kotlin and Scala layers | 1 |
| [zu-java](https://github.com/tamnd/zu-java) | `dev.zudb` on Maven Central. Panama, with a JNI fallback | 1 |
| [zu-dotnet](https://github.com/tamnd/zu-dotnet) | `ZuDb` on NuGet. Source-generated P/Invoke, NativeAOT-clean | 2 |
| [zu-kotlin](https://github.com/tamnd/zu-kotlin) | `dev.zudb:zu-kotlin` on Maven Central. Kotlin/JVM over the Panama layer, coroutines and `Flow` | 2 |
| [zu-scala](https://github.com/tamnd/zu-scala) | `dev.zudb::zu-scala` on Maven Central. Scala 3 and 2.13, with Cats Effect and ZIO modules kept apart | 2 |
| [zu-swift](https://github.com/tamnd/zu-swift) | Swift Package Manager. The C ABI through the clang importer, `AsyncSequence` over rows | 2 |
| [zu-dart](https://github.com/tamnd/zu-dart) | `zudb` on pub.dev. `dart:ffi`, with the declarations generated from `zu.h` | 2 |
| [zu-kit](https://github.com/tamnd/zu-kit) | The binding kit: generated FFI declarations, corpus runners, a reference binding, the scorecard tool | 3 |
| [zu-web](https://github.com/tamnd/zu-web) | The documentation site. Two thirds of it is generated from this repository's release artifacts | |

Expand Down
18 changes: 9 additions & 9 deletions artifacts.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
schema = 1
doc = "What a release of zu publishes, one table for nine repositories."
doc = "What a release of zu publishes, one table for thirteen repositories."
audited = "2026-08-17"

# A release is a tag on this repository and a run that drives the eight
Expand All @@ -13,7 +13,7 @@ audited = "2026-08-17"
# own. `cargo xtask artifacts --assemble` gathers exactly these rows and
# `--verify` reads the directory back, which means an artifact that
# stopped being produced fails the release that dropped it rather than
# the eight repositories that wanted it.
# the twelve repositories that wanted it.
#
# `made` says where a row comes from and there are five answers. `file`
# is a path this tree already holds and the release copies. `corpus` is
Expand All @@ -23,39 +23,39 @@ audited = "2026-08-17"
# is over the rest of the release. `later` is an artifact the contract
# names and nothing makes yet, with the milestone that makes it: writing
# it down early is the point, since a consumer needs to know what a
# release will eventually carry and the alternative is eight
# release will eventually carry and the alternative is twelve
# repositories each guessing.

[[artifact]]
name = "libzu-<target>.tar.zst"
made = "platform"
consumers = ["zu-c", "zu-go", "zu-java", "zu-dotnet", "zu-kit"]
doc = "An install prefix for one tier 1 target, as the platform's job built it: the header, both library forms, the CLI, a pkg-config file, a CMake package config, the export list in each linker's syntax and the license. The five repositories here reach the engine through the C ABI rather than compiling against it, so this archive is the whole of what they link, and it unpacks as a prefix because that is the only shape pkg-config and find_package(zu) can both resolve their paths against (dx/09 C-4, C-5)."
consumers = ["zu-c", "zu-go", "zu-java", "zu-dotnet", "zu-kotlin", "zu-scala", "zu-swift", "zu-dart", "zu-kit"]
doc = "An install prefix for one tier 1 target, as the platform's job built it: the header, both library forms, the CLI, a pkg-config file, a CMake package config, the export list in each linker's syntax and the license. The nine repositories here reach the engine through the C ABI rather than compiling against it, so this archive is the whole of what they link, and it unpacks as a prefix because that is the only shape pkg-config and find_package(zu) can both resolve their paths against (dx/09 C-4, C-5)."

[[artifact]]
name = "zu.h"
made = "file"
from = "crates/zu-capi/include/zu.h"
consumers = ["zu-c", "zu-go", "zu-java", "zu-dotnet", "zu-kit", "zu-web"]
consumers = ["zu-c", "zu-go", "zu-java", "zu-dotnet", "zu-kotlin", "zu-scala", "zu-swift", "zu-dart", "zu-kit", "zu-web"]
doc = "The C ABI, published beside the libraries as well as inside each of them, because a consumer generating bindings needs the header without downloading a platform it does not build for. tamnd/zu-c deliberately does not hold a copy (dx/18 section 2)."

[[artifact]]
name = "model.json"
made = "file"
from = "docs/api/model.json"
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kit", "zu-web"]
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kotlin", "zu-scala", "zu-swift", "zu-dart", "zu-kit", "zu-web"]
doc = "The public Rust surface as data. Every binding checks its api-map.toml against the model of the version it builds against, and the site renders the reference pages from it, so it is fetched by version rather than read from this repository's main branch."

[[artifact]]
name = "conformance-<version>.tar.zst"
made = "corpus"
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kit"]
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kotlin", "zu-scala", "zu-swift", "zu-dart", "zu-kit"]
doc = "The cross-client conformance corpus for this exact version. A client pins an engine version and needs the cases that shipped with it, not the cases on this branch, which are the cases for a version it has not adopted (dx/15 section 2)."

[[artifact]]
name = "SHA256SUMS"
made = "sums"
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kit", "zu-web"]
consumers = ["zu-c", "zu-python", "zu-node", "zu-go", "zu-java", "zu-dotnet", "zu-kotlin", "zu-scala", "zu-swift", "zu-dart", "zu-kit", "zu-web"]
doc = "The digest of every other file of the release, one `sha256sum -c` line each, written last because it is over the rest of them. The install one-liners of dx/12 section 6 fetch this before they fetch anything else, since a `curl | sh` that pipes an unverified download into a shell is the install story every audit stops at, and the packaging manifests carry the same numbers so Homebrew and Scoop check what they install too."

[[artifact]]
Expand Down
44 changes: 42 additions & 2 deletions clients.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
schema = 1
doc = "The clients of this engine, who maintains each one, and what its tier promises."
audited = "2026-08-22"
audited = "2026-08-25"

# The scorecard of dx/01 section 5. A tier is a promise, and a promise
# with nobody's name on it is a commitment nobody made, so every client
Expand Down Expand Up @@ -157,7 +157,7 @@ registry = "Maven Central"
maintainer = "Tam Nguyen Duc <@tamnd>"
tier = 1
holds = ["quickstart", "reference", "idiom", "conditions", "misuse", "leaks", "install", "stability"]
doc = "Panama with a JNI fallback, and the Kotlin and Scala layers on top of it."
doc = "Panama with a JNI fallback. The Kotlin and Scala layers were on top of it until DX5 and are their own clients now, because a dependency is taken by name and the name a Kotlin project wants is a Kotlin one."

[[client]]
repository = "https://github.com/tamnd/zu-c"
Expand All @@ -179,6 +179,46 @@ tier = 2
holds = []
doc = "Source-generated P/Invoke, NativeAOT-clean."

[[client]]
repository = "https://github.com/tamnd/zu-kotlin"
language = "Kotlin"
package = "dev.zudb:zu-kotlin"
registry = "Maven Central"
maintainer = "Tam Nguyen Duc <@tamnd>"
tier = 2
holds = []
doc = "Kotlin/JVM over the Panama layer. use for closing, Sequence for rows, a suspend query and a Flow, and cancellation that reaches the interrupt rather than being dropped."

[[client]]
repository = "https://github.com/tamnd/zu-scala"
language = "Scala"
package = "dev.zudb::zu-scala"
registry = "Maven Central"
maintainer = "Tam Nguyen Duc <@tamnd>"
tier = 2
holds = []
doc = "Scala 3 first, cross published for 2.13. Using for resources, a sealed value type, Either at the edges, and the Cats Effect and ZIO modules kept apart."

[[client]]
repository = "https://github.com/tamnd/zu-swift"
language = "Swift"
package = "zu-swift"
registry = "Swift Package Manager"
maintainer = "Tam Nguyen Duc <@tamnd>"
tier = 2
holds = []
doc = "The C ABI through the clang importer, AsyncSequence over rows, a non-copyable handle that closes in its deinit, and the one-thread rule said in Sendable rather than in a comment."

[[client]]
repository = "https://github.com/tamnd/zu-dart"
language = "Dart"
package = "zudb"
registry = "pub.dev"
maintainer = "Tam Nguyen Duc <@tamnd>"
tier = 2
holds = []
doc = "dart:ffi with the declarations generated from zu.h and regenerated in CI, so a drift in the header is a diff in a pull request."

[[client]]
repository = "https://github.com/tamnd/zu-kit"
language = "Rust"
Expand Down
2 changes: 1 addition & 1 deletion crates/xtask/src/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
//! a `later` row is an artifact the contract names that nothing makes
//! yet, carrying the milestone that will make it: naming it early is
//! the point, since a consumer needs to know what a release will
//! eventually carry, and the alternative is eight repositories each
//! eventually carry, and the alternative is twelve repositories each
//! guessing.

use std::collections::BTreeMap;
Expand Down
14 changes: 9 additions & 5 deletions crates/xtask/src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,11 +1245,15 @@ mod tests {
let notes = table.check(&root, false).expect("the tree is readable");
assert!(notes.is_empty(), "{notes:#?}");

// Seven clients: the five tier 1 SDKs of DX4, the tier 2 one,
// and the kit. Every one of them owes a scorecard back, which is
// the list in repos.toml, and every one of them has a name on
// it, which is what dx/01 section 5 asks for.
assert_eq!(table.clients.len(), 7);
// Eleven clients: the five tier 1 SDKs of DX4, the five tier 2
// ones DX5 adds, and the kit. Every one of them owes a
// scorecard back, which is the list in repos.toml, and every one
// of them has a name on it, which is what dx/01 section 5 asks
// for. The five new ones start at tier 2 rather than at tier 1,
// because tier 1 asks for 100 on conformance and 90 on practice
// and a binding earns that by having shipped rather than by
// having been written.
assert_eq!(table.clients.len(), 11);
let tier1: Vec<&str> = table
.clients
.iter()
Expand Down
2 changes: 1 addition & 1 deletion crates/xtask/src/corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
//! reproducible, which is the shared tar writer's doing and the reason
//! a mirror can be compared against a release rather than trusted. And
//! the packer parses every case before it ships one, so a corpus that
//! does not load cannot become an artifact that eight repositories fail
//! does not load cannot become an artifact that twelve repositories fail
//! on.

use std::path::Path;
Expand Down
2 changes: 1 addition & 1 deletion crates/xtask/src/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! Reading the block by its indentation rather than parsing YAML: what
//! is wanted is a list of `key: value` under one key, the files are
//! written here, and a YAML library to read six keys out of them would
//! be a dependency in the build tooling of nine repositories. A
//! be a dependency in the build tooling of thirteen repositories. A
//! structure this does not understand is an error with a line number
//! rather than a row silently dropped, which is the rule the TOML
//! reader beside it follows too.
Expand Down
18 changes: 11 additions & 7 deletions crates/xtask/src/repos.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The repository table, and the three places that have to agree with
//! it.
//!
//! The split of dx/18 section 2 put eight repositories outside this one,
//! The split of dx/18 section 2 put twelve repositories outside this one,
//! and a split is only a decision once: after it, the list of what was
//! split out is a thing every part of the project quotes. The release
//! train dispatches to it, the README publishes it, the artifact
Expand Down Expand Up @@ -921,12 +921,16 @@ mod tests {
let notes = table.check(&root).expect("the tree is readable");
assert!(notes.is_empty(), "{notes:#?}");

// dx/18 section 2 is nine repositories, one of them this one,
// and the split is a decision that was made once. A row that
// quietly appeared or went is that decision changing without
// anybody saying so.
assert_eq!(table.repos.len(), 9);
assert_eq!(table.dispatched().count(), 8);
// dx/18 section 2 was nine repositories, one of them this one,
// and DX5 made it thirteen: zu-kotlin and zu-scala came out of
// zu-java, because a dependency is taken by name and the name a
// Kotlin project wants is a Kotlin one, and zu-swift and
// zu-dart were added on the reasoning that gave .NET its own
// row. The split is still a decision made deliberately, which
// is what this number is for: a row that quietly appeared or
// went is that decision changing without anybody saying so.
assert_eq!(table.repos.len(), 13);
assert_eq!(table.dispatched().count(), 12);
let tier1 = table
.repos
.iter()
Expand Down
4 changes: 2 additions & 2 deletions crates/xtask/src/terms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! not. The table is `style/zu/terms.yml` in `tamnd/zu-web`, because
//! the site is where the program's prose is published from; the reader
//! is here, because the prose with the most readers is here and because
//! a table checked by nine repositories against nine readers would be
//! a table checked by thirteen repositories against thirteen readers would be
//! nine tables.
//!
//! What is checked is prose, and only prose. Markdown, and the doc
Expand Down Expand Up @@ -43,7 +43,7 @@ use zu_corpus::yaml::{self, Node};
pub const SCHEMA: i64 = 1;

/// The floor on a definition. It is here rather than in a test because
/// the table is read by nine repositories and a definition nobody wrote
/// the table is read by thirteen repositories and a definition nobody wrote
/// is worse than a term nobody defined: the first looks like an answer.
const DOC_MIN: usize = 24;

Expand Down
2 changes: 1 addition & 1 deletion crates/xtask/src/toml.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The subset of TOML `api-map.toml` is written in.
//!
//! A general TOML parser is not what this needs. The map is a
//! hand-written file that has to exist in nine repositories and be
//! hand-written file that has to exist in thirteen repositories and be
//! read by people who did not write it, so the reader's job is to
//! refuse anything it does not understand rather than to accept as
//! much as possible. A key it silently ignored would be a mapping
Expand Down
2 changes: 1 addition & 1 deletion crates/xtask/tests/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ fn the_surface_a_binding_owes_is_the_one_a_user_touches() {

#[test]
fn a_binding_map_written_against_this_ledger_is_checked_the_other_way() {
// The nine repositories have no maps yet, so what this asserts is
// The thirteen repositories have no maps yet, so what this asserts is
// that the release direction works against the real ledger and not
// only against a fixture: a map naming one tier-1 entity is short
// by the rest, and naming a tier-3 entity is a disagreement.
Expand Down
Loading
Loading