Skip to content
Merged
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
114 changes: 114 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: ci

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# Answers one question only: does this repository materialise jobs at all?
# A run object can exist with zero jobs — that is how dotfiles' CI sat "queued"
# for a month unnoticed — so the cheapest possible job runs first and proves it.
materialises:
runs-on: ubuntu-latest
steps:
- run: echo "jobs materialise in this repository"

crate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo build --locked --manifest-path crates/intent/Cargo.toml
- run: cargo test --locked --manifest-path crates/intent/Cargo.toml

# Port of dotfiles' `axe-vrs-context-strict`.
corpus-strict:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# `crates/intent` is a standalone package with no workspace root, so cargo
# writes to `crates/intent/target/` and the steps below would not find the
# binary at `./target/`. `--target-dir` pins the output next to the checkout
# root regardless of whether a workspace root ever appears above the crate.
- run: cargo build --locked --release --manifest-path crates/intent/Cargo.toml --target-dir target

- name: corpus is present
# `intent check` exits 0 on an empty directory and on a directory holding no
# VRS artifacts, so "the check passed" cannot by itself distinguish a healthy
# corpus from a missing one. Fail on absence explicitly, before checking.
run: |
set -euo pipefail
test -d intent || { echo "::error::corpus directory 'intent/' does not exist"; exit 1; }

- name: strict check reports no diagnostics
run: |
set -euo pipefail
./target/release/intent check intent --profile strict --json > report.json || {
cat report.json >&2; exit 1;
}
jq -e '
.schema_version == "axe.vrs.check.v1"
and .profile == "strict"
and (.diagnostics | length) == 0
' report.json > /dev/null

- name: check actually read the corpus
# The assertion above is satisfied by a run against a path containing nothing,
# so on its own it cannot tell "corpus is clean" from "corpus is not there".
# The graph is what discriminates: it is empty for both an empty directory and
# a wrong path, and non-empty only when artifacts were genuinely read.
run: |
set -euo pipefail
./target/release/intent graph intent --json > graph.json
nodes="$(jq '.nodes | length' graph.json)"
echo "graph nodes: $nodes"
jq -e '(.nodes | length) > 0' graph.json > /dev/null \
|| { echo "::error::strict check examined 0 artifacts — wrong path or empty corpus"; exit 1; }

# Port of dotfiles' `vrs-semantic-review-fixtures`.
semantic-review-fixtures:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pipx install check-jsonschema

- name: fixtures and the enforcement schema are present
run: |
set -euo pipefail
fixtures="intent/15-evaluation/semantic-review"
schema="intent/16-enforcement/review-result.schema.json"
test -d "$fixtures" || { echo "::error::missing fixtures root: $fixtures"; exit 1; }
test -f "$fixtures/fixture-format.md" || { echo "::error::missing fixture-format.md"; exit 1; }
test -f "$schema" || { echo "::error::missing review-result schema: $schema"; exit 1; }

- name: every fixture validates against the enforcement schema
# Fully offline: every schema is a local file, so none is ever fetched.
run: |
set -euo pipefail
fixtures="intent/15-evaluation/semantic-review"
schema="intent/16-enforcement/review-result.schema.json"
found=0
for fixture in "$fixtures"/*/; do
[ -d "$fixture" ] || continue
found=$((found + 1))
name="$(basename "$fixture")"
test -f "$fixture/expected-review.json" \
|| { echo "::error::$name: missing expected-review.json"; exit 1; }
check-jsonschema --no-cache --schemafile "$schema" "$fixture/expected-review.json" \
|| { echo "::error::$name: expected-review.json does not satisfy the enforcement schema"; exit 1; }
# A fixture expecting no finding cannot protect any review behavior.
jq -e '.findings | length > 0' "$fixture/expected-review.json" > /dev/null \
|| { echo "::error::$name: expected-review.json must contain at least one expected finding"; exit 1; }
done
# Without this the loop is green over zero fixtures, which is the same
# silent-pass this whole file exists to prevent.
[ "$found" -gt 0 ] || { echo "::error::no semantic-review fixtures found under $fixtures"; exit 1; }
echo "fixtures validated: $found"
33 changes: 33 additions & 0 deletions .github/workflows/nix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: nix

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

concurrency:
group: nix-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
# Deliberately its OWN workflow rather than a job inside `ci.yml`. The corpus
# gates there are fast and must stay separately named and independently
# readable; folding a multi-minute Nix build in beside them would couple the
# two, and collapsing them behind `nix flake check` would leave a run showing
# a single check named `check` instead of which corpus gate concluded and how.
# This lane is additive: it proves the CLI packages and that the packaged
# binary works, and it re-gates nothing.
check:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/determinate-nix-action@v3
# Builds the package — which runs the crate's test suite via doCheck — and
# evaluates every `checks.*`: fmt, clippy, the `--help` smoke test, and the
# proof that the packaged binary reads a real corpus.
- run: nix flake check --print-build-logs
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Cargo build output. Unanchored, so it matches both a repo-root `target/` and
# `crates/intent/target/` — which is where cargo writes unless `--target-dir` says
# otherwise, since the crate is a standalone package with no workspace root.
target/

# Artifacts the CI steps write into the checkout root while running.
/report.json
/graph.json

# `nix build` output symlinks.
/result
/result-*
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ checker rather than the methodology.

## Two things worth knowing early

**The conventions travel.** They are plain Markdown with a naming discipline, and
they require no tool to author or read. `livestorejs/livestore` — a different
project, a different domain, no dependency on anything in this repository — uses
the same artifact set and the same numbered-subsystem structure, nested two levels
deep. Nothing in this corpus is coupled to the environment it grew up in; a text
editor is the only requirement.
**The conventions need no toolchain.** They are plain Markdown with a naming
discipline: a directory layout, a set of filenames, and rules about which file
owns which fact. Authoring and reading them takes a text editor and nothing
else. This corpus is its own worked example — the conventions it describes are
the conventions it is written in, so every rule it states can be seen applied
in the files you are already reading.

**The rules are mechanically checkable, and checked.** `16-enforcement` is not
aspirational — it defines concrete rules with stable identifiers, and a real
Expand Down
Loading
Loading