Skip to content

Latest commit

 

History

History
263 lines (222 loc) · 17 KB

File metadata and controls

263 lines (222 loc) · 17 KB

CI and releases

Workflow YAML under .github/workflows/ is the source of truth. This page explains the boundaries; it does not duplicate every job or pinned version.

Pull-request gates

ci.yml always classifies the diff. Only recognized documentation files may take the documentation-only path; a text fixture under a crate is source code.

Branch protection currently requires these reporting contexts:

  • Classify Changes
  • Check AGENTS.md Links
  • Check Workflow Action Pins
  • Graph Vocabulary Guard
  • Test omnigraph-server --features aws
  • Format (rustfmt)
  • Lint (clippy)
  • GQ Logic Tests
  • Fix Regression Gate

GQ Logic Tests (gq-logic-tests.yml) owns the complete .gqt corpus as a required context aggregating three qualification jobs. GQT (ordinary) checks unit tests and unavailable-DST refusal from the workspace root. GQT (dst) runs the whole package, while GQT (dst-clippy) checks all package targets with Clippy. Both run from crates/omnigraph-gqt, whose Cargo configuration enables the seeded Tokio runtime. Each job has its own 45-minute budget and cache key. Matrix fail-fast cancels the remaining jobs when one fails; Cargo retains its default fail-fast between test targets. The required context fails if classification or any qualification fails, is cancelled, or is skipped. A successful run still requires all three jobs to pass; fail-fast never turns incomplete qualification into success. Test jobs upload invocation reports, and all three jobs upload available Cargo build timings separately, including on failure. Every corpus case is enrolled, including cases whose required graph behavior currently fails. Test Workspace excludes this separately tested package; it does not silently skip DST cases. GQ Logic Tests takes the documentation-only skip the way the AWS job does and reports success without building; its workflow carries a verbatim copy of the Classify Changes job under the name Classify Changes (GQ Logic Tests), and scripts/check-classify-copy.py holds that copy identical to ci.yml. Fix Regression Gate (fix-regression-gate.yml) holds every issue the PR body closes by keyword (Closes #N, Closes ModernRelay/omnigraph#N, or the issue URL) to a regression in the diff: a top-level .gqt case or a #[test]-attributed issue_N function, added or strengthened, in a top-level test target (tests/<name>.rs) or src/ module under crates/* or tools/* (an owner test not yet named for the issue is renamed to carry issue_N when extended). A PR whose diff changes no path under crates/ or tools/ (Markdown files there aside) and neither root Cargo.toml nor Cargo.lock passes unexamined, with a notice annotation saying so: a fix in a workflow, a script, a document, or a deployment file has no logic or Rust test that could witness it. Owners the gate does not recognize inside those paths (helper and fixture modules, a script under a crate, a rustdoc-only change) go through the no-repro label, which a maintainer applies to waive the check per PR; scripts/check-fix-regression.py is the check. A failure names the code paths that made the gate look, the ways through, any near miss in the diff (a case whose header says # issue: N under another name or a subdirectory, a test named with the bare number, moved, under a leading _, or in a helper module, an issue-named function with no test attribute), and a case skeleton, as a log line and as a GitHub error annotation. It is a policy check, so it runs on pull_request_target: the workflow and the script come from main, and the pull request head is fetched only as data for the diff range, never checked out or executed. It runs on body edits and label changes as well as pushes, builds nothing, and takes no documentation-only skip.

The Check AGENTS.md Links context also runs scripts/check-docs.py, which validates local documentation links, user/developer audience boundaries, RFC location and metadata, registry agreement, and the absence of committed merge-conflict markers in Markdown. Before the documentation checks run, the same context also rejects any pull request whose own diff adds a conflict-marker line in any file type, annotating each offending file and line; markers already on the base branch never fail an unrelated pull request. There is no exemption; a document that must quote a conflict block indents the markers one space. After the documentation checks, the same context runs typos (crate-ci/typos, pinned by commit) over every tracked text file, hidden paths such as .github/ included; the tool itself skips Cargo.toml manifests, lock files and binaries. It matches each word against a list of known misspellings, not a dictionary: an unknown word never fires, and an identifier fires only when one of the words it splits into is on the list (a CamelCase fragment or a short abbreviation can be one). A flagged token that is correct where it occurs gets one commented line in .typos.toml: under [default.extend-words] when it appears in prose and code alike, under [type.rust.extend-words] (or extend-identifiers for one exact identifier) when it exists only in Rust sources, so the same misspelling in Markdown still fires; a hyphenated prefix goes in extend-ignore-re; a generated text file gets an extend-exclude glob. Every exemption lives in that one file: the job refuses a sibling typos.toml or _typos.toml, and CI ignores a config file in a subdirectory (a local run inside that subdirectory would not).

Graph Vocabulary Guard remains a required reporting context, but its substrate-sized audit steps are currently disabled everywhere (decision of 2026-08-28; the job-level VOCABULARY_AUDIT_ENABLED variable in ci.yml is the single switch). The job still runs its unit tests and reports success so the exact-SHA release gates stay wired. When re-enabled it checks OpenAPI, Rust presentation strings, and public Rust against the reviewed terminology inventory after merge, on tags, and by manual dispatch. User documentation is intentionally outside this exact-occurrence audit and is owned by scripts/check-docs.py. The AWS job reports a successful skip for a documentation-only change; formatting and Clippy are also skipped by the classifier without leaving required contexts pending.

Automatic edge and versioned publication are jobs in the same CI run and cannot start until that run's vocabulary audit succeeds. Each publishing workflow then re-verifies the authorizing CI run, resolves its source once to an immutable commit, and builds only that commit. Version tags are checked again immediately before publication; a stale main audit cannot move the rolling edge tag backward. A manual backfill must already have a successful non-PR vocabulary audit for the exact commit. The current manual workflows therefore fail closed for historical pre-guard tags rather than offering a force bypass.

GitHub evaluates a tag-push workflow from the commit selected by that tag. A new v* tag must not be created against a commit that predates these gates, because no later workflow edit can retroactively replace that commit's old publisher definitions. Enforcing that administrative boundary against tag creators requires repository tag policy in addition to the checked-in workflow gate.

Formatting and Clippy use the repository's pinned toolchain. Lints remain warnings in the workspace; CI applies -D warnings. Clippy runs both the default and failpoint-superset graphs.

Repository metadata gates also check:

  • immutable commit SHAs for external Actions and reusable workflows;
  • agreement between container and package binary sets;
  • the dependency direction around omnigraph-azure-admission.

Container entrypoint and Azure deployment-validation jobs test argument composition, non-destructive Bicep validation, bootstrap readiness/admission modes, and non-root image ownership.

Full correctness graphs

The workspace suite (Test Workspace) runs on every non-documentation pull request, on every push to main, on release tags, and by manual dispatch. GQT has its own configured owner above. The main, tag, and dispatch form (a pull request drops --no-fail-fast):

cargo test --workspace --exclude omnigraph-gqt --locked --no-fail-fast \
  --features omnigraph-engine/failpoints,omnigraph-cluster/failpoints

On a pull request it is a reporting context, not a required one (branch-protection.md), and it fails fast: wait for it to report, and read a red result, before merging. On main, tags, and dispatch it is the post-merge detection channel and keeps --no-fail-fast, so every independent failure stays attributable; a red run there is stop-the-line. The job compiles in one step (cargo test --no-run) and runs in the next, so compile and run wall clock read apart in the log.

The main run also seeds the dependency cache that pull requests restore. Every Swatinem/rust-cache step in ci.yml, gq-logic-tests.yml, and dst.yml saves only from main (save-if): a save from any other ref, a pull-request branch or a tag, is restorable by no pull request and only evicts shared entries under the repository cache cap. The pull-request-path jobs also save when red (cache-on-failure): dependency artifacts are valid whatever the test verdict, and a red seed run would otherwise leave every pull request cold until main is green again.

Every Rust job in those three workflows installs the rust-toolchain.toml pin with a bare rustup toolchain install; the rustc version is part of every cache key, so the pin is what keeps caches warm across Rust releases. The release and publish workflows still build on the floating stable action and save their caches from the tag ref; they are outside this rule.

The remaining jobs own contracts that need special infrastructure. They run after merge, on tags, and by manual dispatch; three of them, the format fence, the RustFS S3 integration, and the AWS feature build, also run on pull requests:

  • Graph vocabulary audit checks OpenAPI, Rust presentation strings, and public Rust against the reviewed terminology inventory (audit steps currently disabled; see above).
  • V5 ↔ V6 format fence builds the immutable final-v5 CLI and proves mutual refusal plus the documented export/init/load rebuild. It also runs on every non-documentation pull request, as a reporting context: the rebuild check compares the rebuilt export against the predecessor's, so a loss or a spelling change in what it compares reports on the pull request; wait for it as for Test Workspace. A red fence on a pull request that touched neither the export, the loader, nor the format is inherited from main: compare with the latest main run before reading it as the pull request's.
  • RustFS S3 integration runs configured engine, server, cluster, CLI, and recovery owners. A configured test that skips is a failure. It also runs on every non-documentation pull request, as a reporting context: the configured S3 owners run nowhere else, so a contract change that updates only the local-FS twin of an object-store test reports on the pull request instead of first appearing on main; wait for both shards as for Test Workspace. A red shard on a pull request that touched no object-store code, or one that names no test (the 60-minute ceiling, the image pull, RustFS readiness), is inherited from main or from infrastructure: compare with the latest main run before reading it as the pull request's. To reproduce locally, the job's env block and its Start RustFS and Create RustFS test bucket steps in ci.yml are the complete recipe.
  • Azurite Azure integration runs only after merge, on tags, or by manual dispatch: its 90-minute ceiling would outrun Test Workspace on a pull request. It exercises configured storage, admission-lease, recovery, cluster, server, and CLI owners against a digest-pinned Azurite image, then verifies that control objects, Lance data, and the admission object use the declared container.
  • AWS feature builds and tests omnigraph-server with --features aws; it also runs on every pull request, as a required context.

Azure remains a qualification preview. Emulator coverage and the completed managed-identity smoke proof do not replace the pending adversarial live-Azure matrix, and every mutation-capable Azure server must retain the admission-wrapper boundary.

CI checks OpenAPI drift but never rewrites openapi.json. Regenerate an intentional API change locally as described in testing.md.

DST tiers

Two workflows own the simulator's pinned tests and generated fleets; both set RUSTFLAGS: --cfg tokio_unstable themselves (the omnigraph-dst crate compiles empty without it, so the default jobs are unaffected):

  • dst.yml (per PR and on main pushes): the pinned deterministic suite — every failure line carries the universe seed, so a red run is reproducible locally from the log alone. The job also lints the shipped engine shape (-p, no dst feature), which workspace feature unification hides from the default Clippy job. Whether the suite blocks a merge is the branch-protection required-contexts list.
  • dst-nightly.yml (cron 03:00 UTC + manual dispatch): matrix-sharded deterministic and concurrent fleets over date-derived, mutually disjoint seed intervals. Failures are logs with seed rows, not required contexts; the concurrent fleet's wild mode makes no replay claim.

gq-logic-tests.yml separately owns authored GQT execution through DST. Its configured step runs from crates/omnigraph-gqt to load tokio_unstable. An unavailable-runtime refusal test does not replace executing the DST cases.

Local pre-push checks

For Rust changes:

cargo fmt --all --check
cargo clippy --workspace --all-targets --locked -- -D warnings -W clippy::dbg_macro
cargo clippy --workspace --all-targets --locked \
  --features omnigraph-engine/failpoints,omnigraph-cluster/failpoints \
  -- -D warnings -W clippy::dbg_macro
cargo test --workspace --exclude omnigraph-gqt --locked \
  --features omnigraph-engine/failpoints,omnigraph-cluster/failpoints
cargo test -p omnigraph-gqt --locked --lib --test runner_dispatch

From crates/omnigraph-gqt, also run the complete configured package:

cargo test -p omnigraph-gqt --locked
cargo clippy -p omnigraph-gqt --all-targets --locked -- -D warnings -W clippy::dbg_macro

For repository metadata and workflow changes:

bash scripts/check-agents-md.sh
python3 scripts/check-docs.py
python3 scripts/check-workflow-action-pins.py
python3 scripts/check-release-vocabulary-gates.py
python3 scripts/check-container-binary-contract.py
python3 scripts/check-azure-admission-boundary.py
typos                       # from the repository root; a subdirectory run scans only that subtree
actionlint .github/workflows/*.yml
shellcheck scripts/*.sh

typos (cargo install typos-cli --locked --version 1.50.1, the version ci.yml pins; the misspelling list grows per release, so a newer local binary can flag words CI accepts), actionlint and shellcheck are developer tools, not workspace dependencies. Run the applicable subset when a change does not touch their surface.

Release workflows

Workflow Trigger and output
release-edge.yml Called by a non-documentation main CI run after its vocabulary audit, or manually for an already-audited current main; updates the rolling edge release and platform archives.
release.yml Called by audited v* tag CI or manually for an already-audited tag; builds platform archives, publishes the GitHub release, updates Homebrew when credentials are available, and smoke-tests the Windows installer.
publish-crates.yml Called by audited v* tag CI or manually for an already-audited tag; publication remains paused until the registry-ownership policy changes.
publish-image.yml Called by audited v* tag CI or manually for an already-audited tag; builds the bookworm-compatible public server image for GHCR and, when configured, Docker Hub. Manual backfills do not move latest.
package.yml / omnigraph-package.yml Manual AWS CodeBuild packaging for default and AWS-feature artifacts, with checksums, digests, and attestations.
refresh-docs-site.yml Documentation changes on main or manual dispatch; requests a docs-site redeploy.

Release archives and containers include the CLI, server, and Azure admission wrapper where their packaging contract requires all three. Keep the reusable package workflow, Dockerfile, and binary-contract check aligned.

Changing CI

  1. Preserve a reporting path for every branch-protection context on every pull request.
  2. Keep external Actions and reusable workflows pinned to full commit SHAs.
  3. Update the documentation classifier when adding a new documentation format; never classify by extension outside the approved docs paths.
  4. Keep configured object-store jobs fail-closed on accidental skips.
  5. Keep every automatic artifact publisher transitively behind a successful exact-SHA vocabulary audit; a skipped pull-request context never authorizes publication.
  6. Update branch-protection.md only when the declared required contexts or policy actually change.