Skip to content

test: parity verification between Rust and Python starfix (PLT-1048)#3

Merged
eywalker merged 2 commits intomainfrom
eywalker/plt-1048-ensure-implementation-and-logical-parity-between-rust-and
Mar 20, 2026
Merged

test: parity verification between Rust and Python starfix (PLT-1048)#3
eywalker merged 2 commits intomainfrom
eywalker/plt-1048-ensure-implementation-and-logical-parity-between-rust-and

Conversation

@agent-kurouto
Copy link
Contributor

@agent-kurouto agent-kurouto bot commented Mar 20, 2026

Summary

Closes PLT-1048. Verifies that the Rust (nauticalab/starfix) and Python (nauticalab/starfix-python) implementations are logically consistent with the design spec in starfix/docs/ and with each other.

Parity status: ✅ All tests pass, byte-exact hashes confirmed

  • 129 Python tests pass (40 golden parity tests against Rust-generated values)
  • 67 Rust tests pass (including the new cross-implementation parity test)
  • All spec examples A–Q produce identical hashes in both implementations

Findings

1. Implementations are logically consistent ✅

A thorough line-by-line comparison of both implementations against the design spec (starfix/docs/design-spec.md, byte-layout-spec.md) found that:

  • BTreeMap decomposition is correctly implemented in both (field paths, entry types, traversal order)
  • Schema serialization (canonical JSON, type normalization: Utf8→LargeUtf8, Binary→LargeBinary, List→LargeList, Dict→value_type) matches the spec in both
  • Null handling (BitVec<u8, Lsb0>, AND-propagation of struct-level nulls) is consistent
  • Version prefix (0x000001, 3 bytes) is applied identically
  • 77 golden parity tests (in test_golden_parity.py and test_golden_parity_r2.py) confirm byte-exact agreement across all primitive types, temporal types, decimals, nested structs, list types, and float special values

2. Edge case: LargeList<Struct> with inner_field.nullable=True

Uncovered by existing tests: all prior List<Struct> tests used inner_field.nullable=False.

Behavior: When inner_field.nullable=True, the structural-only BTreeMap entry for the list gets an allocated (but never populated) BitVec. At finalisation this contributes 8 zero bytes (bit_count=0) before the structural SHA-256 — a minor deviation from the spec table which shows structural-only entries have no null_bits. Both Rust and Python handle this identically.

Verified: New Rust test list_struct_nullable_inner_field_parity (added to nauticalab/starfix) and new Python test class TestListStructNullableInnerField (added here) confirm byte-exact parity:

  • nullable=True: 0000012c2b1c1d5b4c3dc46ed5335834dbf0d7386c38e607a398a2897fdaf1df387e1c
  • nullable=False: 000001713fa0e500c9aebea61039b30371fd84c0dff8cd3b96b4266978658bf73e4d8c

3. Minor behavioral difference (intentional)

The Python update() does not validate batch schema compatibility (Rust panics if schemas don't match). This is tested and appears intentional per the existing test suite.

Changes

  • tests/test_golden_parity_r2.py: adds TestListStructNullableInnerField (3 tests) covering the List<Struct nullable_element> edge case with golden values verified against Rust

Test plan

  • uv run pytest tests/ -q129 passed
  • Rust cargo test in nauticalab/starfix67 passed (including new list_struct_nullable_inner_field_parity)
  • All existing golden parity tests unchanged

🤖 Generated with Claude Code

…LT-1048)

Adds TestListStructNullableInnerField with 3 tests covering the edge case
where a LargeList<Struct>'s item field has nullable=True vs nullable=False.
Golden values (0000012c... and 000001713f...) are verified byte-exact against
the Rust starfix crate via cargo test list_struct_nullable_inner_field_parity.

This completes the cross-implementation parity verification for PLT-1048:
all 129 Python tests and 67 Rust tests pass, and all golden values are
confirmed consistent between the two implementations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds golden parity regression coverage to ensure the Python starfix implementation matches Rust for an uncovered LargeList<Struct> edge case where the list item field’s nullable flag changes the structural hashing behavior.

Changes:

  • Extend test_golden_parity_r2.py with a new parity test class covering LargeList<Struct> with inner_field.nullable=True vs False using Rust-verified golden hashes.
  • Update the module-level “coverage” summary list to include the new edge case.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +899 to +903
@@ -899,6 +900,79 @@ def test_multi_batch_list(self):
# ---------------------------------------------------------------------------


# ---------------------------------------------------------------------------
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The section headers around here are now out of order/duplicated: the "Float special values" banner appears before the newly inserted LargeList tests, and then the float banner is repeated again later. This makes navigation confusing—please remove the earlier float header or move this new LargeList block above the float section so each section header matches the tests that follow.

Copilot uses AI. Check for mistakes.
The new LargeList<Struct> test block was inserted between the float
section banner and the float test class, leaving a stray orphaned
header. Remove the duplicate so each section header correctly precedes
its own test class.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@agent-kurouto
Copy link
Contributor Author

agent-kurouto bot commented Mar 20, 2026

Replying to the inline review comment about duplicate section headers (comment #2964555208):

Fixed in the latest commit (ff48ac6). The orphaned # Float special values banner that was left between TestMultiBatchList and the new TestListStructNullableInnerField block has been removed. Each section header now directly precedes its own test class — the new LargeList/Struct section is ordered before Float special values, and there is a single # Float special values header immediately above TestFloatSpecialValues.

@agent-kurouto
Copy link
Contributor Author

agent-kurouto bot commented Mar 20, 2026

Review round summary

One issue was raised and has been addressed in commit ff48ac6:

Duplicate/orphaned # Float special values section header

When TestListStructNullableInnerField was inserted before the float tests, the original # Float special values banner was left in place above the new block, creating a stale orphaned header followed by the real banner + class further down. The fix removes that orphaned banner so each section header correctly precedes exactly one test class:

# LargeList<Struct> with nullable vs non-nullable inner (item) field
class TestListStructNullableInnerField: ...

# Float special values
class TestFloatSpecialValues: ...

All 129 tests still pass.

@eywalker eywalker merged commit 344617b into main Mar 20, 2026
3 checks passed
@eywalker eywalker deleted the eywalker/plt-1048-ensure-implementation-and-logical-parity-between-rust-and branch March 20, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants