From 938397295da001ecd49ed84345a08e79aea07aed Mon Sep 17 00:00:00 2001 From: claude Date: Fri, 24 Jul 2026 16:32:59 +0200 Subject: [PATCH] refactor(aura-std, aura-runner): retire the orphaned FoldSchema table Review finding on the #332 fix: rendering --folds from the fold-registry roster removed fold_vocabulary()/FoldSchema's last production consumer, leaving a second, unsurfaced source of fold docs whose wording had already diverged from the registry. The table and its two tests are gone; the discipline they carried moves onto the surviving surface: the registry tests now doc-gate every roster entry (C29 entry seam) and pin the bind/output prose inside each doc line against the entry's executable binds_at/output rules, so the roster cannot drift from what the wiring enforces. refs #332 --- crates/aura-runner/src/tap_plan.rs | 58 ++++++++++++++++++++++++++ crates/aura-std/src/lib.rs | 2 +- crates/aura-std/src/tap_fold.rs | 67 ------------------------------ 3 files changed, 59 insertions(+), 68 deletions(-) diff --git a/crates/aura-runner/src/tap_plan.rs b/crates/aura-runner/src/tap_plan.rs index 4f15e47..4646f16 100644 --- a/crates/aura-runner/src/tap_plan.rs +++ b/crates/aura-runner/src/tap_plan.rs @@ -526,6 +526,64 @@ mod tests { assert!(r.roster().iter().all(|(_, doc)| !doc.is_empty()), "every entry documents itself"); } + /// C29 entry seam for the registry roster: every entry ships a gate-clean + /// one-line meaning, and the bind/output prose inside it matches the + /// entry's executable rules — the drift-pin the retired aura-std + /// `fold_vocabulary` table carried, moved here with the surface (#332). + #[test] + fn roster_docs_pass_the_doc_gate_and_match_the_executable_rules() { + let r = FoldRegistry::core(); + for entry in r.entries.values() { + aura_core::doc_gate(entry.label, entry.doc) + .unwrap_or_else(|f| panic!("fold {} doc fails the gate: {f:?}", entry.label)); + if entry.doc.contains("f64 taps") { + assert!( + (entry.binds_at)(ScalarKind::F64) && !(entry.binds_at)(ScalarKind::I64), + "{} claims f64-only but binds wider", + entry.label + ); + } else { + assert!( + entry.doc.contains("any kind"), + "{}: bind prose must be 'f64 taps' or 'any kind': {}", + entry.label, + entry.doc + ); + assert!( + (entry.binds_at)(ScalarKind::I64) && (entry.binds_at)(ScalarKind::Bool), + "{} claims any-kind but refuses a kind", + entry.label + ); + } + if entry.doc.contains("i64 row") { + assert!( + matches!((entry.output)(ScalarKind::F64), FoldOutput::Row(ScalarKind::I64)), + "{} claims an i64 row but outputs otherwise", + entry.label + ); + } else if entry.doc.contains("f64 row") { + assert!( + matches!((entry.output)(ScalarKind::F64), FoldOutput::Row(ScalarKind::F64)), + "{} claims an f64 row but outputs otherwise", + entry.label + ); + } else if entry.doc.contains("kind-preserving row") { + assert!( + matches!((entry.output)(ScalarKind::F64), FoldOutput::Row(ScalarKind::F64)) + && matches!((entry.output)(ScalarKind::I64), FoldOutput::Row(ScalarKind::I64)), + "{} claims kind-preserving but outputs otherwise", + entry.label + ); + } else { + assert!( + matches!((entry.output)(ScalarKind::F64), FoldOutput::Series), + "{}: doc names no row kind, so it must be the series entry", + entry.label + ); + } + } + } + #[test] fn unknown_label_refusal_enumerates_the_roster() { let r = FoldRegistry::core(); diff --git a/crates/aura-std/src/lib.rs b/crates/aura-std/src/lib.rs index 8792ca9..5c1d332 100644 --- a/crates/aura-std/src/lib.rs +++ b/crates/aura-std/src/lib.rs @@ -74,6 +74,6 @@ pub use sma::Sma; pub use sqrt::Sqrt; pub use sub::Sub; pub use tap_cell::newest_cell; -pub use tap_fold::{fold_binds_at, fold_output_kind, fold_vocabulary, FoldKind, FoldSchema, TapFold}; +pub use tap_fold::{fold_binds_at, fold_output_kind, FoldKind, TapFold}; pub use tap_live::TapLive; pub use when::When; diff --git a/crates/aura-std/src/tap_fold.rs b/crates/aura-std/src/tap_fold.rs index 990abc1..dd2baa1 100644 --- a/crates/aura-std/src/tap_fold.rs +++ b/crates/aura-std/src/tap_fold.rs @@ -45,32 +45,6 @@ pub fn fold_output_kind(fold: FoldKind, kind: ScalarKind) -> ScalarKind { } } -/// One fold entry's introspection row (C29): id, bind/output rules in prose, -/// one-line meaning. `fold_vocabulary` is the binary's discovery surface for -/// [`FoldKind`] (`aura graph introspect --folds`, #315); the unit tests pin -/// each row's rule prose against [`fold_binds_at`] / [`fold_output_kind`] so -/// the table cannot drift from the executable rules. -pub struct FoldSchema { - pub id: &'static str, - pub kind: FoldKind, - pub binds: &'static str, - pub out: &'static str, - pub doc: &'static str, -} - -/// The closed fold vocabulary as introspection rows, in [`FoldKind`] order. -pub fn fold_vocabulary() -> &'static [FoldSchema] { - &[ - FoldSchema { id: "Count", kind: FoldKind::Count, binds: "any tap", out: "i64", doc: "number of rows the tap recorded" }, - FoldSchema { id: "Sum", kind: FoldKind::Sum, binds: "f64 taps", out: "f64", doc: "sum of the tap's recorded values" }, - FoldSchema { id: "Mean", kind: FoldKind::Mean, binds: "f64 taps", out: "f64", doc: "arithmetic mean of the tap's recorded values" }, - FoldSchema { id: "Min", kind: FoldKind::Min, binds: "f64 taps", out: "f64", doc: "smallest recorded value" }, - FoldSchema { id: "Max", kind: FoldKind::Max, binds: "f64 taps", out: "f64", doc: "largest recorded value" }, - FoldSchema { id: "First", kind: FoldKind::First, binds: "any tap", out: "tap kind", doc: "earliest recorded value, kind-preserving" }, - FoldSchema { id: "Last", kind: FoldKind::Last, binds: "any tap", out: "tap kind", doc: "latest recorded value, kind-preserving" }, - ] -} - /// Owned accumulator for every fold kind at once (a handful of words; keeping /// it total avoids a per-kind state enum). Sequential `sum += v` matches a /// slice-driven mean's operation order, so streamed and slice `Mean` agree @@ -190,47 +164,6 @@ mod tests { use aura_core::AnyColumn; use std::sync::mpsc; - /// The vocabulary rows are prose renderings of the executable rules — - /// pin them against `fold_binds_at` / `fold_output_kind` so the - /// introspection surface cannot drift from what the engine enforces. - #[test] - fn fold_vocabulary_rows_match_the_executable_rules() { - let rows = fold_vocabulary(); - assert_eq!(rows.len(), 7, "one row per FoldKind"); - for row in rows { - let f64_only = fold_binds_at(row.kind, ScalarKind::F64) - && !fold_binds_at(row.kind, ScalarKind::I64); - match row.binds { - "f64 taps" => assert!(f64_only, "{} claims f64-only but binds wider", row.id), - "any tap" => assert!( - fold_binds_at(row.kind, ScalarKind::I64) - && fold_binds_at(row.kind, ScalarKind::Bool), - "{} claims any-tap but refuses a kind", - row.id - ), - other => panic!("unknown binds prose {other:?} on {}", row.id), - } - match row.out { - "i64" => assert_eq!(fold_output_kind(row.kind, ScalarKind::F64), ScalarKind::I64), - "f64" => assert_eq!(fold_output_kind(row.kind, ScalarKind::F64), ScalarKind::F64), - "tap kind" => { - assert_eq!(fold_output_kind(row.kind, ScalarKind::F64), ScalarKind::F64); - assert_eq!(fold_output_kind(row.kind, ScalarKind::I64), ScalarKind::I64); - } - other => panic!("unknown out prose {other:?} on {}", row.id), - } - } - } - - /// C29 entry seam: every fold row ships a gate-clean one-line meaning. - #[test] - fn fold_vocabulary_docs_pass_the_doc_gate() { - for row in fold_vocabulary() { - aura_core::doc_gate(row.id, row.doc) - .unwrap_or_else(|f| panic!("fold {} doc fails the gate: {f:?}", row.id)); - } - } - /// Drive a fold over an f64 series and return the emitted rows. fn run_f64_fold(fold: FoldKind, values: &[f64]) -> Vec<(Timestamp, Vec)> { let (tx, rx) = mpsc::channel();