Skip to content
Merged
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
6 changes: 6 additions & 0 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# LATEST_STATE — What Just Shipped (read this FIRST)

## 2026-07-14 — branch `claude/review-medcare-rust-dt7MS` — `class_view::execute_defaults` + `ClassView::default_targets` — the Default-recipe half of the ActionDef value executor (lane-3a inc 2)

### Current Contract Inventory — new entry

- **`class_view::execute_defaults(targets, present, store, apply_default)`** (NEW free fn next to `execute_compute_dag`) + **`ClassView::default_targets(class) -> &[u8]`** (NEW default trait method, zero-fallback `&[]`, next to `compute_dag`). The **Default-recipe** (write-if-blank, `RecipeCentroid::Default` — the C# `if (field == null) field = new …` lazy-init idiom, 56 methods in the MedCare corpus) execution primitive: fires `apply_default(store, t)` for each target whose presence bit is CLEAR, in slice order; skips present AND already-fired positions (duplicate-safe — after a default fires the field IS populated; pins the C# `GetOrCreateChartPanel` init-only-on-create quirk, devcomponent_chart.cs:161-180); abort-at-target reusing `ExecuteComputeError::Compute` (`Cyclic` unreachable — defaults have no dependency order; a default reading a computed field is a Compute recipe). **Presence gate = `WideFieldMask`** (not `FieldMask`): every u8 position addressable, no 64-field ceiling — the wide-mask lesson the a2ui screen-addressing #205 correction paid for, applied at birth. Phase rule documented (not interleaved): defaults run BEFORE `execute_compute_dag`; the caller folds the fired list into its presence mask. One more brick, not a parallel path (the `screens_reachable_from` precedent): existing mask, existing error, same abort semantics as the Compute half. +7 unit tests (slice-order fire, present-skip, abort-keeps-earlier, empty-noop, wide-fire-past-64, duplicate-fires-once, hook-default-empty); 898 contract tests green; fmt + clippy clean (also carries the pending rustfmt reflow on `grammar/thinking_styles.rs` + `style_family.rs` — main was fmt-dirty on those two test files). Consumer witness lands in MedCare-rs (`chart_default_parity`, same arc).

## 2026-07-12 — branch `claude/review-claude-board-files-nhqgx1` — `contract::temporal_pov::{VersionRange, TemporalPov}` — zero-dep temporal POV range filter (operator-directed)

### Current Contract Inventory — new entry
Expand Down
8 changes: 8 additions & 0 deletions .claude/board/PR_ARC_INVENTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@
> - **Docs** — knowledge files produced (immutable)
> - **Confidence (YYYY-MM-DD):** — the ONLY mutable field

## PR (pending) — `claude/review-medcare-rust-dt7MS` — lane-3a inc 2: `execute_defaults` (Default-recipe half)

- **Added:** `class_view::execute_defaults` (fire-if-absent runner over `WideFieldMask` presence, ~40 LOC + docs); `ClassView::default_targets` (zero-fallback default trait method); 7 unit tests.
- **Locked:** (1) Default-recipe presence gate is the WIDE mask from birth — no 64-field ceiling anywhere in the Default path (a2ui #205 lesson applied preemptively). (2) `ExecuteComputeError` is the ONE error type for the value-executor phase family (defaults + recompute thread one error; `Cyclic` documented-unreachable for defaults). (3) Duplicate manifest entries fire at most once — post-fire, a position IS present (the C# GetOrCreateChartPanel init-only-on-create quirk, pinned by test). (4) Phase rule: defaults BEFORE recompute DAG; documented, not interleaved (no combined runner in inc 2). (5) The consumer trait seam (`ActionDefExecutor`, serde-shaped) STAYS in medcare-rs — the zero-dep contract carries recipe-kind execution primitives only (the inc-1 precedent, ratified reading of medcare commitment #5's "upstream executor").
- **Deferred:** Guard recipe (needs pre-write validation phase + `ClassView::constraints`, explicitly deferred since probe-excel-compute-dag-v1 Inc 0); Cascade recipe (cross-row addressing, dirty-set, reverse closure); a combined defaults-then-recompute runner; Normalize (1 corpus method — coverage worthless until Guard lands).
- **Docs:** this entry; medcare-rs side documents the corpus enumeration (56 Defaults, `DEFAULT-RECIPE-TARGETS.md`).
- **Confidence (2026-07-14):** shipped-in-PR; 898 contract tests green.

---

## #676 lance-graph: Post-#674 doc arc — E-NOBODY-WAITS-1 + VISION.md (graded AGI canon) + ancestry census + D-MTS-1 design inputs
Expand Down
208 changes: 208 additions & 0 deletions crates/lance-graph-contract/src/class_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,70 @@ pub fn execute_compute_dag<S, E>(
Ok(order)
}

/// Execute a class's **default targets** over a consumer-owned store — the
/// Default-recipe half of the ActionDef value executor (the medcare transpile
/// arc's lane-3a increment 2, following the Compute half above).
///
/// A *Default* recipe is write-if-blank (`this.Name ??= "unknown"` — the
/// `RecipeCentroid::Default` centroid): the value fires ONLY where the field
/// is not already populated. Same split of responsibilities as
/// [`execute_compute_dag`]: this function owns the *fire/skip decision*
/// (presence-gated, slice order), while `apply_default` owns *value
/// semantics* — it writes field position `t`'s default onto `store` (a
/// hand-ported default expression; never a formula invented here).
///
/// One more brick, not a parallel path (the [`screens_reachable_from`]
/// precedent): the presence gate is the existing [`WideFieldMask`] — every
/// `u8` position is addressable, so there is no 64-field ceiling to skip
/// around (the wide-mask lesson the screen-addressing charter's #205
/// correction paid for). The error is the existing [`ExecuteComputeError`]
/// so a defaults-then-recompute pipeline threads ONE error type;
/// [`ExecuteComputeError::Cyclic`] is unreachable from this function
/// (defaults have no dependency order — a default that reads another
/// computed field is a Compute recipe, not a Default).
///
/// Fire rules, in order, per target in **slice order**:
///
/// - `present.has(t)` → **skip** (the field is populated; a default never
/// overwrites);
/// - `t` already fired earlier in this call (duplicate manifest entry) →
/// **skip** (after firing, the field IS populated — a second entry sees
/// it present);
/// - otherwise → `apply_default(store, t)`; on error, abort-at-target
/// (earlier fired defaults remain written, matching
/// [`execute_compute_dag`]'s abort semantics).
///
/// Returns the fired positions, in fire order (unique). The caller folds
/// them into its presence mask (`fired.iter().fold(present, |m, &p|
/// m.with(p))`) before running [`execute_compute_dag`] — **defaults run
/// BEFORE the recompute DAG** (a recompute reads post-default inputs), the
/// phase rule this increment documents but does not interleave.
///
/// # Errors
///
/// [`ExecuteComputeError::Compute`] wrapping the consumer's error at the
/// failing target (later targets are not attempted). Never
/// [`ExecuteComputeError::Cyclic`].
pub fn execute_defaults<S, E>(
targets: &[u8],
present: &WideFieldMask,
store: &mut S,
mut apply_default: impl FnMut(&mut S, u8) -> Result<(), E>,
) -> Result<Vec<u8>, ExecuteComputeError<E>> {
let mut fired_mask = WideFieldMask::EMPTY;
let mut fired = Vec::new();
for &t in targets {
if present.has(t) || fired_mask.has(t) {
continue;
}
apply_default(store, t)
.map_err(|source| ExecuteComputeError::Compute { target: t, source })?;
fired_mask = fired_mask.with(t);
fired.push(t);
}
Ok(fired)
}

/// The class as a **meta lookup that flies above the SoA** — the resolver trait.
///
/// An implementor (in `lance-graph-ontology`, over the OGIT cache) is the
Expand Down Expand Up @@ -1089,6 +1153,23 @@ pub trait ClassView {
fn compute_dag(&self, _class: ClassId) -> &[ComputeEdge] {
&[]
}

/// The class's **default targets** — the field positions carrying a
/// write-if-blank default (the `RecipeCentroid::Default` harvest:
/// `this.Name ??= …`, the C# lazy-init `if (field == null) field = new …`
/// idiom), in declaration order. The manifest [`execute_defaults`]
/// consumes — same layering as [`compute_dag`](ClassView::compute_dag):
/// resolution metadata above the SoA, stores nothing on the row.
///
/// Default `&[]` — the zero-fallback: an unconfigured class has no
/// defaulted fields. An implementor returns a generated `const &[u8]`;
/// no build-time validation is needed (defaults are order-free and
/// duplicate-safe — [`execute_defaults`] fires each position at most
/// once). Phase rule: defaults run BEFORE the recompute DAG.
#[inline]
fn default_targets(&self, _class: ClassId) -> &[u8] {
&[]
}
}

/// One populated field to render — the late-resolved `label` + its `predicate` key.
Expand Down Expand Up @@ -1450,6 +1531,133 @@ mod tests {
assert_eq!(row, [1]);
}

// ── execute_defaults (lane-3a increment 2: the Default-recipe half) ──────

/// An empty presence mask fires every target, in SLICE order (declaration
/// order — defaults have no dependency order to reorder by).
#[test]
fn execute_defaults_fires_absent_targets_in_slice_order() {
let mut row = [0i32; 8];
let fired = execute_defaults(&[3, 1, 7], &WideFieldMask::EMPTY, &mut row, |r, t| {
r[t as usize] = 100 + i32::from(t);
Ok::<(), core::convert::Infallible>(())
})
.expect("defaults fire");
assert_eq!(fired, vec![3, 1, 7], "slice order, not sorted");
assert_eq!(row[3], 103);
assert_eq!(row[1], 101);
assert_eq!(row[7], 107);
}

/// A present field is skipped — a default never overwrites (the
/// write-if-blank contract; the C# `if (field == null)` guard).
#[test]
fn execute_defaults_skips_present_targets() {
let mut row = [0i32; 8];
row[1] = 999; // already populated
let present = WideFieldMask::from_positions(&[1]);
let fired = execute_defaults(&[3, 1, 7], &present, &mut row, |r, t| {
r[t as usize] = 100 + i32::from(t);
Ok::<(), core::convert::Infallible>(())
})
.unwrap();
assert_eq!(fired, vec![3, 7], "present target 1 not fired");
assert_eq!(row[1], 999, "populated value untouched");
}

/// A failing default aborts at its target: earlier fired defaults stay
/// written, later targets never run (matching execute_compute_dag).
#[test]
fn execute_defaults_abort_at_target_keeps_earlier_writes() {
let mut row = [0i32; 8];
let err = execute_defaults(
&[3, 1, 7],
&WideFieldMask::EMPTY,
&mut row,
|r, t| match t {
3 => {
r[3] = 103;
Ok(())
}
_ => Err("boom"),
},
)
.unwrap_err();
assert_eq!(
err,
ExecuteComputeError::Compute {
target: 1,
source: "boom"
}
);
assert_eq!(row[3], 103, "earlier default stays written");
assert_eq!(row[7], 0, "later target never ran");
}

/// Empty target manifest = nothing fired (zero-fallback, mirrors
/// `compute_dag`'s empty default).
#[test]
fn execute_defaults_empty_targets_is_noop() {
let mut row = [5i32];
let fired = execute_defaults(&[], &WideFieldMask::EMPTY, &mut row, |_, _| {
Ok::<(), core::convert::Infallible>(())
})
.unwrap();
assert!(fired.is_empty());
assert_eq!(row, [5]);
}

/// Positions past 64 fire natively — the presence gate is the WIDE mask,
/// so there is no 64-field ceiling (the wide-mask lesson the
/// screen-addressing charter's #205 correction paid for; every u8
/// position is addressable).
#[test]
fn execute_defaults_fires_wide_positions_past_64() {
let mut hits: Vec<u8> = Vec::new();
let fired = execute_defaults(&[133, 200], &WideFieldMask::EMPTY, &mut hits, |h, t| {
h.push(t);
Ok::<(), core::convert::Infallible>(())
})
.unwrap();
assert_eq!(fired, vec![133, 200], "wide positions fire");
// ...and a wide presence bit skips exactly its position.
let present = WideFieldMask::from_positions(&[133]);
let fired = execute_defaults(&[133, 200], &present, &mut hits, |h, t| {
h.push(t);
Ok::<(), core::convert::Infallible>(())
})
.unwrap();
assert_eq!(fired, vec![200], "wide present bit 133 skips");
}

/// A duplicate manifest entry fires at most once: after a default fires,
/// the field IS populated — the second entry sees it present. (The C#
/// GetOrCreateChartPanel quirk: create+init run only in the absent
/// branch; a present panel is returned untouched.)
#[test]
fn execute_defaults_duplicate_target_fires_once() {
let mut count = 0u32;
let fired = execute_defaults(&[5, 5, 5], &WideFieldMask::EMPTY, &mut count, |c, _| {
*c += 1;
Ok::<(), core::convert::Infallible>(())
})
.unwrap();
assert_eq!(fired, vec![5], "unique fire list");
assert_eq!(count, 1, "closure ran exactly once");
}

/// Default `default_targets` is the zero-fallback empty manifest (no
/// defaulted fields for an unconfigured class).
#[test]
fn default_targets_default_is_empty() {
let c = FakeClasses {
invoice: vec![],
..Default::default()
};
assert!(c.default_targets(7).is_empty());
assert!(c.default_targets(0).is_empty());
}

#[test]
fn nav_reachability_is_a_forward_closure() {
// root(0) -> orders(1) -> lines(2); root -> settings(3)
Expand Down
6 changes: 5 additions & 1 deletion crates/lance-graph-contract/src/grammar/thinking_styles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,11 @@ coverage:
("reflective", ThinkingStyle::Reflective),
("sovereign", ThinkingStyle::Sovereign),
] {
assert_eq!(parse_style_name(name).unwrap(), expected, "passthrough: {name}");
assert_eq!(
parse_style_name(name).unwrap(),
expected,
"passthrough: {name}"
);
}
assert!(parse_style_name("nonsensestyle").is_err());
}
Expand Down
11 changes: 9 additions & 2 deletions crates/lance-graph-contract/src/style_family.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ mod tests {
#[test]
fn default_runbook_round_trips_to_its_family() {
for f in StyleFamily::ALL {
assert_eq!(f.default_runbook().family(), f, "round-trip broke for {f:?}");
assert_eq!(
f.default_runbook().family(),
f,
"round-trip broke for {f:?}"
);
}
}

Expand Down Expand Up @@ -271,7 +275,10 @@ mod tests {
for (i, f) in StyleFamily::ALL.into_iter().enumerate() {
assert_eq!(StyleFamily::from_ordinal(i as u8), Some(f));
assert_eq!(StyleFamily::from_name(f.name()), Some(f));
assert_eq!(StyleFamily::from_name(&f.name().to_ascii_uppercase()), Some(f));
assert_eq!(
StyleFamily::from_name(&f.name().to_ascii_uppercase()),
Some(f)
);
}
assert_eq!(StyleFamily::from_ordinal(12), None);
assert_eq!(StyleFamily::from_name("empathetic"), None); // a runbook name, not a family
Expand Down
Loading