Resolve a named read's offset when the graph compiles

The fold already holds the name and the read input's finished layout, so
the offset falls out there rather than at construction: `RecordLayout`
carries the resolved numbers and `set_layout` copies them into the read
slots. Constructors are untouched, and census-marker reads keep their
current installation.

A read meets the value type the name was written at, so a disagreement
between a read here and a write upstream is the same graph error as two
writes disagreeing; the one-name-one-type check now spans reads and
writes together. An absent attribute stays absent and the read serves
the forced default rather than reporting it.

`read_attribute` is the catalog's get half, typed and never `Option` at
the kernel boundary, with the name declared exactly as the write side
declares it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Dennis Kobert
2026-09-09 10:50:08 +00:00
parent fc94487d0b
commit 5eb80721dd
23 changed files with 349 additions and 69 deletions

View File

@@ -663,6 +663,7 @@ mod tests {
// pass records as lane-invariant.
let resolved = core_types::record::RecordLayout {
named_writes: Vec::new(),
named_reads: Vec::new(),
lane_invariant: u32::MAX,
..meta.resolve(inputs)
};
@@ -673,6 +674,7 @@ mod tests {
fn install_flip<N: Node<ContextImpl<'static>>>(mut node: N, layout: &Layout) -> N {
let bundle = core_types::record::RecordLayout {
named_writes: Vec::new(),
named_reads: Vec::new(),
frame_bytes: layout.frame_bytes(),
plan: Vec::new(),
layout: layout.clone(),
@@ -768,6 +770,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -806,6 +810,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -852,6 +858,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -904,6 +912,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1004,6 +1014,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0, 1],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1074,6 +1086,8 @@ mod tests {
let meta = || core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0, 1],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1150,6 +1164,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0, 1],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1196,6 +1212,8 @@ mod tests {
let meta = || core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1207,6 +1225,8 @@ mod tests {
let extend_meta = || core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0, 1],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1284,6 +1304,8 @@ mod tests {
let meta = || core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1339,6 +1361,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1556,6 +1580,7 @@ mod tests {
let mut node = MirrorNode::new(RecordSource::new(content, &layout, &layout), counting_value(true, &evals));
let resolved = core_types::record::RecordLayout {
named_writes: Vec::new(),
named_reads: Vec::new(),
lane_invariant: 0,
..mirror_layout_meta().resolve(&[Some(&layout)])
};
@@ -1636,6 +1661,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1691,6 +1718,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1803,6 +1832,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,
@@ -1931,6 +1962,8 @@ mod tests {
let meta = core_types::record::LayoutMeta {
named_writes: Vec::new(),
folded_names: Vec::new(),
named_reads: Vec::new(),
folded_read_names: Vec::new(),
sources: vec![0],
reads: vec![],
element: core_types::record::ElementSpec::Carried,