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
40 changes: 40 additions & 0 deletions .claude/board/EPIPHANIES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
## E-A-FEATURE-CONDITIONAL-CLASSID-SILENTLY-EMPTIED-A-FIXTURE-1 (2026-08-05, measured)

**A test that hardcodes a classid the domain now selects BY FEATURE does not
fail loudly — it runs every assertion against an empty projection.** Found by
finally running `lance-graph-callcenter` under `--features query`, which no
`-p` sweep and no CI tier had exercised.

**The mechanism, in three links.** (1) `soa_graph::OSINT_GOTHAM.classid` is
`OSINT_GOTHAM_CLASSID`, which is `NodeGuid::CLASSID_OSINT_V3` (`0x0701_1000`)
under the default `guid-v3-tail` and only falls back to the V1
`NodeGuid::CLASSID_OSINT` (`0x0700_0000`) with the feature off. (2)
`project_snapshot` filters `r.key.classid() == domain.classid` — the codex-P1
guard that stops a mixed-class board leaking other domains' rows. (3) The
`graph_table` fixture minted its rows with the V1 constant spelled literally.
So in a DEFAULT build the filter matched **zero of two rows**, and the test
compared 0 against 4.

**The second link, which the first one hides.** Fixing only the classid is not
enough: once the classid is V3, `family_of` dispatches through `family_v2()`,
so a `NodeGuid::new` key (V1 tail, `family:u24` at bytes 10..13) would carry the
family in the wrong bits even after the filter passed. The fixture had to move
to `mint_for(classid_read_mode(c).tail_variant, …)` — which is what the CANON
already requires of every new mint, and exactly the `ISS-V1-TAIL-RESIDUE` class.
A fixture that reads BOTH the classid and the tail variant off the domain is
correct under either feature setting; one that encodes either is a time bomb.

**Why it survived.** Not a DataFusion-54 regression — `num_rows() == 0` is
decided before DataFusion is involved. It is V1→V3 migration residue that no
gate ran: the failing pair only surfaces with a feature combination outside the
default sweep. This is the SECOND instance this session of the same shape
(the first: `vsa_udfs` / `transcode::ontology_table` returning clippy EXIT=0
while never compiling, both behind `query` / `query-lite`). The generalization
worth keeping: **a feature-gated module is not covered by a green run that
never compiled it, and a feature-CONDITIONAL constant is not pinned by a test
that spells one of its branches.**

**Fixed:** `crates/lance-graph-callcenter/src/graph_table.rs` — 211/211 green
under `--features query`. **Not fixed:** nothing yet runs that feature in CI, so
the coverage hole that hid this is still open.

## E-LANCE-IS-UPSTREAM-AUTHORITATIVE-1 (2026-08-05, operator-ruled — corrects a P0 in `CLAUDE.md`)

**The lance family is consumed from crates.io upstream and NEVER from a fork —
Expand Down
33 changes: 30 additions & 3 deletions crates/lance-graph-callcenter/src/graph_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,37 @@ pub fn register_graph(
#[cfg(test)]
mod tests {
use super::*;
use lance_graph_contract::canonical_node::{EdgeBlock, NodeRow};
use lance_graph_contract::canonical_node::{classid_read_mode, EdgeBlock, NodeRow};
use lance_graph_contract::soa_graph::{project_snapshot, OSINT_GOTHAM};
use lance_graph_contract::NodeGuid;

/// Mint an OSINT member key the way the CANON requires: through
/// `mint_for(classid_read_mode(c).tail_variant, …)`, with the classid taken
/// from the DOMAIN rather than hardcoded.
///
/// Both halves matter and both were wrong here before. `OSINT_GOTHAM.classid`
/// is `CLASSID_OSINT_V3` under the default `guid-v3-tail` and only falls back
/// to the V1 `CLASSID_OSINT` with the feature off; pinning the V1 constant
/// made `project_snapshot`'s `classid == domain.classid` filter match ZERO
/// rows in a default build, so every assertion below ran against an empty
/// snapshot. And once the classid is V3, `family_of` reads the tail through
/// `family_v2()` — so a `NodeGuid::new` (V1 tail) key would carry the family
/// in the wrong bits even after the filter passed. Reading both the classid
/// and the tail variant off the domain keeps the fixture correct under either
/// feature setting instead of encoding one of them.
fn osint_key(heel: u16, family: u32, identity: u32) -> NodeGuid {
NodeGuid::mint_for(
classid_read_mode(OSINT_GOTHAM.classid).tail_variant,
OSINT_GOTHAM.classid,
heel,
0,
0,
0,
family,
identity,
)
}

/// Two OSINT members in families 0xA, 0xB; the family-0xA member carries an
/// out-of-family adapter byte 0x0B → family 0xB. project_snapshot →
/// GraphSnapshot → arrow tables. End-to-end head → DataFusion.
Expand All @@ -127,12 +154,12 @@ mod tests {
a_edges.out_family[0] = 0x0B;
let rows = [
NodeRow {
key: NodeGuid::new(NodeGuid::CLASSID_OSINT, 1, 0, 0, 0xA, 1),
key: osint_key(1, 0xA, 1),
edges: a_edges,
value: [0u8; 480],
},
NodeRow {
key: NodeGuid::new(NodeGuid::CLASSID_OSINT, 2, 0, 0, 0xB, 1),
key: osint_key(2, 0xB, 1),
edges: EdgeBlock::default(),
value: [0u8; 480],
},
Expand Down
Loading