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 .agents/skills/testing-rdf-roundtrip/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ directory alone matches nothing and `sysml` then complains about a missing exten

## The corpus round-trip ratchet (run it before and after any writer/encoder change)

`TestCorpusRoundTrip` (`tests/corpus/roundtrip_test.go`) runs the three-hop trip
`TestExamplesSweep` (`tests/corpus/examples_sweep_test.go`, verdicts in `roundtrip_test.go`) runs the three-hop trip
over **every** `.sysml`/`.kerml` under `examples/` — the 32 committed models, the 100-file
training corpus and the three pilot corpora (213 files) — and pins one verdict per file in
`tests/corpus/testdata/corpus_roundtrip_expected.txt`. It runs in about two seconds.
Expand All @@ -296,7 +296,7 @@ Record: `docs/project/rdf-corpus-roundtrip.md`.
```bash
./scripts/download-training-examples.sh && ./scripts/download-pilot-corpora.sh # once
OPENSYSML_REQUIRE_TRAINING_CORPUS=1 OPENSYSML_REQUIRE_PILOT_CORPORA=1 \
go test -count=1 -v ./tests/corpus -run TestCorpusRoundTrip
go test -count=1 -v ./tests/corpus -run TestExamplesSweep
```

Without the require variables an absent corpus **skips** the gate with a `GATE NOT RUN` banner on
Expand All @@ -321,7 +321,7 @@ regression does, so every movement is adjudicated. When your change moves files:
record.
3. Regenerate and commit the expectation file in the same PR:
```bash
go test ./tests/corpus -run TestCorpusRoundTrip -update-corpus-roundtrip
go test ./tests/corpus -run TestExamplesSweep -update-corpus-roundtrip
git diff --stat tests/corpus/testdata/corpus_roundtrip_expected.txt
```
Run the update twice and confirm the second run leaves the file unchanged; the run is
Expand Down
62 changes: 21 additions & 41 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,7 @@ jobs:
go-race-test:
executor: go-executor
resource_class: large
parallelism: 19
parallelism: 17
steps:
- checkout
- rehearsal-checkout-tag
Expand All @@ -721,14 +721,14 @@ jobs:
- install-fmpy

