Skip to content

Commit a307b0e

Browse files
Work up VCL-UT: repair CI, reconcile the level ladder, and set direction (#75)
Two parts, as asked: deal with the immediate issues first, then work up where this goes — theory and VeriSimDB application kept separate. ## Part A — immediate issues (all measured, all verified) **Two CI faults, independent:** - `dogfood-gate.yml` was **malformed YAML**. The embedded Python started at column 1 while the `run: |` block scalar was indented 10, so YAML closed the scalar early. The workflow had failed **every run in 0s since at least 2026-07-06** — it never once validated anything — and it broke Dependabot's `github_actions` updater with `dependency_file_not_parseable`. Verified by *executing* the extracted step against valid and invalid manifests, not just by parsing it. (~80 of 266 estate copies carry the identical fault.) - `dependabot.yml` declared `mix`/`npm`/`pip`/`nix` with no manifests present — four of the five weekly failures. Also: this repo has **five** cargo workspace roots and the single `/` entry covered one, so the parser and `vclt-gate` were invisible to Dependabot. **Two crates had silently stopped compiling.** `ast::Statement` gained the consonance field `verb`; `attest` and `recompute-wasm` were never updated (`E0063`). Only their test modules were stale, so the libraries still built and nothing complained — **12 tests had just stopped running**, in the crates carrying the attestation and recompute boundaries. They were covered by **no CI job at all**, which is exactly how they rotted. Now fixed and gated. **Coverage gaps closed:** `e2e.yml` ran 69 of the root workspace's 102 tests — every e2e and fuzz test was skipped. Also removed two `git clone echidna` steps that cloned a whole repo per run for nothing (proven: 102 tests and `e2e.sh` 19/19 pass with no sibling present). **Correction to an earlier finding of mine:** I had recorded "0 unit tests, root `cargo test` is a fake gate". That was **wrong** — an artefact of truncating the log. The root crate is a re-export facade whose whole surface lives in `tests/`; the `tests-102 pass` badge was exact. Noted in the workflow header so the misreading isn't repeated. **Documentation truth pass** — the level ladder disagreed with the code three ways: | | was | now | |---|---|---| | Numbering | 1–10 | **L0–L10** (they're wire tags — requesting 7 got Effect-Tracking, not the Cardinality documented) | | Vocabulary | `FETCH`/`REMOVE` | `SELECT`/`RETRACT` — the documented verbs **are rejected by the parser** | | Count | ten | **eleven** — L10 `EpistemicSafe` appeared in *no document anywhere* | ## Part B/C — the work-up `docs/2026-07-21-workup-consonance-and-verisim.adoc`, two strands kept separate. **Theory.** The strongest argument for the consonance reframe came from the code, not from taste: the eleventh level isn't a query-safety property at all, and it's the one level *not* inherited from TypeLL (a UI panel has no federation, so no warrant question). The paper is titled *"A Decalogue…"* — its own title can't house its own eleventh level. The gap in the world is stated honestly: type-safe query languages are a **crowded, mature** field and a ten-levels paper reads as synthesis. What none of them do is type **warrant** — every one assumes a single source of truth that cannot disagree with itself. **The whitepaper reframe is a proposal, not an executed rewrite.** The 1,909-line `.tex` is untouched. Structure + a full draft abstract are offered for approval first — how a paper argues its claim is yours to settle, and it's the least testable change available here. **Application.** Opens with the uncomfortable fact: **VCL-UT delivers nothing to VeriSimDB at runtime today** — the producer is finished and the consumer was never written (`verisim-api/src/vcl.rs` has zero `vclt-gate` references). Two VeriSimDB defects located precisely, including `VCLTypeChecker.res:60` building the default context with **six** modalities though the type admits eight — Provenance and Spatial silently absent from every default type-check. Those are VeriSimDB changes and are **not** made here. Closes with a falsification section, including one thing that should be **measured before** the wiring work rather than after: subprocess latency on the hot path. ## Verification ``` reuse lint -> compliant, 460/460 23 workflows -> 0 malformed cargo test --workspace --locked -> 102 passed cargo test (parse) -> 36 passed cargo test (attest) -> 9 passed (was: did not compile) cargo test (recompute-wasm) -> 3 passed (was: did not compile) bash tests/e2e.sh -> 19/19, no echidna sibling 150 tests total ``` ## Note The three unpushed `main` commits (sweep2/3/4, Mistral Vibe) are **not** carried here. They break `reuse lint` — a genuinely fail-closed gate — by adding an AGPL licence file to a repo with zero AGPL-declared files, and they inject `@metadatastician` as owner/sponsor into a `hyperpolymath` repo while duplicating correct `.github/` files. Recommend `main` be reset to `origin/main` with a `sweep-quarantine` branch kept for reachability. This branch is based at `origin/main` and is unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 717ceb3 commit a307b0e

20 files changed

Lines changed: 1246 additions & 206 deletions

.github/dependabot.yml

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,34 @@
11
# SPDX-License-Identifier: MPL-2.0
2-
# Dependabot configuration for RSR-compliant repositories
3-
# Covers common ecosystems - remove unused ones for your project
2+
# Dependabot configuration for vcl-ut.
3+
#
4+
# Trimmed from the RSR template on 2026-07-21. Only ecosystems with an actual
5+
# manifest in this repository are declared. Declaring an ecosystem with no
6+
# manifest makes the corresponding Dependabot job fail on EVERY run — this
7+
# repository was failing `hex`, `pip`, `nix` and `npm_and_yarn` weekly for
8+
# exactly that reason (measured: 5 consecutive red runs from 2026-07-13).
9+
#
10+
# vcl-ut is Rust-only. Verified absent at the root: mix.exs, package.json,
11+
# requirements.txt, pyproject.toml, flake.nix.
12+
#
13+
# Cargo note: this repository has FIVE cargo workspace roots, not one. A single
14+
# `directory: "/"` entry covers the root workspace only, so the crates holding
15+
# most of the actual code were invisible to Dependabot. Each self-contained
16+
# workspace root is now declared explicitly:
17+
#
18+
# / root workspace (vcl-ut, fmt, lint, core)
19+
# /src/interface/parse parser + decider + vclt-gate <- the real spine
20+
# /src/interface/attest depends on ../parse (in-repo)
21+
# /src/interface/recompute-wasm depends on ../parse (in-repo)
22+
#
23+
# DELIBERATELY EXCLUDED: /src/interface/echidna-client. It depends on
24+
# ../../interface, which in turn carries an out-of-tree path dependency
25+
# (`echidna-core = { path = "../../../echidna/..." }`). Dependabot cannot
26+
# resolve a path dependency outside the repository, so declaring it would
27+
# reintroduce exactly the always-red job this trim removes.
428

529
version: 2
630
updates:
7-
# GitHub Actions - always include
31+
# GitHub Actions always include.
832
- package-ecosystem: "github-actions"
933
directory: "/"
1034
schedule:
@@ -14,38 +38,33 @@ updates:
1438
patterns:
1539
- "*"
1640

17-
# Rust/Cargo
41+
# Rust/Cargo — one entry per self-contained workspace root.
42+
#
43+
# `open-pull-requests-limit: 0` suppresses routine version-update PRs while
44+
# leaving Dependabot SECURITY PRs flowing. The previous `ignore: "*" patch`
45+
# rule also silenced security PRs under GitHub's current Dependabot
46+
# behaviour. See rsr-template-repo commit 78b050e and
47+
# 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md.
1848
- package-ecosystem: "cargo"
1949
directory: "/"
2050
schedule:
2151
interval: "weekly"
22-
# `open-pull-requests-limit: 0` suppresses routine version-update PRs
23-
# while leaving Dependabot SECURITY PRs flowing. The previous
24-
# `ignore: "*" patch` rule also silenced security PRs under GitHub\'s
25-
# current Dependabot behaviour. See rsr-template-repo commit 78b050e
26-
# and 007-lang/audits/audit-dependabot-automation-gap-2026-04-17.md.
2752
open-pull-requests-limit: 0
2853

29-
# Elixir/Mix
30-
- package-ecosystem: "mix"
31-
directory: "/"
32-
schedule:
33-
interval: "weekly"
34-
35-
# Node.js/npm
36-
- package-ecosystem: "npm"
37-
directory: "/"
54+
- package-ecosystem: "cargo"
55+
directory: "/src/interface/parse"
3856
schedule:
3957
interval: "weekly"
58+
open-pull-requests-limit: 0
4059

41-
# Python/pip
42-
- package-ecosystem: "pip"
43-
directory: "/"
60+
- package-ecosystem: "cargo"
61+
directory: "/src/interface/attest"
4462
schedule:
4563
interval: "weekly"
64+
open-pull-requests-limit: 0
4665

47-
# Nix flakes
48-
- package-ecosystem: "nix"
49-
directory: "/"
66+
- package-ecosystem: "cargo"
67+
directory: "/src/interface/recompute-wasm"
5068
schedule:
5169
interval: "weekly"
70+
open-pull-requests-limit: 0

.github/workflows/dogfood-gate.yml

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -280,26 +280,26 @@ jobs:
280280
281281
# Validate TOML structure using Python 3.11+ tomllib
282282
python3 -c "
283-
import tomllib, sys
284-
with open('eclexiaiser.toml', 'rb') as f:
285-
data = tomllib.load(f)
286-
project = data.get('project', {})
287-
if not project.get('name', '').strip():
288-
print('ERROR: project.name is required', file=sys.stderr)
289-
sys.exit(1)
290-
functions = data.get('functions', [])
291-
if not functions:
292-
print('ERROR: at least one [[functions]] entry is required', file=sys.stderr)
293-
sys.exit(1)
294-
for fn in functions:
295-
if not fn.get('name', '').strip():
296-
print('ERROR: function name cannot be empty', file=sys.stderr)
297-
sys.exit(1)
298-
if not fn.get('source', '').strip():
299-
print(f'ERROR: function {fn[\"name\"]} has no source path', file=sys.stderr)
300-
sys.exit(1)
301-
print(f'Valid: {project[\"name\"]} ({len(functions)} function(s))')
302-
" || {
283+
import tomllib, sys
284+
with open('eclexiaiser.toml', 'rb') as f:
285+
data = tomllib.load(f)
286+
project = data.get('project', {})
287+
if not project.get('name', '').strip():
288+
print('ERROR: project.name is required', file=sys.stderr)
289+
sys.exit(1)
290+
functions = data.get('functions', [])
291+
if not functions:
292+
print('ERROR: at least one [[functions]] entry is required', file=sys.stderr)
293+
sys.exit(1)
294+
for fn in functions:
295+
if not fn.get('name', '').strip():
296+
print('ERROR: function name cannot be empty', file=sys.stderr)
297+
sys.exit(1)
298+
if not fn.get('source', '').strip():
299+
print(f'ERROR: function {fn[\"name\"]} has no source path', file=sys.stderr)
300+
sys.exit(1)
301+
print(f'Valid: {project[\"name\"]} ({len(functions)} function(s))')
302+
" || {
303303
echo "::error file=eclexiaiser.toml::Invalid eclexiaiser.toml — see step output for details"
304304
exit 1
305305
}

.github/workflows/e2e.yml

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
11
# SPDX-License-Identifier: MPL-2.0
2+
#
3+
# e2e.yml — Root-workspace test gate.
4+
#
5+
# The root workspace has four members (vcl-total, vcltotal-fmt, vcltotal-lint,
6+
# vcltotal-core) and its whole test surface lives in `tests/`, because the root
7+
# crate is a re-export facade over fmt + lint. Per-crate UNIT counts are
8+
# therefore all zero, which makes a truncated `cargo test` log look like an
9+
# empty gate; it is not. Measured 2026-07-21: 102 tests.
10+
#
11+
# tests/e2e_test.rs 20
12+
# tests/fuzz_test.rs 13
13+
# tests/integration_test.rs 59
14+
# tests/property_test.rs 10
15+
#
16+
# This job previously ran only property_test + integration_test, so 33 of the
17+
# 102 — every e2e and fuzz test — never ran in CI. It now runs the whole
18+
# workspace.
19+
#
20+
# The former "Provide echidna sibling" steps have been removed. They cloned a
21+
# whole repository on every run for nothing: `src/interface` (the member that
22+
# carries the external `echidna-core` path-dep) is deliberately NOT a root
23+
# workspace member, so neither `cargo test --workspace` nor `tests/e2e.sh`
24+
# ever resolves it. Verified 2026-07-21 by running both with no sibling
25+
# present: 102 tests pass, e2e.sh reports 19/19. echidna-client is gated
26+
# separately in backend-matrix.yml, which does need the sibling.
27+
228
name: E2E, Property and Aspect Tests
329
on:
430
push: { branches: [main] }
@@ -15,27 +41,22 @@ jobs:
1541
- name: Install Rust
1642
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
1743
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
18-
# echidna-core path-dependency (src/interface/Cargo.toml) — provide as sibling.
19-
- name: Provide echidna sibling
20-
run: git clone --depth 1 https://github.com/hyperpolymath/echidna ../echidna
2144
- name: Run E2E validation
2245
run: bash tests/e2e.sh
2346
property:
24-
name: Property and integration tests
47+
name: Root workspace tests
2548
runs-on: ubuntu-latest
2649
timeout-minutes: 15
2750
steps:
2851
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2952
- name: Install Rust
3053
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
3154
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2
32-
# echidna-core path-dependency (src/interface/Cargo.toml) — provide as sibling.
33-
- name: Provide echidna sibling
34-
run: git clone --depth 1 https://github.com/hyperpolymath/echidna ../echidna
35-
- name: Run property tests
36-
run: cargo test --test property_test
37-
- name: Run integration tests
38-
run: cargo test --test integration_test
55+
# Whole workspace, all targets — not a hand-picked subset. Previously
56+
# `--test property_test` + `--test integration_test` only, which silently
57+
# skipped tests/e2e_test.rs and tests/fuzz_test.rs.
58+
- name: Run root workspace tests (expect 102)
59+
run: cargo test --workspace --all-targets --locked
3960
aspect:
4061
name: Aspect tests
4162
runs-on: ubuntu-latest
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# satellite-crates-gate.yml — Gates the self-contained satellite workspaces.
5+
#
6+
# vcl-ut has FIVE cargo workspace roots, not one. Before this workflow, CI
7+
# covered only three of them:
8+
#
9+
# / e2e.yml
10+
# /src/interface/parse parse-gate.yml
11+
# /src/interface/echidna-client backend-matrix.yml (needs echidna sibling)
12+
# /src/interface/attest NOTHING <- gated here
13+
# /src/interface/recompute-wasm NOTHING <- gated here
14+
#
15+
# The cost of that gap was measured on 2026-07-21: both ungated crates had
16+
# stopped compiling. `ast::Statement` gained the S1 consonance field `verb`
17+
# (DECLARE / ASSERT / RETRACT / MERGE / ...), and neither crate's test module
18+
# was updated, so both failed with E0063 `missing field 'verb'`. Their
19+
# libraries still built, so nothing downstream noticed; 12 tests had simply
20+
# stopped running. Silent rot in exactly the crates that carry the
21+
# attestation and recompute boundaries.
22+
#
23+
# Both crates are self-contained (in-repo path deps only), so unlike
24+
# echidna-client they need no sibling checkout and can be gated cheaply.
25+
#
26+
# Tracked: vcl-ut#25.
27+
28+
name: Satellite Crates Gate
29+
30+
on:
31+
pull_request:
32+
branches: ['**']
33+
push:
34+
branches: [main, master]
35+
36+
permissions:
37+
contents: read
38+
39+
concurrency:
40+
group: ${{ github.workflow }}-${{ github.ref }}
41+
cancel-in-progress: true
42+
43+
jobs:
44+
satellite-gate:
45+
name: ${{ matrix.crate }} — clippy / tests
46+
runs-on: ubuntu-latest
47+
timeout-minutes: 15
48+
49+
strategy:
50+
fail-fast: false
51+
matrix:
52+
crate: [attest, recompute-wasm]
53+
54+
steps:
55+
- name: Checkout repository
56+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
57+
58+
# rustup is preinstalled on ubuntu-latest; no third-party action
59+
# (avoids the action-pinning / deprecated-cache hazards). Mirrors
60+
# parse-gate.yml deliberately.
61+
- name: Pin toolchain + components
62+
run: |
63+
set -euo pipefail
64+
rustup show active-toolchain || rustup default stable
65+
rustup component add clippy
66+
cargo --version && cargo clippy --version
67+
68+
# Operate via the manifest path so CI never traverses the parent
69+
# virtual workspace, whose `src/interface` member carries an external
70+
# path-dep that does not resolve in a standalone checkout.
71+
#
72+
# `--locked` is deliberately NOT used: these two lockfiles drifted while
73+
# the crates were ungated. They are regenerated and committed as part of
74+
# the repair; once a Dependabot cycle has run against them, `--locked`
75+
# should be restored here to make lockfile drift itself a gate.
76+
- name: Clippy — warnings are errors
77+
run: |
78+
set -euo pipefail
79+
cargo clippy --manifest-path src/interface/${{ matrix.crate }}/Cargo.toml \
80+
--all-targets -- -D warnings
81+
82+
- name: Tests
83+
run: |
84+
set -euo pipefail
85+
cargo test --manifest-path src/interface/${{ matrix.crate }}/Cargo.toml

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ version = "0.1.0"
55
edition = "2021"
66
license = "MPL-2.0"
77
authors = ["Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"]
8-
repository = "https://github.com/hyperpolymath/vql-ut"
8+
repository = "https://github.com/hyperpolymath/vcl-ut"
99
description = "VCL-total: 10-level type-safe query language for VeriSimDB"
1010

1111
# The top-level crate re-exports the formatter and linter for integration testing.

0 commit comments

Comments
 (0)