From 91b3d5412ef24cb07fced81fb8369c0c97e94682 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 21:17:59 +0000 Subject: [PATCH 1/2] lance-graph-r2il: production alias views for the polyfill lens (D-DT64-7 L4) Each POLYFILL word now records which alias is its SQL and which its Quack name (sql_at, quack_at index into the existing aliases, so no name is spelled twice). FrozenWord gains name_of, name_in and is_alias. PolyfillView is a ClassView answering 0xFFFF with one label per position in R2IL, SQL or Quack; the predicate IRI names the word, the label the language. WithPolyfill puts it over a consumer's view, answering 0xFFFF and delegating every other concept. The binding path and the 0xC401 reading are unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF --- crates/lance-graph-r2il/src/polyfill.rs | 215 +++++++++++++-- .../tests/integration/main.rs | 1 + .../tests/integration/polyfill_views.rs | 252 ++++++++++++++++++ 3 files changed, 451 insertions(+), 17 deletions(-) create mode 100644 crates/lance-graph-r2il/tests/integration/polyfill_views.rs diff --git a/crates/lance-graph-r2il/src/polyfill.rs b/crates/lance-graph-r2il/src/polyfill.rs index 21751e2a7..52a835b37 100644 --- a/crates/lance-graph-r2il/src/polyfill.rs +++ b/crates/lance-graph-r2il/src/polyfill.rs @@ -21,7 +21,9 @@ //! order. The opcode, arity and R2IL name of each entry are checked against //! OGAR's `R2ILVocabulary` by test, not at run time. +use lance_graph_contract::class_view::{ClassId, ClassView}; use lance_graph_contract::ogar_codebook::compose_classid; +use lance_graph_contract::ontology::{DisplayTemplate, FieldRef}; use ogar_loco::FnIndex; use ogar_r2il::{ALL, ANY, KEY_RUNS, MAX, MIN, SUM}; @@ -46,38 +48,119 @@ pub struct FrozenWord { /// Every name a view may give this position. The first is the R2IL /// opcode name. pub aliases: &'static [&'static str], + /// Which alias is this word's SQL name, if SQL has one. + pub sql_at: Option, + /// Which alias is this word's Quack name, if Quack has one. + pub quack_at: Option, } -const fn w(opcode: FnIndex, arity: u8, aliases: &'static [&'static str]) -> FrozenWord { +/// A language whose names a view gives the polyfill positions. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum AliasLanguage { + /// OGAR's R2IL opcode names. + R2il, + /// SQL keywords and operators. + Sql, + /// `lance-graph-quack` variant names (`Agg::*`, `Cmp::*`, `Filter::*`). + Quack, +} + +impl FrozenWord { + /// This word's name in `lang`, if that language has one. + #[must_use] + pub fn name_of(&self, lang: AliasLanguage) -> Option<&'static str> { + let at = match lang { + AliasLanguage::R2il => Some(0), + AliasLanguage::Sql => self.sql_at, + AliasLanguage::Quack => self.quack_at, + }; + at.and_then(|i| self.aliases.get(usize::from(i)).copied()) + } + + /// This word's name in `lang`, or its R2IL name where `lang` has none, + /// so a view always holds one label per position. + #[must_use] + pub fn name_in(&self, lang: AliasLanguage) -> &'static str { + self.name_of(lang).unwrap_or(self.aliases[0]) + } + + /// Whether `label` is one of this word's names. + #[must_use] + pub fn is_alias(&self, label: &str) -> bool { + self.aliases.contains(&label) + } +} + +const fn w( + opcode: FnIndex, + arity: u8, + aliases: &'static [&'static str], + sql_at: Option, + quack_at: Option, +) -> FrozenWord { FrozenWord { opcode, arity, aliases, + sql_at, + quack_at, } } /// The polyfill lens, by position. pub const POLYFILL: [FrozenWord; 17] = [ - w(INT_ADD, 2, &["IntAdd", "+"]), - w(INT_SUB, 2, &["IntSub", "-"]), - w(INT_MULT, 2, &["IntMult", "*"]), - w(INT_S_DIV, 2, &["IntSDiv", "/"]), - w(INT_EQUAL, 2, &["IntEqual", "=", "Cmp::EqI32", "Cmp::EqU32"]), - w(INT_S_LESS, 2, &["IntSLess", "<", "Cmp::LtI32"]), - w(INT_AND, 2, &["IntAnd", "AND", "Filter::and"]), - w(INT_OR, 2, &["IntOr", "OR", "Filter::or"]), - w(INT_XOR, 2, &["IntXor", "XOR"]), - w(INT_NOT, 1, &["IntNot", "NOT", "Filter::negate"]), - w(POP_COUNT, 1, &["PopCount", "COUNT", "Agg::Count"]), - w(SUM, 2, &["SUM", "Agg::SumI32"]), - w(MIN, 2, &["MIN", "Agg::MinI32"]), - w(MAX, 2, &["MAX", "Agg::MaxI32"]), - w(ANY, 1, &["ANY", "EXISTS", "Agg::Any"]), - w(ALL, 1, &["ALL", "Agg::All"]), + w(INT_ADD, 2, &["IntAdd", "+"], Some(1), None), + w(INT_SUB, 2, &["IntSub", "-"], Some(1), None), + w(INT_MULT, 2, &["IntMult", "*"], Some(1), None), + w(INT_S_DIV, 2, &["IntSDiv", "/"], Some(1), None), + w( + INT_EQUAL, + 2, + &["IntEqual", "=", "Cmp::EqI32", "Cmp::EqU32"], + Some(1), + Some(2), + ), + w( + INT_S_LESS, + 2, + &["IntSLess", "<", "Cmp::LtI32"], + Some(1), + Some(2), + ), + w( + INT_AND, + 2, + &["IntAnd", "AND", "Filter::and"], + Some(1), + Some(2), + ), + w(INT_OR, 2, &["IntOr", "OR", "Filter::or"], Some(1), Some(2)), + w(INT_XOR, 2, &["IntXor", "XOR"], Some(1), None), + w( + INT_NOT, + 1, + &["IntNot", "NOT", "Filter::negate"], + Some(1), + Some(2), + ), + w( + POP_COUNT, + 1, + &["PopCount", "COUNT", "Agg::Count"], + Some(1), + Some(2), + ), + w(SUM, 2, &["SUM", "Agg::SumI32"], None, Some(1)), + w(MIN, 2, &["MIN", "Agg::MinI32"], None, Some(1)), + w(MAX, 2, &["MAX", "Agg::MaxI32"], None, Some(1)), + w(ANY, 1, &["ANY", "EXISTS", "Agg::Any"], Some(1), Some(2)), + w(ALL, 1, &["ALL", "Agg::All"], None, Some(1)), w( KEY_RUNS, 2, &["KEY_RUNS", "COUNT DISTINCT", "Agg::CountDistinctOrderedU32"], + Some(1), + Some(2), ), ]; @@ -100,3 +183,101 @@ pub fn position_of(label: &str) -> Option { _ => None, } } + +/// The polyfill lens's labels in one language: a [`ClassView`] that answers +/// [`HARDCODED`] with one label per [`POLYFILL`] position, and nothing else. +/// +/// Every label is an alias of its own position, so +/// [`crate::binding::prepare`] binds the same plan from every language. A +/// field's `predicate_iri` names the word, not the language +/// (`lg:polyfill:f000/`); only the label changes. A position with +/// no name in the language is labelled with its R2IL name. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PolyfillView { + lang: AliasLanguage, + labels: Vec, +} + +impl PolyfillView { + /// The view of the polyfill lens in `lang`. + #[must_use] + pub fn new(lang: AliasLanguage) -> Self { + let labels = POLYFILL + .iter() + .map(|w| { + FieldRef::new( + format!("lg:polyfill:f000/{}", w.aliases[0]), + w.name_in(lang), + ) + }) + .collect(); + Self { lang, labels } + } + + /// The language this view labels the positions in. + #[must_use] + pub fn language(&self) -> AliasLanguage { + self.lang + } +} + +impl ClassView for PolyfillView { + fn fields(&self, class: ClassId) -> &[FieldRef] { + if class == HARDCODED { + &self.labels + } else { + &[] + } + } + fn template(&self, _class: ClassId) -> DisplayTemplate { + DisplayTemplate::Detail + } + fn dolce_category_id(&self, _class: ClassId) -> u8 { + 0 + } +} + +/// A consumer's [`ClassView`] with [`HARDCODED`] answered by a +/// [`PolyfillView`]: every other concept, its template and its DOLCE +/// category, come from the consumer's view unchanged. The consumer's own +/// labels for [`HARDCODED`], if any, are not consulted. +/// +/// This routes one concept and checks nothing else; whether the caller's +/// classes are activated is not this adapter's question (D-DT64-7 L3). +#[derive(Debug, Clone, Copy)] +pub struct WithPolyfill<'a, V: ?Sized> { + inner: &'a V, + polyfill: &'a PolyfillView, +} + +impl<'a, V: ClassView + ?Sized> WithPolyfill<'a, V> { + /// `inner` with [`HARDCODED`] answered by `polyfill`. + #[must_use] + pub fn new(inner: &'a V, polyfill: &'a PolyfillView) -> Self { + Self { inner, polyfill } + } +} + +impl ClassView for WithPolyfill<'_, V> { + fn fields(&self, class: ClassId) -> &[FieldRef] { + if class == HARDCODED { + self.polyfill.fields(class) + } else { + self.inner.fields(class) + } + } + fn template(&self, class: ClassId) -> DisplayTemplate { + if class == HARDCODED { + self.polyfill.template(class) + } else { + self.inner.template(class) + } + } + fn dolce_category_id(&self, class: ClassId) -> u8 { + if class == HARDCODED { + self.polyfill.dolce_category_id(class) + } else { + self.inner.dolce_category_id(class) + } + } +} diff --git a/crates/lance-graph-r2il/tests/integration/main.rs b/crates/lance-graph-r2il/tests/integration/main.rs index ae0287139..84844de87 100644 --- a/crates/lance-graph-r2il/tests/integration/main.rs +++ b/crates/lance-graph-r2il/tests/integration/main.rs @@ -4,3 +4,4 @@ pub mod binding; pub mod binding_native; pub mod polyfill; +pub mod polyfill_views; diff --git a/crates/lance-graph-r2il/tests/integration/polyfill_views.rs b/crates/lance-graph-r2il/tests/integration/polyfill_views.rs new file mode 100644 index 000000000..f28bdb28c --- /dev/null +++ b/crates/lance-graph-r2il/tests/integration/polyfill_views.rs @@ -0,0 +1,252 @@ +//! The production alias views of the polyfill lens (D-DT64-7 L4): one +//! `ClassView` per language, derived from `POLYFILL`, and an adapter that +//! puts one over a consumer's own view. + +use lance_graph_contract::class_view::{ClassId, ClassView, WideFieldMask}; +use lance_graph_contract::ontology::{DisplayTemplate, FieldRef}; +use lance_graph_contract::set_rules::{Population, Truth}; +use lance_graph_dt64::dr::{Focus, FrameRevisions, FrameStore, Guards, Scope}; +use lance_graph_dt64::{ + AlgebraRef, Arg, BindStore, ClassSchema, Effect, Extent, MethodBinding, MethodId, MethodRef, + SchemaRev, SigRev, ValueDemand, +}; +use lance_graph_r2il::binding::{prepare, ExecRefusal, Prepared, R2ilLens, Resolution}; +use lance_graph_r2il::polyfill::{ + polyfill_arities, position_of, AliasLanguage, PolyfillView, WithPolyfill, HARDCODED, POLYFILL, + POLYFILL_LENS, +}; +use ogar_loco::Vocabulary; +use ogar_r2il::R2ILVocabulary; + +const LANGS: [AliasLanguage; 3] = [ + AliasLanguage::R2il, + AliasLanguage::Sql, + AliasLanguage::Quack, +]; + +// ----------------------------------------------------- the views themselves + +#[test] +fn each_language_view_labels_every_position_with_its_own_name() { + for lang in LANGS { + let v = PolyfillView::new(lang); + let fields = v.fields(HARDCODED); + assert_eq!(fields.len(), POLYFILL.len(), "{lang:?}: one label per word"); + for (p, w) in POLYFILL.iter().enumerate() { + let label = fields[p].label.as_str(); + assert_eq!(label, w.name_in(lang), "{lang:?} position {p}"); + assert!(w.is_alias(label), "{lang:?} position {p}: {label:?}"); + assert_eq!( + position_of(label), + u8::try_from(p).ok(), + "{lang:?}: {label:?} names exactly this position" + ); + } + } +} + +#[test] +fn the_word_identity_is_the_same_in_every_language() { + let views: Vec<_> = LANGS.into_iter().map(PolyfillView::new).collect(); + for p in 0..POLYFILL.len() { + let iris: Vec<&str> = views + .iter() + .map(|v| v.fields(HARDCODED)[p].predicate_iri.as_str()) + .collect(); + assert!(iris.iter().all(|i| *i == iris[0]), "position {p}: {iris:?}"); + } + // ...while the labels differ where the languages differ. + let lt = position_of("IntSLess").unwrap() as usize; + let labels: Vec<&str> = views + .iter() + .map(|v| v.fields(HARDCODED)[lt].label.as_str()) + .collect(); + assert_eq!(labels, ["IntSLess", "<", "Cmp::LtI32"]); +} + +#[test] +fn each_language_names_come_from_the_table_not_a_spelling_rule() { + for w in &POLYFILL { + assert_eq!(w.name_in(AliasLanguage::R2il), w.aliases[0]); + assert_eq!( + Some(w.name_in(AliasLanguage::R2il)), + R2ILVocabulary.name(w.opcode) + ); + for lang in [AliasLanguage::Sql, AliasLanguage::Quack] { + match w.name_of(lang) { + Some(n) => assert!(w.aliases[1..].contains(&n), "{n:?}"), + // No name in that language: the view falls back to the + // R2IL name, so the basis keeps one label per position. + None => assert_eq!(w.name_in(lang), w.aliases[0]), + } + } + } + // SUM has no SQL alias: SQL's SUM is NULL on an empty selection, + // this word is 0 (polyfill module doc). + let sum = &POLYFILL[position_of("SUM").unwrap() as usize]; + assert_eq!(sum.name_of(AliasLanguage::Sql), None); + let lt = &POLYFILL[position_of("IntSLess").unwrap() as usize]; + assert_eq!(lt.name_of(AliasLanguage::Sql), Some("<")); + assert_eq!(lt.name_of(AliasLanguage::Quack), Some("Cmp::LtI32")); +} + +#[test] +fn a_polyfill_view_answers_only_the_hardcoded_concept() { + let v = PolyfillView::new(AliasLanguage::Sql); + assert!(v.fields(0x7F0B).is_empty()); + assert_eq!(v.field_count(HARDCODED), POLYFILL.len()); +} + +// --------------------------------------- over a consumer view, through prepare + +const CLASS: u32 = 0x7F0B_0001; +const CLASS_VIEW: ClassId = 0x7F0B; +const REV: SchemaRev = SchemaRev(1); +const POSITION: u16 = 3; + +/// A consumer's own view: its class, and a stale label set for `0xFFFF` +/// that the adapter must hide. +struct Consumer { + class: Vec, + stale: Vec, +} + +impl Consumer { + fn new() -> Self { + Self { + class: ["a", "b", "k", "m", "s"] + .iter() + .map(|l| FieldRef::new(format!("lab:class/{l}"), *l)) + .collect(), + stale: vec![FieldRef::new("lab:stale", "MIN")], + } + } +} + +impl ClassView for Consumer { + fn fields(&self, class: ClassId) -> &[FieldRef] { + match class { + CLASS_VIEW => &self.class, + HARDCODED => &self.stale, + _ => &[], + } + } + fn template(&self, _class: ClassId) -> DisplayTemplate { + DisplayTemplate::Detail + } + fn dolce_category_id(&self, _class: ClassId) -> u8 { + 7 + } +} + +fn store() -> (BindStore, lance_graph_dt64::RouteVersion) { + let mut s = BindStore::new(); + s.declare_algebra(POLYFILL_LENS, REV, Extent::DR64_CUBE, polyfill_arities()) + .unwrap(); + let word = |name: &str| AlgebraRef { + lens: POLYFILL_LENS, + word: position_of(name).unwrap(), + }; + s.register( + CLASS, + ClassSchema { + schema_rev: REV, + field_count: 5, + extent: Extent::DR64_CUBE, + }, + vec![MethodBinding { + id: MethodId(1), + sig_rev: SigRev(1), + name: "sum_below".into(), + on: WideFieldMask::from_positions(&[0, 1]), + when: None, + reads: WideFieldMask::from_positions(&[0, 1]), + effects: vec![ + Effect { + target: 3, + algebra: word("IntSLess"), + args: vec![Arg::Field(0), Arg::Const(5)], + }, + Effect { + target: 4, + algebra: word("SUM"), + args: vec![Arg::Field(3), Arg::Field(1)], + }, + ], + population: Population::Distinct, + truth: Truth::TwoValued, + demand: ValueDemand::Values, + }], + ) + .unwrap(); + let v = s.route(POSITION, CLASS).unwrap(); + (s, v) +} + +fn prep(view: &V) -> Result { + let (s, version) = store(); + let frames = FrameStore::new(FrameRevisions { + source: 1, + relation_map: 1, + coordinates: 1, + }); + let now = (Focus { revision: 1 }, Scope { id: 1 }); + let r = MethodRef { + class: CLASS, + method: MethodId(1), + sig_rev: SigRev(1), + guard: None, + }; + let g = Guards { + frame: frames.seal(), + focus: now.0, + scope: now.1, + }; + prepare( + &s, + view, + R2ilLens { + lens: POLYFILL_LENS, + schema_rev: REV, + }, + &Resolution { + method: &r, + schema_rev: REV, + route: (version, POSITION), + guards: &g, + }, + &frames, + now, + ) +} + +#[test] +fn the_adapter_binds_the_same_plan_in_every_language() { + let consumer = Consumer::new(); + let plans: Vec = LANGS + .into_iter() + .map(|lang| { + let pv = PolyfillView::new(lang); + prep(&WithPolyfill::new(&consumer, &pv)).expect("prepares") + }) + .collect(); + for p in &plans[1..] { + assert_eq!(p.steps, plans[0].steps); + assert_eq!(p.plan_id, plans[0].plan_id); + } +} + +#[test] +fn the_adapter_hides_the_consumers_own_hardcoded_labels() { + let consumer = Consumer::new(); + // Twin: the consumer's view alone carries a one-label basis for 0xFFFF, + // so the lens's 17-word basis does not match it. + assert!(matches!(prep(&consumer), Err(ExecRefusal::Binding(_)))); + let pv = PolyfillView::new(AliasLanguage::Quack); + let both = WithPolyfill::new(&consumer, &pv); + assert_eq!(both.fields(HARDCODED).len(), POLYFILL.len()); + // Every other concept is the consumer's, including template and DOLCE. + assert_eq!(both.fields(CLASS_VIEW), consumer.fields(CLASS_VIEW)); + assert_eq!(both.template(CLASS_VIEW), DisplayTemplate::Detail); + assert_eq!(both.dolce_category_id(CLASS_VIEW), 7); +} From aac42f7053abb9568d85bdb616f2b81f01f97c96 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 21:18:31 +0000 Subject: [PATCH 2/2] board: L4 alias views entry Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF --- .../entries/2026-10-31-polyfill-alias-views-l4.md | 10 ++++++++++ .claude/board/entries/README.md | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 .claude/board/entries/2026-10-31-polyfill-alias-views-l4.md diff --git a/.claude/board/entries/2026-10-31-polyfill-alias-views-l4.md b/.claude/board/entries/2026-10-31-polyfill-alias-views-l4.md new file mode 100644 index 000000000..019d5acc9 --- /dev/null +++ b/.claude/board/entries/2026-10-31-polyfill-alias-views-l4.md @@ -0,0 +1,10 @@ +# D-DT64-7 L4: production alias views for the polyfill lens — 2026-10-31 + +**Status:** MEASURED (`crates/lance-graph-r2il/tests/integration/polyfill_views.rs`). First step of the execution order in plan §1d. + +- Each `POLYFILL` word records which of its existing aliases is its SQL name and which its Quack name (`sql_at`, `quack_at`); no name is spelled twice and no spelling rule picks the language. `FrozenWord::{name_of, name_in, is_alias}`. +- `PolyfillView::new(AliasLanguage)` answers `0xFFFF` with one label per position. The `predicate_iri` names the word (`lg:polyfill:f000/`), the label the language; a position with no name in that language carries its R2IL name (SQL: `SUM`, `MIN`, `MAX`, `ALL`, where SQL's empty-selection `NULL` differs). +- `WithPolyfill::new(&consumer, &view)` answers `0xFFFF` from the polyfill view and delegates every other concept, template and DOLCE category to the consumer's view. It checks no activation (L3). +- Measured: R2IL, SQL and Quack views over the same consumer view bind the same steps and plan id; the consumer's own stale `0xFFFF` labels are refused alone and hidden behind the adapter. +- Disable runs, all red: SQL reading the Quack index (2 fail), one wrong index (2), no R2IL fallback (3), the polyfill view answering every concept (1), the adapter not routing `0xFFFF` (2), a per-language IRI (1), the adapter dropping the consumer's DOLCE category (1). +- Unchanged: `binding.rs`, the `0xC401` reading, the 9 existing polyfill tests. diff --git a/.claude/board/entries/README.md b/.claude/board/entries/README.md index 747048ea3..077152e62 100644 --- a/.claude/board/entries/README.md +++ b/.claude/board/entries/README.md @@ -25,7 +25,7 @@ index row, (3) no duplicate entry id. Checks 1 and 2 are deliberately opposite directions; the stranding this convention prevents shows up in exactly one of them, never both. -534 entries, 2026-08-06 .. 2026-10-31. +535 entries, 2026-08-06 .. 2026-10-31. | date | entry id | finding | file | |---|---|---|---| @@ -33,6 +33,7 @@ exactly one of them, never both. | 2026-10-31 | `r1-r2il-binding-reading` | | [2026-10-31-r1-r2il-binding-reading.md](2026-10-31-r1-r2il-binding-reading.md) | | 2026-10-31 | `r1-native-prepared-successor` | | [2026-10-31-r1-native-prepared-successor.md](2026-10-31-r1-native-prepared-successor.md) | | 2026-10-31 | `polyfill-positional-lens` | | [2026-10-31-polyfill-positional-lens.md](2026-10-31-polyfill-positional-lens.md) | +| 2026-10-31 | `D-DT64-7` | | [2026-10-31-polyfill-alias-views-l4.md](2026-10-31-polyfill-alias-views-l4.md) | | 2026-10-31 | `ogar-behavior-probe-p2-p3-p9` | | [2026-10-31-ogar-behavior-probe-p2-p3-p9.md](2026-10-31-ogar-behavior-probe-p2-p3-p9.md) | | 2026-10-31 | `D-SAG-6` | | [2026-10-31-kythe-bridge-ra-facts.md](2026-10-31-kythe-bridge-ra-facts.md) | | 2026-10-31 | `D-XLOG-NATIVE-6` | | [2026-10-31-d-xlog-native-6-ndarray-simd-execution.md](2026-10-31-d-xlog-native-6-ndarray-simd-execution.md) |