# internal/exec/runtime (31-57 minutes whole, near 8.5 GB under -race), tests/export and tests/corpus
# (about 40 minutes whole) are split by test name as make test-shard does: four and three shards.
# (about 40 minutes whole) are split by test name as make test-shard does: four and two shards.
- run:
name: Run Go race tests
command: |
set -o pipefail
# One entry per node; a quoted entry runs its shards in turn (tests/hygiene keeps
# the entries the shard list of scripts/race-shard.sh).
shards=(runtime runtime-corpus model smt "corpus codegen" corpus-roundtrip corpus-apijson export export-library export-examples export-corpus export-settled graph translate grpc tools rest "migrate runtime-exploration" cli)
shards=(runtime runtime-corpus model smt "corpus codegen" corpus-sweep export export-library export-examples export-corpus graph translate grpc tools rest "migrate runtime-exploration" cli)
if [ "$CIRCLE_NODE_TOTAL" != "${#shards[@]}" ]; then
echo "error: parallelism is $CIRCLE_NODE_TOTAL, but the shard array has ${#shards[@]} nodes" >&2
exit 1
Expand All @@ -743,31 +743,26 @@ jobs:
exploration='^TestExploreWithIsExploreOverTheConformanceCorpus$'
corpus='^Test(ExploreWithIsExploreOverTheConformanceCorpus|CheckAgreesWithExploreOverTheConformanceCorpus|CheckWitnessesReplayOverTheConformanceCorpus|ExecutionConformance|ExecutionConformanceUnderPolicies)$'
exportcorpus='^TestAPIJSONWritersNeverEmitNameReferences$'
exportsettled='^TestSettledCollectionsAreWhatReconcilingWouldFind$'
exportlibrary='^TestLibraryFilesComeBackFromTheGraphAlone$'
exportexamples='^TestExamplesCorpusInvariants$'
# The Makefile's RACE_CORPUS_ROUNDTRIP and RACE_CORPUS_APIJSON; tests/hygiene keeps them the same.
corpusroundtrip='^TestCorpusRoundTrip$'
corpusapijson='^TestCorpusAPIJSONRoundTrip$'
# The Makefile's RACE_CORPUS_SWEEP; tests/hygiene keeps the two the same.
corpussweep='^TestExamplesSweep$'
case "$shard" in
# Its own shard and process: alone it nears 5 GB, the five suites together 9 GB under -race,
# over this class's 8 GB. The Makefile's RACE_RUNTIME_EXPLORATION; tests/hygiene keeps the two the same.
runtime-exploration) go test -json -race -pgo=off -timeout 30m -run "$exploration" $pkgs | stream ;;
runtime-corpus) go test -json -race -pgo=off -timeout 30m -run "$corpus" -skip "$exploration" $pkgs | stream ;;
runtime) go test -json -race -pgo=off -timeout 30m -skip "$corpus" $pkgs | stream ;;
# The Makefile's RACE_EXPORT_CORPUS, RACE_EXPORT_SETTLED, RACE_EXPORT_LIBRARY and RACE_EXPORT_EXAMPLES; tests/hygiene
# keeps them the same. tests/export whole passed 55 minutes under -race; its remainder ran 37, so five shards.
# The Makefile's RACE_EXPORT_CORPUS, RACE_EXPORT_LIBRARY and RACE_EXPORT_EXAMPLES; tests/hygiene
# keeps them the same. tests/export whole passed 55 minutes under -race; its remainder ran 37, so four shards.
export-corpus) go test -json -race -pgo=off -timeout 55m -run "$exportcorpus" $pkgs | stream ;;
# Four settled models at once peak at 8.2-8.4 GB under -race, this class's 8 GB (killed on
# develop at #2014); two at once peak at 6.5 GB for a tenth more wall time.
export-settled) go test -json -race -pgo=off -timeout 55m -parallel 2 -run "$exportsettled" $pkgs | stream ;;
export-library) go test -json -race -pgo=off -timeout 55m -run "$exportlibrary" $pkgs | stream ;;
export-examples) go test -json -race -pgo=off -timeout 55m -run "$exportexamples" $pkgs | stream ;;
export) go test -json -race -pgo=off -timeout 55m -skip "$exportcorpus|$exportsettled|$exportlibrary|$exportexamples" $pkgs | stream ;;
# tests/corpus's two round trips over every example ran about 20 minutes each under -race.
corpus-roundtrip) go test -json -race -pgo=off -timeout 55m -run "$corpusroundtrip" $pkgs | stream ;;
corpus-apijson) go test -json -race -pgo=off -timeout 55m -run "$corpusapijson" $pkgs | stream ;;
corpus) go test -json -race -pgo=off -timeout 30m -skip "$corpusroundtrip|$corpusapijson" $pkgs | stream ;;
export) go test -json -race -pgo=off -timeout 55m -skip "$exportcorpus|$exportlibrary|$exportexamples" $pkgs | stream ;;
# tests/corpus's sweep has -parallel models in hand at once, a whole corpus directory as one model
# among them: four peaked at 10.4 GB and three at 10.0 GB under -race on a four-vCPU box (this class ran ~0.8x of that).
corpus-sweep) go test -json -race -pgo=off -timeout 55m -parallel 3 -run "$corpussweep" $pkgs | stream ;;
corpus) go test -json -race -pgo=off -timeout 30m -skip "$corpussweep" $pkgs | stream ;;
tools)
go test -json -race -pgo=off -timeout 30m $pkgs | stream
go test -C tools -json -race -pgo=off -timeout 30m ./... | stream
Expand Down Expand Up @@ -811,7 +806,7 @@ jobs:
executor: go-executor
resource_class: large
# The race test's shards but the runtime's corpus ones: without -race the runtime runs whole in about 19 minutes.
parallelism: 19
parallelism: 17
steps:
- checkout
- rehearsal-checkout-tag
Expand All @@ -834,7 +829,7 @@ jobs:
command: |
# tests/export and tests/corpus whole overran 30 minutes, so make coverage-shard splits them by test name.
# cmd/sysml has its own node: its exploration budgets took 23-30 minutes on the rest node.
shards=(runtime model smt corpus corpus-roundtrip corpus-apijson export export-library export-examples export-corpus export-settled graph codegen translate grpc tools rest migrate cli)
shards=(runtime model smt corpus corpus-sweep export export-library export-examples export-corpus graph codegen translate grpc tools rest migrate cli)
if [ "$CIRCLE_NODE_TOTAL" != "${#shards[@]}" ]; then
echo "error: parallelism is $CIRCLE_NODE_TOTAL, but the Makefile's COVERAGE_SHARDS has ${#shards[@]} shards" >&2
exit 1
Expand Down Expand Up @@ -1022,32 +1017,17 @@ jobs:
environment:
OPENSYSML_REQUIRE_PILOT_LIBRARY_XMI: "1"

