Skip to content
Closed
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
25 changes: 13 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ jobs:
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
toolchain: "1.93.0"
components: rustfmt
cache: false
rustflags: ""
Expand Down Expand Up @@ -77,6 +76,9 @@ jobs:
with:
fetch-depth: 1

- name: Rust toolchain pin alignment (rust-toolchain.toml vs rustup.dag)
run: bash scripts/check-rust-toolchain-pin-alignment.sh

- name: Fabrication sentinel ratchet (P0-C)
run: bash scripts/check-fabrication-sentinels.sh

Expand Down Expand Up @@ -108,7 +110,6 @@ jobs:
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
toolchain: "1.93.0"
components: rustfmt
cache: false
rustflags: ""
Expand Down Expand Up @@ -145,7 +146,6 @@ jobs:
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
toolchain: "1.93.0"
# Integration snapshot tests (`regen_parse` path, lane2d cost lens, …) shell out to `rustfmt`.
components: rustfmt, clippy
cache: false
Expand Down Expand Up @@ -192,14 +192,14 @@ jobs:
# miss, first compile + link on ubuntu-latest) can spend minutes — keep
# headroom beyond a tight 120s; per-test discipline lives in
# `tests/common/budgeted.rs` (DEFAULT_BUDGET_MS).
- name: v3 tests (Stage 2d integration module, 300s cold-compile-safe budget)
- name: v3 tests (Stage 2d integration module, 420s cold-compile-safe budget)
run: |
start=$(date +%s)
cargo test -p v3-compiler --test integration lane2_stage_2d_symbolic_cost_test::
elapsed=$(( $(date +%s) - start ))
echo "v3 Stage 2d (lane2d) wall time: ${elapsed}s"
if [ "$elapsed" -gt 300 ]; then
echo "::error::v3 lane2d tests took ${elapsed}s (budget: 300s) — share bootstrap setup via OnceLock or collapse fine-grained tests"
if [ "$elapsed" -gt 420 ]; then
echo "::error::v3 lane2d tests took ${elapsed}s (budget: 420s) — share bootstrap setup via OnceLock or collapse fine-grained tests"
exit 1
fi

Expand All @@ -213,12 +213,14 @@ jobs:
# `RUSTC_BOOTSTRAP=1` prefix is the documented narrow unlock for libtest flags
# and does not enable unstable language features.
- name: v3 tests (full suite, 2400s transitional budget)
id: v3_full_suite
env:
# Keep libtest lines plain for `scripts/check-test-timeout.sh` (Phase-0
# ratchet); workflow-level `CARGO_TERM_COLOR=always` would otherwise
# inject ANSI into cargo's stream.
CARGO_TERM_COLOR: never
run: |
rm -f /tmp/v3-test-timings.log
start=$(date +%s)
RUSTC_BOOTSTRAP=1 cargo test -p v3-compiler -- -Z unstable-options --report-time 2>&1 | tee /tmp/v3-test-timings.log
status=${PIPESTATUS[0]}
Expand All @@ -241,12 +243,12 @@ jobs:
# `src/v3/compiler/tests/HANDOFF_PHASE0.md` (TESTING.md § test layers,
# `feedback_test_timeout_2s`).
#
# **`if: always()`** — the ratchet report is still useful on red runs
# (full-suite failure, 2400s transitional-budget overflow). The log is captured via
# `tee` before the enforcement check, so partial timing data survives
# failure and the ratchet can still emit actionable slow-test output.
# Run only when the full-suite step actually executed (success or failure).
# If an earlier step (e.g. lane2d budget) aborts the job, `v3_full_suite` is
# skipped — do not parse a stale `/tmp/v3-test-timings.log` from a prior
# step or runner reuse (`if: always()` alone is insufficient).
- name: v3 tests (per-test 2s ratchet)
if: always()
if: always() && (steps.v3_full_suite.outcome == 'success' || steps.v3_full_suite.outcome == 'failure')
run: |
if [ ! -s /tmp/v3-test-timings.log ]; then
echo "::notice::no timing log captured or log is empty (full-suite step did not reach cargo test, or tee wrote nothing) — skipping per-test ratchet"
Expand Down Expand Up @@ -332,7 +334,6 @@ jobs:
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
toolchain: "1.93.0"
cache: false
rustflags: ""

Expand Down
1 change: 1 addition & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ Per-row tagging is a scheduled follow-up sweep — **trigger:** post-merge of th
- **`effects.dag` dual authority** — `dsl/std/effects.dag` (395 lines) vs `src/v3/std/effects.dag` (818 lines, diverged 2×). Dissolution: decide authoritative location, collapse the other; name a convergence lane.
- **`container_template_algebra_rows` table duplicates type aliases** — `dsl/std/types.dag:133-146` is the string-keyed table (renamed from `container_to_algebra` in PR #651's narrow dissolution); `types.dag:211-213` declares `type List<T> = FreeMonoid<T>` etc. Dissolution: derive the table from the aliases when alias reflection lands.
- **Parallel string-keyed authorities in types.dag + coercion.dag**: `kernel_primitives` (65-74), `container_arity` (79-91), `ordered_collections` (125-130), `TypeCheckpoint.dag_name: String` (38-44), `InhabitantDecl.algebra: String` (59-65). Header labels as transitional. Dissolution: derive from structural declarations.
- **`rust-toolchain.toml` vs `dsl/extdeps/rustup.dag::ci_pinned_toolchain`**: the pinned rustc channel string lives in both the repo-root TOML (rustup + `setup-rust-toolchain` after checkout) and `data ci_pinned_toolchain` in the extdep stub — P2 parallel-authority drift risk. PR #1789 removed a false “codegen” banner and documented alignment; it did not introduce the duplication (the TOML was already hand-maintained). Dissolution trigger: **`rust_toolchain_toml_codegen_from_rustup_dag`** — regenerate `rust-toolchain.toml` from `rustup.dag` (or fold `ci_pinned_toolchain` into a single file-backed authority) via bounded `gunbc-codegen` (or successor) so only one authored pin remains. Owner: T-Workflow-As-Data / extdeps hygiene as bandwidth allows.

### P3 — modeling gaps

Expand Down
2 changes: 1 addition & 1 deletion dsl/extdeps/github/actions.dag
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ data checkout_action: ActionRef = ActionRef {
}

data setup_rust_action: ActionRef = ActionRef {
owner: "dtolnay", repo: "rust-toolchain", ref: "stable"
owner: "actions-rust-lang", repo: "setup-rust-toolchain", ref: "v1.16.0"
}

data cache_action: ActionRef = ActionRef {
Expand Down
7 changes: 4 additions & 3 deletions dsl/extdeps/rustup.dag
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
// What we actually depend on from rustup:
// - cargo binary, installed by default with the stable toolchain
// - rustc, installed by default
// - Pinned toolchain "1.93.0" in CI (.github/workflows/ci.yml)
// - Pinned toolchain "1.93.0" in repo-root rust-toolchain.toml (CI reads it)
//
// What we do NOT currently depend on:
// - Custom components (clippy ships with stable, rustfmt ships with stable)
// - Cross-compilation targets (gunbc only builds for the host)
// - Multiple toolchains (no toolchain switching)
//
// The CI workflow uses dtolnay/rust-toolchain@v1 to provision
// rustup. Local dev uses whatever rustup ships as stable.
// CI uses actions-rust-lang/setup-rust-toolchain (see setup_rust_action in
// extdeps/github/actions.dag); channel comes from rust-toolchain.toml. Local dev
// usually tracks stable unless overridden by that file.
//
// Future:
// When we model toolchain switching, channels, components, or
Expand Down
5 changes: 3 additions & 2 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by gunbc-codegen. Do not edit manually.
# Source of truth: dsl/config/toolchain.dag
# Channel pin for local rustup and GitHub Actions (`setup-rust-toolchain` reads
# this file after checkout when no explicit `toolchain:` input is passed).
# Keep `channel` aligned with `dsl/extdeps/rustup.dag` `ci_pinned_toolchain`.
[toolchain]
channel = "1.93.0"
components = ["clippy", "rustfmt"]
30 changes: 30 additions & 0 deletions scripts/check-rust-toolchain-pin-alignment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Fail closed if rust-toolchain.toml [toolchain].channel drifts from
# dsl/extdeps/rustup.dag `ci_pinned_toolchain` while both remain hand-authored
# (ROADMAP P2 / rust_toolchain_toml_codegen_from_rustup_dag).
set -euo pipefail
repo_root=$(cd "$(dirname "$0")/.." && pwd)
cd "$repo_root"

toml_channel=$(
grep -E '^[[:space:]]*channel[[:space:]]*=' rust-toolchain.toml |
head -1 |
sed -E 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"([^"]+)".*/\1/'
)
dag_channel=$(
grep -E '^data ci_pinned_toolchain' dsl/extdeps/rustup.dag |
head -1 |
sed -E 's/^data ci_pinned_toolchain:[^=]*=[[:space:]]*"([^"]+)".*/\1/'
)

if [ -z "${toml_channel}" ] || [ -z "${dag_channel}" ]; then
echo "::error::could not parse channel from rust-toolchain.toml and/or ci_pinned_toolchain from dsl/extdeps/rustup.dag"
exit 1
fi

if [ "${toml_channel}" != "${dag_channel}" ]; then
echo "::error::Rust toolchain pin mismatch: rust-toolchain.toml channel='${toml_channel}' vs dsl/extdeps/rustup.dag ci_pinned_toolchain='${dag_channel}'. Align both until rust_toolchain_toml_codegen_from_rustup_dag dissolves the duplicate (ROADMAP.md P2)."
exit 1
fi

