Catnip10
A deterministic conformance benchmark for branch-wise workflows that file values on a fixed or shared reference-branch axis. Ten tips, seventeen frozen primitive coordinates, small enough to trace completely — and structured enough to test every declared coordinate claim.
A number can be right while its coordinate is wrong
Comparative-genomics pipelines routinely place branch-associated values — rates, residuals, path lengths — into a matrix whose columns are branches of a reference tree. That only means something if a column label keeps denoting the same evolutionary object across every gene that contributes to it.
Genes differ in taxon coverage, so each gene tree is a contraction of the reference tree. Removing a tip can leave an internal node with only two neighbours; standard tree reduction then suppresses that node and merges its two incident edges into one. The merged edge can carry the exact sum of its members' lengths — the arithmetic is perfect — but the two original branches are no longer separately observable in that gene.
If a pipeline writes that merged value into a cell named after one of the two members, the number is numerically valid and the coordinate is not. Nothing crashes, no NA appears, and the error is invisible to every check that only asks whether the arithmetic is correct.
The distinction Catnip10 enforces. The composite edge {b₁,b₂} is a perfectly valid estimand — as a reduced-tree edge, or as a declared composite. What it is not is an independent value for b₁ or for b₂. Endpoint-defined paths and reduced-tree edges are legitimate native objects; the requirement only bites when values are aligned, compared, or interpreted on a shared full-tree branch axis.
The oracle: graph contraction with bookkeeping
The oracle is deliberately not a phylogenetic method. It is a small graph algorithm that computes the answer by construction, so the benchmark's truth object is exact and inspectable rather than estimated. It never looks at the audited workflow's output.
- Freeze a reference tree and enumerate its edges as primitive coordinates
B1…B17. Every edge is a discrete object; removing it induces a taxon bipartition, which is what gives the label its meaning. - For a taxon subset, delete the absent tips and repeatedly suppress every degree-2 internal vertex, merging its two incident edges. This is the standard tree-reduction operation modeled by the benchmark.
- Propagate original-edge membership through every suppression. Each surviving reduced edge carries the set of primitive edges it absorbed; a merge takes the union of the two member sets. Nothing is discarded, so provenance is never lost.
- Classify each primitive coordinate by the fate of its membership: sole member of a surviving edge →
observed; member of a surviving edge with two or more members →NA_fuse; contained in no surviving edge →NA_struct. - Emit two linked ledgers: a primitive-coordinate ledger assigning every original coordinate exactly one state, and a composite-edge ledger listing each surviving composite keyed by its member set and summed length.
Primitive identity and branch length are propagated separately: membership by set union and length by addition. Primitive-coordinate state is derived only from the final membership sets.
Input:
weighted unrooted tree G = (V,E)
primitive label p(e) and length ℓ(e) for every reference edge
retained tip set S
Initialize:
M(e) = {p(e)}
Delete all tips not in S and their incident edges.
While there exists a suppressible degree-2 internal vertex v:
let e1=(u,v), e2=(v,w)
replace e1,e2,v by e*=(u,w)
M(e*) = M(e1) ∪ M(e2)
ℓ(e*) = ℓ(e1) + ℓ(e2)
For each surviving edge e:
compute its canonical unrooted split key
record [split key, M(e), ℓ(e)]
For each primitive coordinate b:
containers = surviving edges whose member set contains b
if exactly one container exists and M(container) = {b}:
OBSERVED_PRIMITIVE
else if exactly one container exists and |M(container)| > 1:
NA_FUSE
else:
NA_STRUCT
No circular oracle. Canonical split keys are computed only after graph reduction and are used to identify and align surviving reduced edges; they do not derive pruning state. Primitive-coordinate state comes solely from graph deletion, contraction, and propagated original-edge membership.
The oracle consumes neither SplitAligner output nor participant output, package-specific branch numbering, or participant-specific mapping logic.
Historical provenance. Catnip10 grew out of an independent validation layer originally developed for the SplitAligner benchmark. That benchmark directory preserves the historical predecessor. The authoritative Catnip10 oracle specification, truth tables and composite ledgers are maintained in the current Catnip10 repository.
Because the procedure is deterministic and finite, the expected state of all 17 coordinates can be enumerated for every retained-tip subset permitted by the benchmark, in advance — no simulation, no sampling, no tolerance. For an exposed workflow with a validated adapter, disagreement with the frozen oracle is an auditable conformance mismatch.
Scope of the three states. Within this fixed-topology toy core, observed, NA_fuse and NA_struct are mutually exclusive and exhaustive. That is a property of the benchmark's design, not a claim about heterogeneous-tree workflows in general: topology-driven absence is intentionally excluded from the fixed-topology core, so these three states are not offered as a complete taxonomy for workflows outside it.
Three states, and what each one licenses
The whole audit turns on separating two kinds of missingness that pipelines habitually collapse into one. A branch that vanished and a branch that merged are not the same event, and they call for different handling downstream.
| State | What happened to the coordinate | What a value in this cell would mean |
|---|---|---|
| observed | The primitive branch survives contraction as an edge of its own; no other original edge merged into it. | Legitimate. The cell can hold an independent value for this named branch. |
| NA_fuse | The branch survives only inside a composite edge, together with at least one other original branch. The composite's length is the exact sum of its members. | Not eligible. Any number here is the composite's, not this member's. The value may be arithmetically exact and still misattributed. |
| NA_struct | The branch is structurally absent: no surviving edge contains it under this taxon subset. | Undefined. There is no evolutionary object for the cell to refer to. Note that zero is not this — zero is an observed no-change state. |
Names used in the published tables. The machine-readable truth tables write these three states as OBSERVED_PRIMITIVE, NA_FUSE and NA_STRUCT; the shorter forms used on this page and in the figures denote exactly the same states. A fourth state, NA_TOPO, is reserved in the contract for topology-driven absence and is not generated by the fixed-topology pruning core.
Why the last row matters in practice. A numeric zero in a structurally unavailable cell can pass ordinary missing-value filters and be treated downstream as an observed zero, unless coordinate state is validated explicitly. Missingness codes describe coordinate state, not software failure — telling NA_struct apart from a genuine observed zero is a coordinate-level question that numerical validation alone cannot answer.
Axis A — pruning-aware coordinate eligibility
The first validity axis asks a single question: after pruning and contraction, is a value independently eligible on the primitive full-tree coordinate it is filed under?
The pruning experiment is built so that pruning is the only thing that can explain a discrepancy within this experiment. Topology and branch lengths are fixed. There is no true rate shift, no gene-tree/species-tree discordance, no branch-length estimation error, and no species-tree uncertainty. Taxon deletion and degree-2-node suppression are the only perturbations applied here — the benchmark as a whole also contains representation controls, which vary something else entirely and are described in Axis B below.
Two prespecified deletion schedules give contrasting geometries: a progressive global sequence working inward from the display-root side, and a localized sequence concentrating deletions within one clade. Each runs eight steps including its baseline. Because the tree is small, the oracle can also enumerate the expected state of every coordinate under all subsets of the deletable tips — which is what the interactive panel below is driving.
Scope, stated plainly. This is a deterministic existence-and-mechanism design. It shows how pruning alone can separate numerical validity from coordinate eligibility, and it makes that separation testable. It is not an estimate of how often such mismatches occur in empirical datasets, and it does not by itself establish gene-level bias in any real analysis.
Axis B — representation-stable coordinate identity and availability
The second validity axis varies nothing biological at all. It asks whether the same canonical unrooted split keeps the same identity and the same declared availability when the same tree is written down a different way.
Display root. The root location used to serialize or traverse a tree representation. It is not part of the authoritative unrooted branch identity, which remains the canonical split key.
The controls are built as strict equivalents: identical tip sets, identical canonical split keys, and identical branch lengths after canonical alignment. What differs is only how the tree is written.
Native representation
- baseline serialization
- display root unchanged
The reference point every control is compared against.
Serialization / child-order control
- strict-equivalent unrooted tree
- child order changed
- display root unchanged
An irrelevant-representation negative control. Nothing that matters has changed, so nothing should move.
Display-root displacement challenge
- strict-equivalent unrooted tree
- same tips, same unrooted splits
- same split-specific lengths
- display root genuinely moved
The actual test: the serialization root sits on a different vertex while the weighted unrooted split object is untouched.
A changed Newick string is not a changed representation variable. Rewriting a tree can alter the bytes, the child order, or both, without moving the display root at all. Catnip10 therefore defines the display-root signature as the unordered partition of tip sets incident to the serialized root vertex, and independently certifies whether that signature actually changed before any participant is scored on this axis. A request to shift the display root that produces only a reordering is retained as a no-op regression control, so a benchmark run cannot quietly credit itself with a challenge it never applied.
Child-order variation is a negative control, not a predicted failure mode. Nothing on this page should be read as a claim that reordering children generally breaks workflows.
Four dispositions
Auditing a workflow is a mechanical procedure. You normalize one output layer to the adapter contract, declare that layer's exposure, and let the scorer compare it against the oracle ledgers cell by cell. The outcome is one of exactly four dispositions, and only one of them is a failure.
PASS
The workflow is exposed to the tested coordinate contract and satisfies the specified benchmark condition.
FAIL
The workflow is exposed to the tested coordinate contract and violates the specified benchmark condition.
NOT-EXPOSED
The workflow's declared native estimand does not claim the tested coordinate contract. This is a clean result, and it is not a euphemism for missing data.
UNRESOLVED
Required evidence or a valid test precondition is unavailable, so the benchmark cannot adjudicate the contract either way.
What a FAIL is about. A disposition applies to a declared claim at a specified interface, not to an entire software package. A native endpoint or path object is never assigned a primitive-axis FAIL when no primitive alignment was claimed in the first place. Adapter validation is separate again: a missing expected row is an input error, not NOT-EXPOSED.
Diagnostic localization. Not a disposition, but a use of the benchmark: when a reproducible failure exists, Catnip10 can be used to trace the first representation boundary at which coordinate identity or availability diverges.
Anonymous case study — what a conformance audit looks like
Two branch-wise workflows were run on identical pruned inputs from the global schedule, and their outputs mapped onto the frozen coordinate axis through an explicitly declared exposure. Participant identities are withheld in the public benchmark release; exact identities, versions, adapters and execution provenance are retained in a sealed archive. The two are shown here as Method A and Method B.
One result frames everything below: the native path arithmetic was exact in both workflows. Nothing here is a claim that either computes distances incorrectly. What the audit examines is where those correct numbers are filed.
This case study illustrates the pruning-eligibility axis. Representation stability is tested separately, using the strict-equivalence controls described in Axis B.
Seven progressive deletions from the display-root side. Each tree shows what the contraction does to every coordinate: red dashed where the coordinate becomes structurally absent, blue where it survives only inside a composite, black where it is unaffected.
The independent graph oracle supplies the expected state of every primitive coordinate at every step. This is the truth object the participants are scored against.
| coordinate | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reference tree | 1.464364 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step1 | NA_struct | NA_fuse | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | NA_fuse | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step2 | NA_struct | NA_fuse | NA_struct | NA_fuse | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | NA_fuse | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step3 | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_struct | NA_fuse | 0.390203 | 0.905738 | 0.446970 | 0.836004 | NA_fuse | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step4 | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_fuse | NA_struct | NA_fuse | 0.836004 | NA_fuse | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step5 | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_struct | NA_struct | NA_struct | NA_fuse | NA_fuse | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step6 | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_fuse | 0.388108 | 0.685170 | NA_fuse | 0.832916 | 0.007334 |
| main_step7 | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_fuse | NA_struct | NA_fuse | NA_fuse | 0.832916 | 0.007334 |
Method A declares a fixed shared primitive layer, so the eligibility contract applies to it. Highlighted cells are coordinate-state mismatches in this frozen benchmark configuration: either a coordinate the oracle records as independently observable came back as NA, or a complete composite-path quantity occupies a fusion-ineligible primitive cell.
| step | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reference tree | 1.464364 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step1 | NA | NA | NA | NA | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.876306 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step2 | NA | NA | NA | NA | NA | NA | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 1.822974 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step3 | NA | NA | NA | NA | NA | NA | NA | 0.905738 | 0.446970 | NA | 2.337186 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step4 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 2.337186 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step5 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.388108 | 0.685170 | NA | 0.832916 | 0.007334 |
| main_step6 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.815003 | 0.832916 | 0.007334 |
| main_step7 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
Composite-path quantities in NA_fuse cells
N_16: 0.876306 = N_12|N_16 · 1.822974 = N_13|N_12|N_16 · 2.337186 = N_14|N_13|N_12|N_16
N_18: 0.815003 = N_17|N_18
Frozen-configuration outcome
13 oracle-observed coordinate dropouts
5 complete composite quantities in fusion-ineligible cells
Example audit outcomes for this frozen toy configuration — not a software error rate and not a prevalence estimate.
NOT-EXPOSED to the primitive-axis contract shown here. Method B's native object is endpoint- and path-associated; it is not equivalent to a primitive branch-length matrix and never claims one. The marked cells are not errors. They show how a legitimate native object looks when it is projected onto a frozen primitive axis: typically half of a composite under an endpoint split, or a whole composite attributed to a single endpoint.
| step | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| baseline | 0.732182 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step1 | NA | 0.438153 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.438153 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step2 | NA | NA | NA | 0.911487 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.911487 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step3 | NA | NA | NA | NA | NA | 1.168593 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 1.168593 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step4 | NA | NA | NA | NA | NA | NA | NA | NA | 0.837173 | 0.836004 | 1.168593 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step5 | NA | NA | NA | NA | NA | NA | NA | NA | NA | 1.586595 | 1.586595 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| main_step6 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.407502 | 0.388108 | 0.685170 | 0.407502 | 0.832916 | 0.007334 |
| main_step7 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.750087 | 0.750087 | 0.832916 | 0.007334 |
Endpoint-split projection
N_16 & N_12: 0.438153 = (N_12|N_16)/2 · N_13 & N_16: 0.911487 = (N_13|N_12|N_16)/2
N_14 & N_16: 1.168593 = (N_14|N_13|N_12|N_16)/2 · N_17 & N_18: 0.407502 = (N_17|N_18)/2
t9 & N_16: 1.586595 = (t9|N_14|N_13|N_12|N_16)/2 · t2 & N_18: 0.750087 = (t2|N_17|N_18)/2
Single-endpoint full projection
t4: 0.837173 = t4|N_15
The baseline row also differs at t10 by construction: an endpoint split halves the display-root-incident edge.
Reading C and D together. Identical inputs, identical arithmetic, two different filing behaviours — and two different dispositions, because the two methods claim different things. That distinction is not available to any check that only compares numbers. It needs the coordinate ledger and a declared exposure, which is the whole reason both exist.
The global schedule deletes inward from the display-root side. The localized schedule removes the same number of taxa but concentrates them inside one clade, so fusion and structural absence fall in entirely different places. Everything else is identical: the same reference tree, the same frozen axis, the same declared exposure, the same audit.
The same graph oracle, run on the localized taxon subsets. Note how different this ledger looks from the global one: the coordinates that fuse and the coordinates that vanish are almost a different set.
| coordinate | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reference tree | 1.464364 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step1 | 1.464364 | 0.138710 | 0.988892 | NA_fuse | NA_struct | NA_fuse | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step2 | 1.464364 | 0.138710 | 0.988892 | NA_fuse | NA_struct | NA_fuse | NA_fuse | NA_struct | NA_fuse | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step3 | 1.464364 | 0.138710 | 0.988892 | NA_fuse | NA_struct | NA_fuse | NA_struct | NA_struct | NA_struct | NA_fuse | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step4 | 1.464364 | NA_fuse | NA_fuse | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step5 | 1.464364 | NA_fuse | NA_fuse | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | 0.737596 | NA_fuse | NA_struct | NA_fuse | 0.003948 | 0.832916 | 0.007334 |
| local_step6 | 1.464364 | NA_fuse | NA_fuse | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_fuse | NA_struct | NA_struct | NA_struct | NA_fuse | 0.832916 | 0.007334 |
| local_step7 | 1.464364 | NA_fuse | NA_fuse | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_struct | NA_fuse | NA_struct | NA_struct | NA_struct | NA_fuse | NA_struct | NA_fuse |
The same exposed workflow, the same declared fixed-axis contract, and this time no cell disagrees with the oracle. Every coordinate the oracle records as independently observable carries its value; every ineligible cell is empty. Across all seven steps there is nothing to highlight.
| step | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reference tree | 1.464364 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step1 | 1.464364 | 0.138710 | 0.988892 | NA | NA | NA | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step2 | 1.464364 | 0.138710 | 0.988892 | NA | NA | NA | NA | NA | NA | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step3 | 1.464364 | 0.138710 | 0.988892 | NA | NA | NA | NA | NA | NA | NA | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step4 | 1.464364 | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step5 | 1.464364 | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.737596 | NA | NA | NA | 0.003948 | 0.832916 | 0.007334 |
| local_step6 | 1.464364 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.832916 | 0.007334 |
| local_step7 | 1.464364 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA |
No discrepant cells
0 oracle-observed coordinate dropouts
0 composite quantities in fusion-ineligible cells
Same implementation, same coordinate contract, different prespecified pruning configuration.
What that certifies
Only this configuration. A clean result under the localized schedule says nothing about the global one, and the global result said nothing about this one.
Still NOT-EXPOSED to the primitive-axis contract. The estimand boundary has not moved, but the projection signature has: a different geometry produces a different set of marked cells, including single-endpoint full projections into fusion-ineligible cells.
| step | t10 | N_12 | t1 | N_13 | t8 | N_14 | N_15 | t7 | t4 | t9 | N_16 | N_17 | t5 | t2 | N_18 | t3 | t6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| baseline | 0.732182 | 0.138710 | 0.988892 | 0.946668 | 0.082438 | 0.514212 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step1 | 0.732182 | NA | 0.988892 | NA | NA | 1.460880 | 0.390203 | 0.905738 | 0.446970 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step2 | 0.732182 | NA | 0.988892 | NA | NA | NA | NA | NA | 0.837173 | 0.836004 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step3 | 0.732182 | NA | 0.988892 | NA | NA | NA | NA | NA | NA | 2.296884 | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step4 | 0.732182 | NA | 1.127602 | NA | NA | NA | NA | NA | NA | NA | 0.737596 | 0.811055 | 0.388108 | 0.685170 | 0.003948 | 0.832916 | 0.007334 |
| local_step5 | 0.732182 | NA | 1.127602 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 1.496225 | 0.003948 | 0.832916 | 0.007334 |
| local_step6 | 0.732182 | NA | 1.127602 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.741544 | 0.832916 | 0.007334 |
| local_step7 | 0.732182 | NA | 1.127602 | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | NA | 0.748878 |
Coordinate-ineligible native distances
t1: 1.127602 = t1|N_12 · N_14: 1.460880 = N_14|N_13 · t4: 0.837173 = t4|N_15
t9: 2.296884 = t9|N_13|N_14 · t2: 1.496225 = t2|N_17 · N_18: 0.741544 = N_18|N_16
t6: 0.748878 = t6|N_18|N_16
Availability under projection
4 oracle-observed coordinates unavailable in the audit projection
The baseline again differs at t10 by construction: an endpoint split halves the display-root-incident edge.
Why both schedules are shown. A workflow that satisfies the contract under one pruning geometry has not been shown to satisfy it under another. Here the same exposed implementation disagrees with the oracle under the global schedule and agrees with it completely under the localized one — the coordinates that fuse are simply different, and a workflow can handle one fusion pattern while mishandling another. Certifying a single schedule and generalizing from it is exactly the inference this benchmark exists to prevent. Both schedules ship with the benchmark for that reason.
Explore the oracle
Delete tips and watch the ledger update. Every state shown is the oracle's exact answer for that taxon subset — select a branch to see which coordinates fuse together with it, and which vanish entirely.
SplitAligner builds coordinates; Catnip10 tests them
SplitAligner constructs and interprets the branch-coordinate framework: it defines branch identity through projected species-tree splits and names every kind of branch absence. Catnip10 tests whether an implementation preserves a declared coordinate contract. The two answer different questions, and neither substitutes for the other.
Catnip10 was developed within the SplitAligner validation ecosystem, which is where the need for an independent truth object first became concrete. Its oracle and scoring contract are implementation-independent: the truth layer is derived by graph contraction, not by asking SplitAligner what the answer should be. SplitAligner is reference infrastructure for the framework, not the benchmark's oracle and not the identity of any participant.
If you want the coordinate system itself — how projected splits define branch identity, and how absence is decomposed — start with the explainer and the tutorial.
Score your own workflow
You do not have to make your implementation public to be scored. Normalize one output layer to the long-table adapter contract, declare that layer's exposure, and run the scorer. The public repository ships the normative specifications, the frozen benchmark inputs, the oracle truth tables and composite ledgers, machine-readable table schemas, a method-neutral scoring engine, a synthetic example adapter, and anonymous normalized participant outputs. Participant-specific adapters, source versions and execution commands are not public, because they would reveal participant identities.
# Axis A — score an exposed fixed/shared primitive layer
python3 tools/score_participant.py \
--truth oracle/primitive_truth_tables/global_truth.tsv \
--input tutorial/example_scoring/pass_output.tsv \
--exposure tutorial/example_scoring/pass_exposure.tsv \
--cell-output /tmp/catnip10_cells.tsv \
--summary-output /tmp/catnip10_summary.tsv
# Axis B — certify strict equivalence first, then score
python3 tools/certify_representations.py \
--manifest benchmark/representation_controls/representation_manifest.tsv \
--output /tmp/catnip10_representation_certification.tsv
python3 tools/score_representation.py \
--namespace benchmark/reference_tree/branch_namespace.tsv \
--baseline-output tutorial/example_representation_scoring/rep_pass_baseline.tsv \
--equivalent-output tutorial/example_representation_scoring/rep_pass_equivalent.tsv \
--certification /tmp/catnip10_representation_certification.tsv \
--representation-id display_root_shift_true \
--exposure tutorial/example_representation_scoring/rep_pass_exposure.tsv \
--cell-output /tmp/catnip10_rep_cells.tsv \
--summary-output /tmp/catnip10_rep_summary.tsv
# contract and anonymity checks
python3 -m unittest discover -s tests -v
Axis A requires the complete expected canonical-key set before scoring: missing, duplicate, unknown or inconsistent crosswalk rows are adapter-validation errors rather than participant results. Axis B requires an independently computed certification record before any participant is scored, then aligns outputs by canonical split identity. Synthetic PASS, FAIL, NOT-EXPOSED, true-shift and serialization-only no-op cases are all exercised by the test suite. The authoritative numerical assets are TSV files; rendered documents and figures are views, not the source of truth.
Citing this work. SplitAligner and Catnip10 both rest on two papers and should be cited through both: the SplitAligner main text for the coordinate-construction framework, and the graph-theoretic truth table for the branch-identity definitions and for the uniqueness of the coordinate-and-state ledger the oracle computes. Both are currently available as preprints. The Catnip10 repository may be referenced in addition when the benchmark materials themselves are used. Released under the MIT licence.