# The RDF round-trip ratchet over every example alone, so its per-verdict
# counts are legible in the log and a skip cannot hide behind a green suite.
# The RDF and api-json round-trip ratchets over every example alone, so their
# per-verdict counts are legible in the log and a skip cannot hide behind a green suite.
- run:
name: Run RDF corpus round-trip gate
name: Run corpus round-trip gates
command: |
set -o pipefail
go test -count=1 -v ./tests/corpus -run 'TestCorpusRoundTrip' | tee corpus-roundtrip-gate.log
grep -E 'corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
go test -count=1 -v ./tests/corpus -run 'TestExamplesSweep' | tee corpus-roundtrip-gate.log
grep -E ': corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
grep -E 'api-json corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
if grep -qE '^\s*--- SKIP' corpus-roundtrip-gate.log; then
echo "error: the RDF corpus round-trip gate skipped" >&2
exit 1
fi
environment:
OPENSYSML_REQUIRE_TRAINING_CORPUS: "1"
OPENSYSML_REQUIRE_PILOT_CORPORA: "1"
OPENSYSML_REQUIRE_SPEC_EXAMPLES: "1"

# The same ratchet over the API's JSON element form, beside the RDF one.
- run:
name: Run api-json corpus round-trip gate
command: |
set -o pipefail
go test -count=1 -v ./tests/corpus -run 'TestCorpusAPIJSONRoundTrip' | tee api-json-roundtrip-gate.log
grep -E 'api-json corpus round trip: [0-9]+ files:' api-json-roundtrip-gate.log
if grep -qE '^\s*--- SKIP' api-json-roundtrip-gate.log; then
echo "error: the api-json corpus round-trip gate skipped" >&2
echo "error: the corpus round-trip gates skipped" >&2
exit 1
fi
environment:
Expand Down
30 changes: 9 additions & 21 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ jobs:
TIER: ${{ steps.areas.outputs.tier }}
run: |
if [ "$TIER" != quick ]; then
echo 'go_shards=["runtime","runtime-corpus","runtime-exploration","model","smt","corpus","corpus-roundtrip","corpus-apijson","export","export-library","export-examples","export-corpus","export-settled","graph","codegen","translate","grpc","rest","migrate","cli"]'
echo 'go_shards=["runtime","runtime-corpus","runtime-exploration","model","smt","corpus","corpus-sweep","export","export-library","export-examples","export-corpus","graph","codegen","translate","grpc","rest","migrate","cli"]'
else
echo 'go_shards=["runtime runtime-corpus runtime-exploration model","codegen migrate","cli translate","graph","smt","corpus corpus-roundtrip corpus-apijson","export export-examples","export-library export-settled","export-corpus","rest grpc"]'
echo 'go_shards=["runtime runtime-corpus runtime-exploration model","codegen migrate","cli translate","graph","smt","corpus corpus-sweep","export export-examples","export-library export-corpus","rest grpc"]'
fi | tee -a "$GITHUB_OUTPUT"

# The vendored copy is checked in this job, not static-and-integrity: the
Expand Down Expand Up @@ -466,31 +466,19 @@ jobs:
if: needs.changes.outputs.tier != 'quick'
run: go run -C tools ./cmd/fuml-referee -check

# The RDF round-trip ratchet over every example on its own, so its per-verdict counts are legible and a
# skip must not pass; it is an examples/ sweep, so the queue tier takes the construct-cover subset here too.
- name: Run RDF corpus round-trip gate
# The RDF and api-json round-trip ratchets over every example on their own, so their per-verdict counts are
# legible and a skip must not pass; they are an examples/ sweep, so the queue tier takes the construct-cover subset here too.
- name: Run corpus round-trip gates
if: needs.changes.outputs.tier != 'quick'
env:
OPENSYSML_CORPUS_SUBSET: ${{ needs.changes.outputs.tier == 'queue' && 'construct-cover' || '' }}
run: |
set -o pipefail
go test -count=1 -v ./tests/corpus -run 'TestCorpusRoundTrip' | tee corpus-roundtrip-gate.log
grep -E 'corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
go test -count=1 -v ./tests/corpus -run 'TestExamplesSweep' | tee corpus-roundtrip-gate.log
grep -E ': corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
grep -E 'api-json corpus round trip: [0-9]+ files:' corpus-roundtrip-gate.log
if grep -qE '^\s*--- SKIP' corpus-roundtrip-gate.log; then
echo "error: the RDF corpus round-trip gate skipped" >&2
exit 1
fi

- name: Run api-json corpus round-trip gate
if: needs.changes.outputs.tier != 'quick'
env:
OPENSYSML_CORPUS_SUBSET: ${{ needs.changes.outputs.tier == 'queue' && 'construct-cover' || '' }}
run: |
set -o pipefail
go test -count=1 -v ./tests/corpus -run 'TestCorpusAPIJSONRoundTrip' | tee api-json-roundtrip-gate.log
grep -E 'api-json corpus round trip: [0-9]+ files:' api-json-roundtrip-gate.log
if grep -qE '^\s*--- SKIP' api-json-roundtrip-gate.log; then
echo "error: the api-json corpus round-trip gate skipped" >&2
echo "error: the corpus round-trip gates skipped" >&2
exit 1
fi

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rebaseline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ jobs:

- name: Re-record the per-file ratchets
run: |
go test -count=1 ./tests/corpus -run 'TestPilotCorporaDiagnostics|TestSpecExamplesDiagnostics|TestPSSMSuiteMigration|TestCorpusRoundTrip|TestCorpusAPIJSONRoundTrip' \
go test -count=1 ./tests/corpus -run 'TestPilotCorporaDiagnostics|TestSpecExamplesDiagnostics|TestPSSMSuiteMigration|TestExamplesSweep' \
-update-pilot-corpora -update-spec-examples -update-pssm-migration -update-corpus-roundtrip -update-api-json-roundtrip
go test -count=1 ./internal/translate/export -run TestSymbolStructureMatchesGraphStructure -update-structure-differential
go test -count=1 ./internal/exec/runtime -run TestLibraryAndPrefixSweep -update-library-prefix-sweep
Expand Down
10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ make build # build bin/sysml and bin/sysml-lsp (with version ldflags)
make build-sysml # REPL binary only
make build-lsp # LSP binary only
make test # full suite: go test -race -coverprofile ... ./...
make test-shard SHARD=runtime # one CI shard of the race suite (runtime|runtime-corpus|runtime-exploration|model|smt|corpus|corpus-roundtrip|corpus-apijson|export|export-library|export-examples|export-corpus|export-settled|graph|codegen|translate|grpc|tools|rest|migrate|cli)
make test-shard SHARD=runtime # one CI shard of the race suite (runtime|runtime-corpus|runtime-exploration|model|smt|corpus|corpus-sweep|export|export-library|export-examples|export-corpus|graph|codegen|translate|grpc|tools|rest|migrate|cli)
make test-quick SHARDS="rest grpc" # the same shards without -race, in turn: what a pull-request push runs
make test-queue SHARDS="rest export-corpus" # the merge queue's tier: -race, but the examples/ sweeps (scripts/race-shard.sh --sweeps) race-free over the construct-cover subset
make test-short # faster, no race detector
Expand Down Expand Up @@ -102,10 +102,10 @@ answers under `internal/ir/docplan/markup/testdata/`, and the `Installed` test t
against the pinned converter — re-record them (`asciidoctor-json.js < x.adoc > x.json`) when either moves.

The RDF mapping has a per-file ratchet of its own over every model under `examples/`, the
downloaded corpora included: `TestCorpusRoundTrip` in `tests/corpus` converts each file
notation → Turtle → notation → Turtle and pins the verdict. Run it with both require variables
set after any change to `internal/translate/export`, adjudicate every movement, then regenerate with
`-update-corpus-roundtrip`. See `docs/project/rdf-corpus-roundtrip.md`.
downloaded corpora included: `TestExamplesSweep` in `tests/corpus` loads each file once, converts it
notation → Turtle → notation → Turtle (and the same through `api-json`) and pins the verdicts. Run it with
the require variables set after any change to `internal/translate/export`, adjudicate every movement,
then regenerate with `-update-corpus-roundtrip` (`-update-api-json-roundtrip`). See `docs/project/rdf-corpus-roundtrip.md`.

---

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,15 +301,15 @@ syntactic construct the whole corpus does; unset, they walk the whole corpus.

**The quick tier** is what every push to a pull request gets, draft or ready, in about half the
runner time of the full tier and a third of its wall time: the binaries, the same Go suite without
`-race` in ten groups of the race shards (`make test-quick`), the download-free static checks
`-race` in nine groups of the race shards (`make test-quick`), the download-free static checks
(gofmt, vet, the production build, grpc imports, proto lint and breaking), the WebAssembly, Xpect
and conformance gates, and only the clients, editors and docs whose own paths changed. The lint,
the corpus and solver gates, the PDF toolchain and the fan-out from a service change to every
client wait for the full tier. Only a push touching a path no area claims escalates itself to
the full tier (`scripts/ci-changed-areas.sh`, and its test pins it).

**The queue tier** runs on the merge queue's commit (below). It runs every job and gate of the
full tier — gofmt, `go vet`, `make lint`, every shard of the test suite (twenty, `make
full tier — gofmt, `go vet`, `make lint`, every shard of the test suite (eighteen, `make
test-queue`), the binaries, the client suites, the conformance suite over each transport, the
protobuf lint and wire-compatibility checks, the documentation hygiene checks (`make docs-check`,
`make man-check` and the census check), the site build, the PDF toolchain, and in each client's
Expand Down
Loading
Loading