echo "Rust toolchain pin alignment OK (${toml_channel})."
66 changes: 38 additions & 28 deletions src/v3/compiler/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ mod t_demo_fixture_test {

use std::fs;
use std::path::PathBuf;
use std::sync::OnceLock;

use v3_compiler::compile_to_dag;
use v3_compiler::dag::Dag;
Expand All @@ -216,6 +217,9 @@ mod t_demo_fixture_test {
/// Byte-sync with `t_demo_structural_cost_obligation_gate.source` in `t_demo_fixtures.dag`.
const T_DEMO_STRUCTURAL_COST_OBLIGATION_CLAIM_SOURCE: &str = "fn pair_score(xs: List<Int>) -> Int = fold(xs, 0, |outer, x| outer + fold(xs, 0, |inner, y| inner + x + y))\nlet complexity_demo_out: Int = pair_score(cons(1, singleton(2)))\n";

// Process-wide cache: shared read-only `Dag`; tests that mutate or need isolation must compile locally.
static T_DEMO_FIXTURE_DAG: OnceLock<Dag> = OnceLock::new();

fn fixture_source() -> String {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../..")
Expand All @@ -227,39 +231,47 @@ mod t_demo_fixture_test {
compile_to_dag(source, FIXTURE).expect("T-Demo fixture skeleton compiles")
}

fn shared_t_demo_fixture_dag() -> &'static Dag {
T_DEMO_FIXTURE_DAG.get_or_init(|| {
let source = fixture_source();
compile_fixture(&source)
})
}

#[test]
fn t_demo_fixture_skeleton_compiles() {
let source = fixture_source();
let dag = compile_fixture(&source);

let dag = shared_t_demo_fixture_dag();
assert!(
dag.diagnostics().is_empty(),
"T-Demo fixture skeleton should compile without diagnostics: {:?}",
dag.diagnostics()
);
}

fn assert_t_demo_canonical_suite_passes(dag: &Dag, suite_name: &str) {
let results = TestRunner::new(dag).run_suite(suite_name);
assert!(
!results.is_empty(),
"T-Demo suite `{suite_name}` should contain Day-1 Compiles claims"
);
assert!(
results
.iter()
.all(|result| result.result == ClaimResult::Pass),
"T-Demo suite `{suite_name}` should pass Day-1 Compiles claims, got {results:?}"
);
}

#[test]
fn t_demo_canonical_suites_are_runner_visible() {
let source = fixture_source();
let dag = compile_fixture(&source);
fn t_demo_fixture_compiler_nerd_canonical_suite_is_runner_visible() {
let dag = shared_t_demo_fixture_dag();
assert_t_demo_canonical_suite_passes(dag, "fixture_compiler_nerd_canonical");
}

for suite_name in [
"fixture_compiler_nerd_canonical",
"fixture_integration_canonical",
] {
let results = TestRunner::new(&dag).run_suite(suite_name);
assert!(
!results.is_empty(),
"T-Demo suite `{suite_name}` should contain Day-1 Compiles claims"
);
assert!(
results
.iter()
.all(|result| result.result == ClaimResult::Pass),
"T-Demo suite `{suite_name}` should pass Day-1 Compiles claims, got {results:?}"
);
}
#[test]
fn t_demo_fixture_integration_canonical_suite_is_runner_visible() {
let dag = shared_t_demo_fixture_dag();
assert_t_demo_canonical_suite_passes(dag, "fixture_integration_canonical");
}

/// ROADMAP T-Demo / PR #764: `FailsWithDiagnostic.detail_contains` must pin the **sum
Expand All @@ -283,9 +295,8 @@ mod t_demo_fixture_test {

#[test]
fn t_demo_impossible_bug_suite_r1_passes() {
let source = fixture_source();
let dag = compile_fixture(&source);
let results = TestRunner::new(&dag).run_suite("impossible_bug_class_suite_r1");
let dag = shared_t_demo_fixture_dag();
let results = TestRunner::new(dag).run_suite("impossible_bug_class_suite_r1");
assert_eq!(results.len(), 2);
assert!(
results
Expand All @@ -301,9 +312,8 @@ mod t_demo_fixture_test {
/// surface is user-extensible (THESIS §"User-defined dimensions").
#[test]
fn t_demo_user_authored_lens_rejects_violating_program_passes() {
let source = fixture_source();
let dag = compile_fixture(&source);
let results = TestRunner::new(&dag)
let dag = shared_t_demo_fixture_dag();
let results = TestRunner::new(dag)
.run_suite("demo_user_authored_lens_rejects_violating_program_suite");
assert_eq!(results.len(), 1);
assert!(
Expand Down
Loading