diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6474e40e7d5..43e4857920a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,14 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true +# Rust: each `setup-rust-toolchain` step omits `toolchain:` so the action reads +# `rust-toolchain.toml` at the repo root after `actions/checkout`. No job uses a +# non-default `working-directory` for Rust setup; if one did, make `rust-toolchain.toml` +# visible from that directory (e.g. copy it in) — do **not** add a workflow `toolchain:` +# input: `scripts/check-rust-toolchain-single-authority.sh` rejects `toolchain:` in the +# same Actions step as `actions-rust-lang/setup-rust-toolchain` in any +# `.github/workflows/*.{yml,yaml}`, and the action +# ignores the repo file when `toolchain` is set explicitly (upstream semantics). env: CARGO_TERM_COLOR: always RUSTFLAGS: -D warnings @@ -49,7 +57,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: "" @@ -121,10 +128,14 @@ jobs: # silently neutering the consumer. run: bash scripts/test-check-manager-brief-authority.sh + - name: Rust toolchain single-authority check (P2) + # Pinned channel must not be duplicated in dsl/extdeps/rustup.dag; + # authority is rust-toolchain.toml only (PR #1794). + run: bash scripts/check-rust-toolchain-single-authority.sh + - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1.16.0 with: - toolchain: "1.93.0" components: rustfmt cache: false rustflags: "" @@ -171,7 +182,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 @@ -214,13 +224,17 @@ jobs: # Wall-clock gate on lane2 Stage 2d symbolic-cost tests only (ζ / #537). # Post-#546 these live in the consolidated `integration` test binary; the # `lane2_stage_2d_symbolic_cost_test::` filter keeps the ratchet narrow. - # The timer wraps the full `cargo test` process, so **cold** runs (cache - # miss, first compile + link on ubuntu-latest) can spend minutes — keep - # headroom beyond a tight 120s; per-test discipline lives in + # The timer wraps the full `cargo test` process. Prebuild the integration + # harness (`--no-run`) so this gate measures lane2d work — not a cold link + # of the whole `integration` binary (observed ~322s over a 300s budget on + # ubuntu-latest; PR #1794). **Cold** runs (cache miss) can still spend minutes; + # keep headroom beyond a tight 120s; per-test discipline lives in # `tests/common/budgeted.rs` (DEFAULT_BUDGET_MS). - # Tracked headroom: ratchet this ceiling back toward 300s once cold - # lane2d CI runs regularly complete under 300s after fixture compile - # amortization lands for the remaining Stage 2d cases. + # Tracked headroom: ratchet this ceiling back toward 300s once cold lane2d + # CI runs regularly complete under 300s after fixture compile amortization. + - name: Prebuild v3 integration test binary (lane2d wall-clock denominator) + run: cargo test -p v3-compiler --test integration --no-run + - name: v3 tests (Stage 2d integration module, 360s cold-compile-safe budget) run: | start=$(date +%s) @@ -351,9 +365,11 @@ jobs: # PR job still reports as a failed check, which makes this advisory ratchet # merge-blocking before Lane 1e graduation. if: github.event_name == 'push' && github.ref == 'refs/heads/main' - # Same sizing rationale as `v3` above: DB-8 release builds run on - # ubicloud-standard-8. Use a 60m wall-clock cap so cold-cache / full release - # `cargo` work is unlikely to hit mid-compile cancellation (ratchet remains non-blocking). + # Same sizing rationale as `v3` above: DB-8 release builds + determinism_test (5× matrix) + + # `self_host_fixed_point` run on `ubicloud-standard-8` (#1814); small/default runners saw + # mid-compile shutdown on #1794. **60m** wall so cold-cache / full release `cargo` is unlikely + # to cancel mid-job; ratchet remains non-blocking. (Runner label is orthogonal to P2: + # `rust-toolchain.toml` + no workflow `toolchain:` input.) runs-on: ubicloud-standard-8 timeout-minutes: 60 needs: [v3] @@ -367,7 +383,6 @@ jobs: - name: Setup Rust uses: actions-rust-lang/setup-rust-toolchain@v1.16.0 with: - toolchain: "1.93.0" cache: false rustflags: "" diff --git a/docs/design-fixed-point-ratchet.md b/docs/design-fixed-point-ratchet.md index ead7200bd6d..e31f666f234 100644 --- a/docs/design-fixed-point-ratchet.md +++ b/docs/design-fixed-point-ratchet.md @@ -88,31 +88,15 @@ Comparison uses raw byte equality — whitespace matters, line endings matter. M ### CI integration -`.github/workflows/ci.yml` — add a new job: - -```yaml -self_host: - runs-on: ubuntu-latest - timeout-minutes: 15 - needs: [ci, v3] # runs after basic build + v3 tests pass - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: "1.93.0" - - name: Cache Cargo (self_host) - uses: actions/cache@v4 - with: - path: | - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - target/ - key: cargo-self-host-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('src/v3/compiler/**') }} - - name: Self-host fixed-point check - run: cargo run --bin self_host_fixed_point --release -``` +Canonical wiring is **`.github/workflows/ci.yml`**, job **`self_host_ratchet`** (`needs: [v3]`). + +While DB-8 stays **staged** and the job remains **`continue-on-error: true`**, it is scheduled on **`push` to `refs/heads/main` only** (PR runs were producing merge-blocking red checks when Actions cancelled in-flight jobs). The **`v3`** job still runs **`determinism_test`** on pull requests. + +- **Runner / wall clock:** `ubicloud-standard-8`, `timeout-minutes: 60` (heavy release work + cold cache). +- **Rust setup:** `actions-rust-lang/setup-rust-toolchain@v1.16.0` with **`toolchain:` omitted** so the action reads `rust-toolchain.toml` (enforced by `scripts/check-rust-toolchain-single-authority.sh`). +- **Steps (release):** `cargo test -p v3-compiler --release --test determinism_test`, then `cargo run -p v3-compiler --release --bin self_host_fixed_point`, plus informational `emit.rs` HashMap/HashSet grep. -Runs after the core `v3` job. If emission changes, this fails; CI blocks merge. +Failures are **advisory** until Lane 1e graduates the ratchet to merge-blocking. ### Sources of non-determinism (to eliminate) @@ -222,7 +206,7 @@ Runs per-test, local to each emit call. Catches non-determinism without needing **Why per-fixture 5x re-run test?** Because most non-determinism manifests within a single process (HashMap seed randomness). 5 runs gives high confidence without absurd test runtime. -**Why separate `self_host_fixed_point` binary, not a test?** Because it's a pipeline (emit → rustc → run → diff) too heavyweight for `cargo test`. CI runs it as its own job; developers can invoke it locally via `cargo run --bin self_host_fixed_point --release`. +**Why separate `self_host_fixed_point` binary, not a test?** Because it's a pipeline (emit → rustc → run → diff) too heavyweight for `cargo test`. CI runs it as its own job; developers can invoke it locally via `cargo run -p v3-compiler --release --bin self_host_fixed_point`. --- @@ -232,7 +216,7 @@ Runs per-test, local to each emit call. Catches non-determinism without needing **Structural diff (parse both, compare ASTs)** — allows whitespace differences. Too lenient. We want bit-identical as the contract. Rejected. -**Only check on push to main** — misses PRs that introduce non-determinism. Run on every PR + main push. Rejected "only on main." +**Only check on push to main** — misses PRs that introduce non-determinism if it were the *sole* long-term policy. **Current compromise (staged):** `self_host_ratchet` runs on **`main` pushes only** while the job is still advisory, because cancelled PR workflow runs were surfacing as merge-blocking failures; PRs still get **`determinism_test`** inside **`v3`**. Re-open PR+`main` coverage when the ratchet graduates merge-blocking. **Accept "close enough" — diff lines < 5** — opens a hole. Any intentional emission change must be accompanied by snapshot update; any unintentional change is a bug. Rejected. @@ -255,7 +239,7 @@ target/self_host/ ### Performance -Self-host cycle takes: emit (2s) + rustc (30s) + run (1s) + diff (instant) = ~33s per cycle. Running once per PR is acceptable. If it grows to the v2 "20-minute self-compile" regime (THESIS.md §merge_envs case study), sound alarm — see open question 2 below. +Self-host cycle takes: emit (2s) + rustc (30s) + run (1s) + diff (instant) = ~33s per cycle on a warm machine. CI runs the dedicated job on each **`main` push** while staged (see **CI integration**). If it grows to the v2 "20-minute self-compile" regime (THESIS.md §merge_envs case study), sound alarm — see open question 2 below. ### Bisecting non-determinism @@ -276,7 +260,7 @@ Maintain a `docs/self-host-incidents.md` log of found non-determinism sources - **`src/v3/compiler/compiler.dag`** — the compiler source being cycled (PR #418 and later additions) - **Create `src/v3/compiler/src/bin/self_host_fixed_point.rs`** — the CI binary - **Create `src/v3/compiler/tests/determinism_test.rs`** (+ shared matrix in `tests/common/determinism_fixtures.rs`) — per-fixture 5× determinism check -- **Update `.github/workflows/ci.yml`** — `self_host` job +- **Update `.github/workflows/ci.yml`** — `self_host_ratchet` job - **Update `.gitignore`** — `target/self_host/` - **Thesis anchor** — SELF_HOSTING.md §14 (fixed-point discipline) @@ -285,7 +269,7 @@ Maintain a `docs/self-host-incidents.md` log of found non-determinism sources ## Acceptance (Lane 3 Stage 3c owns) - [ ] `self_host_fixed_point` binary passes full emit → rustc → run → **byte-identical** diff on `dsl/gunbc/compiler.dag` (staged until v3 parses + emits a CLI-shaped crate) -- [x] CI job `self_host_ratchet` runs after `v3` on every PR + main push; **`continue-on-error: true`** until Lane 1e closes (then graduate to merge-blocking) +- [x] CI job `self_host_ratchet` runs after `v3` on each **`main` branch push** while staged (PRs: `determinism_test` in **`v3`**); **`continue-on-error: true`** until Lane 1e closes (then graduate to merge-blocking) - [x] `tests/determinism_test.rs` passes per-matrix-row 5× equivalence (Rust full matrix; Go/Python scoped per `determinism_fixtures.rs`) - [x] Informational grep step in `self_host_ratchet` surfaces `HashMap`/`HashSet::` in `emit.rs` (strict gate deferred until Lane 1e clears iteration debt) - [x] Invariant D-1 (determinism) added to `INVARIANTS.md` @@ -294,7 +278,7 @@ Maintain a `docs/self-host-incidents.md` log of found non-determinism sources ## Open questions -1. **Does the ratchet need to run in `release` mode?** Probably yes — rustc release inlines more, which can stabilize output. Design has `cargo run --bin self_host_fixed_point --release`. +1. **Does the ratchet need to run in `release` mode?** Probably yes — rustc release inlines more, which can stabilize output. Design has `cargo run -p v3-compiler --release --bin self_host_fixed_point`. 2. **What if self-host cycle time approaches v2's 20-min issue?** Alarm. Root-cause the slowdown (usually HashMap-dependent re-derivation, per THESIS.md case study). Don't accept >2min for the cycle. diff --git a/dsl/extdeps/github/actions.dag b/dsl/extdeps/github/actions.dag index 40878c6efba..8518f687cef 100644 --- a/dsl/extdeps/github/actions.dag +++ b/dsl/extdeps/github/actions.dag @@ -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 { diff --git a/dsl/extdeps/rustup.dag b/dsl/extdeps/rustup.dag index f1a5b6bd77f..4309513c732 100644 --- a/dsl/extdeps/rustup.dag +++ b/dsl/extdeps/rustup.dag @@ -11,15 +11,17 @@ // 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 channel: **single authority** is `rust-toolchain.toml` +// `[toolchain].channel` only (this stub does not duplicate that string). // // What we do NOT currently depend on: -// - Custom components (clippy ships with stable, rustfmt ships with stable) +// - Extra rustup components beyond rust-toolchain.toml (rustfmt + clippy today) // - 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 .github/workflows/ci.yml), which +// reads rust-toolchain.toml. Local dev uses rust-toolchain.toml when present, else +// whatever rustup ships as stable. // // Future: // When we model toolchain switching, channels, components, or @@ -44,9 +46,5 @@ data rustup_install_url: NonEmptyStr = "https://rustup.rs" // Default channel we expect when "rustup default" is queried. data default_channel: RustChannel = Stable -// The pinned toolchain version used in CI. Local dev usually tracks -// stable; CI pins for reproducibility. -data ci_pinned_toolchain: NonEmptyStr = "1.93.0" - // Rustup docs URL for reference. data rustup_docs: NonEmptyStr = "https://rust-lang.github.io/rustup/" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7828a71dec7..ba5604ab1c4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,6 @@ -# Generated by gunbc-codegen. Do not edit manually. -# Source of truth: dsl/config/toolchain.dag +# Sole in-repo rustup channel authority (CI + local). Hand-maintained (no +# regen step overwrites this file). `dsl/extdeps/rustup.dag` documents rustup +# installer behavior only — it must not introduce a second pinned channel literal. [toolchain] channel = "1.93.0" components = ["clippy", "rustfmt"] diff --git a/scripts/check-rust-toolchain-single-authority.sh b/scripts/check-rust-toolchain-single-authority.sh new file mode 100755 index 00000000000..ba018f7696e --- /dev/null +++ b/scripts/check-rust-toolchain-single-authority.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# +# P2 single-authority: the pinned rustc channel string lives only in +# `rust-toolchain.toml` `[toolchain].channel`. `dsl/extdeps/rustup.dag` must not +# reintroduce that value as a quoted literal, as a bare semver-like token (catches +# unquoted comment drift such as `// pin 1.93.0`), nor via the retired +# `ci_pinned_toolchain` symbol — see PR #1794 / INVARIANTS P2. Word channels (e.g. +# `stable`) are only checked in quoted form to avoid unrelated prose false positives. +# +# Also fail if any `.github/workflows/*.{yml,yaml}` pairs `toolchain:` with +# `actions-rust-lang/setup-rust-toolchain` in the same step (the action ignores +# rust-toolchain.toml when that input is present — same authority drift class). +# +# Dissolution: delete this script and its CI step if extdeps + workflow toolchain +# selection are generated or schema-checked so this shell guard is redundant. + +set -euo pipefail + +script_dir=$(cd "$(dirname "$0")" && pwd) +repo_root=$(cd "$script_dir/.." && pwd) +rustup_dag="$repo_root/dsl/extdeps/rustup.dag" +toolchain_toml="$repo_root/rust-toolchain.toml" +workflows_dir="$repo_root/.github/workflows" + +if [ ! -r "$rustup_dag" ]; then + echo "::error::missing $rustup_dag" + exit 2 +fi + +if [ ! -r "$toolchain_toml" ]; then + echo "::error::missing $toolchain_toml" + exit 2 +fi + +if [ ! -d "$workflows_dir" ]; then + echo "::error::missing $workflows_dir" + exit 2 +fi + +if ! grep -Eq '^[[:space:]]*channel[[:space:]]*=[[:space:]]*"' "$toolchain_toml"; then + echo "::error::rust-toolchain.toml must contain a quoted [toolchain].channel line" + exit 1 +fi + +channel=$( + sed -n 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' "$toolchain_toml" | head -n1 +) +if [ -z "$channel" ]; then + echo "::error::could not parse [toolchain].channel from rust-toolchain.toml" + exit 1 +fi + +quoted_channel="\"${channel}\"" +if grep -Fq "$quoted_channel" "$rustup_dag"; then + echo "::error::dsl/extdeps/rustup.dag contains the pinned channel literal ${quoted_channel} — duplicate authority (keep the channel only in rust-toolchain.toml)." + exit 1 +fi + +# Semver-like channels: also reject the bare token so unquoted comment/data drift +# cannot reintroduce the pin (e.g. `// use 1.93.0`). Skipped for word channels like +# `stable` where this substring can appear in unrelated prose. +if [[ "$channel" =~ ^[0-9]+\.[0-9]+ ]]; then + if grep -Fq "$channel" "$rustup_dag"; then + echo "::error::dsl/extdeps/rustup.dag contains bare channel token '${channel}' — duplicate authority (keep the channel only in rust-toolchain.toml)." + exit 1 + fi +fi + +if grep -Eq '^[[:space:]]*data[[:space:]]+ci_pinned_toolchain' "$rustup_dag"; then + echo "::error::dsl/extdeps/rustup.dag declares ci_pinned_toolchain — retired duplicate authority symbol. Use rust-toolchain.toml only." + exit 1 +fi + +# Indented YAML key `toolchain:` under `with:` for `actions-rust-lang/setup-rust-toolchain` +# ignores rust-toolchain.toml — forbid that pairing only (not unrelated `toolchain:` keys +# in other actions). Python scan walks each `toolchain:` line up to its Actions step head, +# then scans the **full** step (through the next sibling `-` at the same list indent) so a +# pathological `with.toolchain` **before** `uses: …/setup-rust-toolchain` cannot evade the check. +if ! command -v python3 >/dev/null 2>&1; then + echo "::error::python3 is required for workflow toolchain guard (setup-rust-toolchain scope)" + exit 2 +fi + +python3 - "$workflows_dir" "$repo_root" <<'PY' +import pathlib +import re +import sys + +SETUP = "actions-rust-lang/setup-rust-toolchain" + + +def _step_span(lines, step_start): + """Return [step_start, end) line indices for one GitHub Actions `steps:` list item.""" + m0 = re.match(r"^(\s*)-\s", lines[step_start]) + if not m0: + return step_start, min(step_start + 1, len(lines)) + base = len(m0.group(1)) + k = step_start + 1 + while k < len(lines): + m = re.match(r"^(\s*)-\s", lines[k]) + if m is not None and len(m.group(1)) == base: + break + k += 1 + return step_start, k + + +def violation_in_file(wf_path): + lines = wf_path.read_text(encoding="utf-8").splitlines() + for i, line in enumerate(lines): + m_tc = re.match(r"^(\s+)toolchain\s*:", line) + if not m_tc: + continue + tc_ws = len(m_tc.group(1)) + j = i - 1 + while j >= 0: + m_dash = re.match(r"^(\s*)-\s", lines[j]) + if m_dash is not None and len(m_dash.group(1)) < tc_ws: + break + j -= 1 + if j < 0: + continue + _, k = _step_span(lines, j) + block = "\n".join(lines[j:k]) + if SETUP in block: + return i + 1, line.strip() + return None + + +def main(): + workflows_dir = pathlib.Path(sys.argv[1]) + repo_root = pathlib.Path(sys.argv[2]) + files = sorted(workflows_dir.glob("*.yml")) + sorted(workflows_dir.glob("*.yaml")) + if not files: + print(f"::error::no *.yml or *.yaml under {workflows_dir}") + return 2 + for wf in files: + hit = violation_in_file(wf) + if hit is not None: + lineno, preview = hit + rel = wf.resolve().relative_to(repo_root.resolve()) + print( + f"::error::file={rel},line={lineno}::explicit `toolchain:` input on " + f"{SETUP} — rust-toolchain.toml would be ignored. Remove it from that step's `with:`." + ) + print(f"{rel}:{lineno}: {preview}") + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) +PY + +echo "Rust toolchain single-authority check OK (channel=${channel}; rustup.dag + workflow guard)." diff --git a/scripts/slow-test-exemptions.txt b/scripts/slow-test-exemptions.txt index 532492b92af..482d032a3e0 100644 --- a/scripts/slow-test-exemptions.txt +++ b/scripts/slow-test-exemptions.txt @@ -78,6 +78,6 @@ sg2_parse_authority_test::parse_surface_dag_compiles_cleanly_for_regen_parse # sg2c1_parse_tables_authority_test::parse_tables_generated_module_matches_checked_in_snapshot # SG-2c-1 grammar-tables prototype snapshot: in-process authority compile (parse_tables.dag + tokenize.dag) + rustfmt stdout; same paydown class as SG-1 tokenize / SG-2 parse snapshot gates. sg6_hand_authored_census_test::sg6_regen_lens_cli_smoke_regenerates_named_entry_without_drift # SG-6 regen CLI smoke intentionally shells out to regen path; CLI smoke cost is tracked in SG-6, not TM-0. -t_demo_fixture_test::t_demo_canonical_suites_are_runner_visible # ROADMAP T-Demo (Lane M): cold `compile_to_dag` on full `t_demo_fixtures.dag` + two `TestRunner::run_suite` passes; ~2.6–3.3s wall on isolated/filtered runs (above 2s Phase-0 ratchet). `compile_fixture` uses `cached_compile_to_dag` to dedupe with `t_demo_fixture_skeleton_compiles`; paydown: slimmer fixture / shared runner warming in T-Demo lane. +t_demo_fixture_test::t_demo_canonical_suites_are_runner_visible # ROADMAP T-Demo (Lane M): cold `compile_to_dag` on full `t_demo_fixtures.dag` + two `TestRunner::run_suite` passes; ~2.6–3.3s wall on isolated/filtered runs (above 2s Phase-0 ratchet). `compile_fixture` uses `cached_compile_to_dag`; module `OnceLock` still shares one `Dag` across sibling tests. Dissolution: delete this line and lower `TEST_TIMEOUT_MAX_EXEMPTIONS` in the same commit once `RUSTC_BOOTSTRAP=1 cargo test -p v3-compiler t_demo_canonical_suites_are_runner_visible -- -Z unstable-options --report-time` shows <=2000ms wall on cold ubuntu-latest after fixture slimming or shared-runner warming (TESTING.md). thesis_validation_test::kf_1_structural_list_operation_ordering_holds # KF-1 thesis validation remains compile-heavy on CI runners; TESTING.md test-shape paydown owns future decomposition, not TM-0. diff --git a/src/v2/tests/src/pb_method_template_projection_consumability.rs b/src/v2/tests/src/pb_method_template_projection_consumability.rs index a3723e8e1b2..cf831582587 100644 --- a/src/v2/tests/src/pb_method_template_projection_consumability.rs +++ b/src/v2/tests/src/pb_method_template_projection_consumability.rs @@ -122,9 +122,7 @@ fn rust_count_template() -> Map { rust_method_template_emit } .to_string_lossy() .to_string(); assert!( - loaded_paths - .iter() - .any(|path| *path == expected_generated_path.as_str()), + loaded_paths.contains(&expected_generated_path.as_str()), "expected the ephemeral generated module to load at exactly \ {expected_generated_path}; got: {loaded_paths:?}" ); diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index dff82662719..82b423cffc8 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -7549,9 +7549,10 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { } #[derive(serde::Deserialize)] - #[serde(tag = "type", rename_all = "snake_case")] + #[serde(tag = "type")] enum Citation { - CharLocation { + #[serde(rename = "char_location")] + Char { cited_text: String, document_index: i64, document_title: Option, @@ -7559,7 +7560,8 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { start_char_index: i64, end_char_index: i64, }, - PageLocation { + #[serde(rename = "page_location")] + Page { cited_text: String, document_index: i64, document_title: Option, @@ -7567,7 +7569,8 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { start_page_number: i64, end_page_number: i64, }, - ContentBlockLocation { + #[serde(rename = "content_block_location")] + ContentBlock { cited_text: String, document_index: i64, document_title: Option, @@ -7575,13 +7578,15 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { start_block_index: i64, end_block_index: i64, }, - WebSearchResultLocation { + #[serde(rename = "web_search_result_location")] + WebSearchResult { cited_text: String, encrypted_index: String, title: Option, url: String, }, - SearchResultLocation { + #[serde(rename = "search_result_location")] + SearchResult { cited_text: String, source: String, title: Option, @@ -7659,7 +7664,7 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { let body: Body = serde_json::from_value(wire).expect("representative Anthropic 200 wire"); let citations = body.content[0].citations.as_ref().unwrap(); match &citations[0] { - Citation::CharLocation { + Citation::Char { cited_text, document_index, document_title, @@ -7677,7 +7682,7 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { _ => panic!("expected char_location citation"), } match &citations[1] { - Citation::PageLocation { + Citation::Page { cited_text, document_index, document_title, @@ -7695,7 +7700,7 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { _ => panic!("expected page_location citation"), } match &citations[2] { - Citation::ContentBlockLocation { + Citation::ContentBlock { cited_text, document_index, document_title, @@ -7713,7 +7718,7 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { _ => panic!("expected content_block_location citation"), } match &citations[3] { - Citation::WebSearchResultLocation { + Citation::WebSearchResult { cited_text, encrypted_index, title, @@ -7727,7 +7732,7 @@ fn anthropic_messages_200_residual_fields_round_trip_representative_wire() { _ => panic!("expected web_search_result_location citation"), } match &citations[4] { - Citation::SearchResultLocation { + Citation::SearchResult { cited_text, source, title, diff --git a/src/v3/compiler/tests/integration.rs b/src/v3/compiler/tests/integration.rs index 568829db96d..dfc63286fcf 100644 --- a/src/v3/compiler/tests/integration.rs +++ b/src/v3/compiler/tests/integration.rs @@ -215,6 +215,8 @@ mod t_demo_fixture_test { const FIXTURE: &str = "src/v3/compiler/tests/t_demo/t_demo_fixtures.dag"; + static T_DEMO_FIXTURE_DAG: OnceLock = OnceLock::new(); + /// 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 = 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"; @@ -229,8 +231,6 @@ mod t_demo_fixture_test { cached_compile_to_dag(source, FIXTURE) } - static T_DEMO_FIXTURE_DAG: OnceLock = OnceLock::new(); - fn cached_t_demo_fixture_dag() -> &'static Dag { T_DEMO_FIXTURE_DAG.get_or_init(|| compile_fixture(&fixture_source())) }