Skip to content

refactor(tds)!: hydrate TDS through validated UUID snapshots (#454) - #460

Merged
acgetchell merged 2 commits into
mainfrom
refactor/454-tds-snapshots
Jun 15, 2026
Merged

refactor(tds)!: hydrate TDS through validated UUID snapshots (#454)#460
acgetchell merged 2 commits into
mainfrom
refactor/454-tds-snapshots

Conversation

@acgetchell

Copy link
Copy Markdown
Owner
  • Route TDS serialization through a validated UUID snapshot boundary that carries vertex, simplex, neighbor, and periodic-offset relationships without storage-local slotmap handles.
  • Rebuild runtime TDS storage only from validated snapshots, with fresh slotmap keys and full topology validation before exposing hydrated state.
  • Keep standalone simplex records from becoming an alternate hydration path, so simplex connectivity is resolved only in the TDS snapshot context.
  • Update repository guards and documentation to describe snapshot-based persistence as the serialization boundary.

BREAKING CHANGE: TDS JSON now uses the validated snapshot format, including serialized simplex neighbor UUID relationships, and no longer supports older storage-local/key-based hydration shapes.

Closes #454

- Route TDS serialization through a validated UUID snapshot boundary that carries vertex, simplex, neighbor, and periodic-offset relationships without storage-local slotmap handles.
- Rebuild runtime TDS storage only from validated snapshots, with fresh slotmap keys and full topology validation before exposing hydrated state.
- Keep standalone simplex records from becoming an alternate hydration path, so simplex connectivity is resolved only in the TDS snapshot context.
- Update repository guards and documentation to describe snapshot-based persistence as the serialization boundary.

BREAKING CHANGE: TDS JSON now uses the validated snapshot format, including serialized simplex neighbor UUID relationships, and no longer supports older storage-local/key-based hydration shapes.

Closes #454
@acgetchell
acgetchell enabled auto-merge (squash) June 15, 2026 14:53
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Introduces src/core/tds_snapshot.rs as a dedicated persistence boundary for Tds, relocating Serialize/Deserialize impls from tds.rs into the new module. The module defines raw codec types (RawTdsSnapshot, RawSnapshotSimplex), validated snapshot types with typed errors (TdsSnapshotError), and a full UUID-based hydration pipeline. simplex.rs renames its internal DTO from SerializedSimplex to StandaloneSimplexRecord. Facet APIs gain borrowed view patterns via FacetHandle::view() and FacetView::handle(). Semgrep rules, test fixtures, and integration tests are updated to enforce and validate the new persistence boundary.

Changes

TDS UUID Snapshot Persistence Boundary

Layer / File(s) Summary
TdsSnapshotError, raw schema, and validated snapshot types
src/core/tds_snapshot.rs
Defines TdsSnapshotError variants for all failure modes (duplicate UUIDs, dangling references, arity/dimension mismatches, validation failures), RawTdsSnapshot/RawSnapshotSimplex as serde-facing codec records with deny_unknown_fields, and TdsSnapshot/TdsSnapshotSimplex with slot wrapper types proving UUID relationship consistency before hydration.
StandaloneSimplexRecord rename and RawSnapshotSimplex serde
src/core/simplex.rs, src/core/tds_snapshot.rs
Renames internal deserialization DTO from SerializedSimplex to StandaloneSimplexRecord and updates visitor/deserializer wiring; implements custom serde for RawSnapshotSimplex serializing only uuid and optional data while strictly rejecting storage-local simplex state fields.
Snapshot hydration pipeline and Tds Serialize/Deserialize wiring
src/core/tds_snapshot.rs
Implements RawTdsSnapshot::parse (UUID set/arity validation), TdsSnapshot::from_tds (borrowed serialization), TdsSnapshot::into_raw (codec emission), TdsSnapshot::into_tds (hydration with UUID→SlotMap remapping, neighbor assignment via set_neighbors_from_keys, full validation). Wires Serialize/Deserialize for Tds to use the snapshot pipeline.
tds.rs delegation to tds_snapshot and import cleanup
src/core/tds.rs
Adds tds_snapshot module via #[path], removes SerializedSimplex import and local serde machinery, deletes inline Serialize/Deserialize impls for Tds, removes periodic_offset_tds_2d() test helper, and removes all serde-focused tests (−812 lines).
tds_snapshot comprehensive unit and integration tests
src/core/tds_snapshot.rs
Adds ~1200 lines of tests covering stable UUID serialization invariants, field rejection (unknown/missing), periodic-offset round-trips and validation, duplicate UUID rejection, error-variant preservation, hydration correctness under inconsistent neighbors, and full serde round-trips preserving topology and payload data.
Facet handle/view APIs and round-tripping
src/core/facet.rs
Clarifies facet documentation for runtime-local handles/views (non-durable across I/O). Adds FacetHandle::view(tds) public method revalidating and returning a borrowed FacetView; adds FacetView::handle() infallible conversion back to FacetHandle. Updates examples and adds unit tests for round-tripping and error handling.
EdgeKey and runtime topology handle documentation
src/core/edge.rs
Expands EdgeKey Rustdoc to clarify runtime-only nature tied to a specific live Tds, directing callers to use stable vertex UUIDs for persistence and cross-boundary comparisons.
Semgrep rules tightening persistence boundary
semgrep.yaml
Updates existing rules to reference issue #454 (instead of #442), changes message wording from "DTO records" to "snapshot records", extends pattern-regex to cover snapshot_simplices fields. Adds new rules enforcing UUID-only relationship storage, duplicate-key-rejecting deserializers, snapshot privacy, and Tds serialization via TdsSnapshot::from_tds.
Semgrep test fixtures for snapshot serialization
tests/semgrep/src/project_rules/rust_style.rs
Updates fixtures to use RawSnapshotSimplex instead of SerializedSimplex. Adds snapshot_uuid_relationships_ok fixture and snapshot fixture scaffolding (public structs, Serialize impls, serialize_via_snapshot method).
Integration test updates for snapshot hydration
tests/proptest_orientation.rs, tests/serialization_vertex_preservation.rs
Updates proptest orientation tamper-detection to accept InvalidNeighbors alongside OrientationViolation. Adds diag_debug! macro to serialization tests (gated by diagnostics feature) and replaces println! calls with diagnostic logging while preserving all assertions.
Documentation and collection test cleanup
docs/code_organization.md, tests/README.md, src/core/collections/*.rs, docs/dev/tooling-alignment.md
Adds tds_snapshot.rs to architecture docs; updates test count in README; removes compile-only instantiation tests from collection modules; adds documentation for Semgrep hardening #454.
Prelude exports and test API coverage
tests/prelude_exports.rs
Extends prelude test to import facet-related types (FacetHandle, FacetView), adds FacetError variant, and validates facet handle/view round-trip exports.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TdsSerialize as Tds::serialize
  participant TdsSnapshot
  participant RawTdsSnapshot as codec
  participant TdsDeserialize as Tds::deserialize

  rect rgba(100, 149, 237, 0.5)
    note over User, codec: Serialization path
    User->>TdsSerialize: serialize(tds)
    TdsSerialize->>TdsSnapshot: from_tds(tds) — extract UUID slots
    TdsSnapshot->>RawTdsSnapshot: into_raw() — emit codec-friendly records
    RawTdsSnapshot-->>User: JSON (UUIDs, no slotmap keys)
  end

  rect rgba(60, 179, 113, 0.5)
    note over User, TdsDeserialize: Deserialization path
    User->>TdsDeserialize: deserialize(data)
    TdsDeserialize->>RawTdsSnapshot: decode JSON
    RawTdsSnapshot->>TdsSnapshot: parse() — validate UUIDs, arity, offsets
    TdsSnapshot->>TdsSnapshot: into_tds() — remap to fresh SlotMap keys
    TdsSnapshot->>TdsSnapshot: set_neighbors_from_keys + validate
    TdsSnapshot-->>User: Result~Tds, TdsSnapshotError~
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

Possibly related PRs

  • acgetchell/delaunay#455: Both PRs tighten TDS persistence/serialization boundary rules around UUID-based snapshots vs. slotmap keys in semgrep.yaml.

Poem

🐇 A snapshot springs to life today,
UUIDs guide the stored array,
No slotmap keys shall cross the wire—
Fresh handles, views, and hydration fire!
The topology boundary is clear,
Validated snapshots persevere! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(tds)!: hydrate TDS through validated UUID snapshots (#454)' clearly summarizes the main change: moving TDS hydration to use validated UUID snapshots instead of storage-local keys.
Description check ✅ Passed The description is well-related to the changeset, detailing the routing of TDS serialization through UUID snapshots, rebuild mechanisms, simplex record handling, and breaking changes.
Linked Issues check ✅ Passed The PR fully addresses issue #454's requirements: establishes UUIDs as durable identifiers, implements validated deserialization with typed errors, improves handle/view clarity with new public methods, adds semgrep rules, and updates documentation and preludes.
Out of Scope Changes check ✅ Passed All changes are directly related to the refactoring objective: new TdsSnapshot implementation, removal of old serde logic, documentation updates, semgrep rules, handle/view API improvements, and test modifications are all in scope for issue #454.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 100.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/454-tds-snapshots

Comment @coderabbitai help to get the list of available commands and usage tips.

@acgetchell acgetchell self-assigned this Jun 15, 2026
@acgetchell
acgetchell disabled auto-merge June 15, 2026 14:55
@coderabbitai coderabbitai Bot added rust Pull requests that update rust code breaking change api topology labels Jun 15, 2026
@codacy-production

codacy-production Bot commented Jun 15, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 215 complexity

Metric Results
Complexity 215

View in Codacy

🟢 Coverage 97.85% diff coverage · +0.10% coverage variation

Metric Results
Coverage variation +0.10% coverage variation (-1.00%)
Diff coverage 97.85% diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (739aba0) 66786 61125 91.52%
Head commit (9aed5b9) 67814 (+1028) 62132 (+1007) 91.62% (+0.10%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#460) 1625 1590 97.85%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.84615% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.59%. Comparing base (739aba0) to head (9aed5b9).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/core/tds_snapshot.rs 97.92% 33 Missing ⚠️
src/core/facet.rs 96.55% 1 Missing ⚠️
src/core/simplex.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #460      +/-   ##
==========================================
+ Coverage   91.49%   91.59%   +0.09%     
==========================================
  Files          72       72              
  Lines       66574    67602    +1028     
==========================================
+ Hits        60915    61922    +1007     
- Misses       5659     5680      +21     
Flag Coverage Δ
unittests 91.59% <97.84%> (+0.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/tds_snapshot.rs`:
- Around line 707-722: The from_tds() function unnecessarily requires Copy
bounds on type parameters U and V by eagerly copying vertex data with *vertex
dereference, whereas the serialization format RawTdsSnapshot only requires
DataSerialize (not Copy). Refactor from_tds() to avoid eager copying—either by
collecting vertex references directly without dereferencing, or by using a
borrowed serialization path—so that non-Copy types implementing DataSerialize
can be serialized through Tds. Ensure the refactored approach aligns with how
deserialization correctly avoids the Copy requirement.
- Around line 231-237: The three relationship map fields in RawTdsSnapshot
(simplex_vertices, simplex_neighbors, and simplex_vertex_offsets) deserialize
directly into FastHashMap without detecting duplicate simplex UUID keys during
deserialization, allowing serde_json to silently overwrite earlier values.
Create custom deserializers for these fields that explicitly error on duplicate
Uuid keys during deserialization, similar to the existing SnapshotSimplexVisitor
pattern, and apply these deserializers to simplex_vertices, simplex_neighbors,
and simplex_vertex_offsets using serde attributes. Alternatively, if the
serde_with crate is available, apply the maps_duplicate_key_is_error attribute
to these three fields instead.
- Around line 588-604: The deserialization of the data field in the Tds snapshot
is collapsing explicit None values by wrapping deserialized values in Some() and
then calling flatten(). This loses the distinction between a present JSON field
with null value and a missing field. After the deserialization loop for uuid and
data fields completes, find where the deserialized values are being finalized
and remove the flatten() call that collapses Some(None) to None. Store the
deserialized V value directly without the intermediate Some() wrapping so that
explicit null payloads in the JSON are preserved as Some(None) rather than being
flattened to None.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: ddce8678-4212-4585-9da2-0f6c8676c0eb

📥 Commits

Reviewing files that changed from the base of the PR and between 739aba0 and 14480e4.

📒 Files selected for processing (11)
  • docs/code_organization.md
  • semgrep.yaml
  • src/core/collections/key_maps.rs
  • src/core/collections/secondary_maps.rs
  • src/core/simplex.rs
  • src/core/tds.rs
  • src/core/tds_snapshot.rs
  • tests/README.md
  • tests/proptest_orientation.rs
  • tests/semgrep/src/project_rules/rust_style.rs
  • tests/serialization_vertex_preservation.rs
💤 Files with no reviewable changes (2)
  • src/core/collections/secondary_maps.rs
  • src/core/collections/key_maps.rs

Comment thread src/core/tds_snapshot.rs
Comment thread src/core/tds_snapshot.rs
Comment thread src/core/tds_snapshot.rs Outdated
@acgetchell
acgetchell enabled auto-merge (squash) June 15, 2026 15:41
- Reject duplicate UUID relationship-map keys and storage-local simplex fields during snapshot deserialization.
- Preserve explicit null simplex payloads and serialize non-Copy vertex and simplex payload data without eager copies.
- Clarify FacetHandle, FacetView, and EdgeKey as runtime-local topology identities with handle/view conversion APIs.
- Add Semgrep guardrails that keep snapshot internals private, require duplicate-key deserializers, and prevent runtime handle serde.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
semgrep.yaml (1)

732-752: 💤 Low value

Fragile negative lookbehind relies on exact whitespace formatting.

The patterns use negative lookbehinds that expect exact indentation (4 spaces) and line structure. While this works for rustfmt-consistent code, it may produce false positives if the serde attribute is split across lines or uses different indentation.

Consider documenting this formatting sensitivity in the rationale, or accepting the limitation since rustfmt enforces consistent formatting in this repository.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@semgrep.yaml` around lines 732 - 752, The negative lookbehind patterns in the
delaunay.rust.raw-tds-snapshot-uuid-maps-require-duplicate-key-deserializers
rule rely on exact whitespace matching (4 spaces of indentation), which may
cause false positives if code formatting changes. Add documentation to the
rationale section acknowledging that these patterns depend on rustfmt-consistent
formatting, explaining that the negative lookbehinds expect specific indentation
and line structure for the serde attributes decorating simplex_vertices,
simplex_neighbors, and simplex_vertex_offsets fields, and note that deviations
from this formatting (such as different indentation or different line breaks)
may result in false positives despite the presence of the required deserializer
attributes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@semgrep.yaml`:
- Around line 732-752: The negative lookbehind patterns in the
delaunay.rust.raw-tds-snapshot-uuid-maps-require-duplicate-key-deserializers
rule rely on exact whitespace matching (4 spaces of indentation), which may
cause false positives if code formatting changes. Add documentation to the
rationale section acknowledging that these patterns depend on rustfmt-consistent
formatting, explaining that the negative lookbehinds expect specific indentation
and line structure for the serde attributes decorating simplex_vertices,
simplex_neighbors, and simplex_vertex_offsets fields, and note that deviations
from this formatting (such as different indentation or different line breaks)
may result in false positives despite the presence of the required deserializer
attributes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bd6e2a63-5064-4b75-8c7a-efc63d2823d3

📥 Commits

Reviewing files that changed from the base of the PR and between 14480e4 and 9aed5b9.

📒 Files selected for processing (7)
  • docs/dev/tooling-alignment.md
  • semgrep.yaml
  • src/core/edge.rs
  • src/core/facet.rs
  • src/core/tds_snapshot.rs
  • tests/prelude_exports.rs
  • tests/semgrep/src/project_rules/rust_style.rs
✅ Files skipped from review due to trivial changes (2)
  • src/core/edge.rs
  • docs/dev/tooling-alignment.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/core/tds_snapshot.rs

@acgetchell
acgetchell merged commit 87eb8b1 into main Jun 15, 2026
22 checks passed
@acgetchell
acgetchell deleted the refactor/454-tds-snapshots branch June 15, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api breaking change rust Pull requests that update rust code topology

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: make TDS identity and handle boundaries proof-bearing

1 participant