Skip to content

feat(cesium): implement tileset.rs cold-import parser — Group-A entry, no-serde#205

Merged
AdaWorldAPI merged 1 commit into
masterfrom
claude/audit-pr-x12-hallucinations-wN5kw
May 26, 2026
Merged

feat(cesium): implement tileset.rs cold-import parser — Group-A entry, no-serde#205
AdaWorldAPI merged 1 commit into
masterfrom
claude/audit-pr-x12-hallucinations-wN5kw

Conversation

@AdaWorldAPI
Copy link
Copy Markdown
Owner

@AdaWorldAPI AdaWorldAPI commented May 26, 2026

Summary

Fills crates/cesium/src/tileset.rs — the one Group-A ingest module still commented scaffold — with a live OGC 3D Tiles 1.1 tileset.json parser, per the crate's RULE 3 (Cargo.toml: no serde, no json crates).

  • No JSON in the hot path. A dependency-free, hand-rolled tokeniser parses at the cold-import boundary into a transient, module-private Json model that is walked into owned structs and dropped before return — no JSON value survives the import boundary.
  • Owned model matches the scaffold's planned shapes: Tileset / TilesetAsset / TileNode / enum BoundingVolume (Box·Region·Sphere) / Refine / TileContent / ImplicitTilingRef / SubdivisionScheme / ParseError.
  • content + contents unified into one Vec; refine inheritance resolved at traversal; uri (1.1) and legacy url (1.0) both accepted; fail-fast on missing fields / conflicting content / unknown enums.
  • Traversal: iter_leaves, collect_content_uris, refine-resolved visit_preorder, node_count.

Refactored from the audit session's tested serde reader onto cesium's owned-struct, no-serde contract — the serde layer replaced by the hand tokeniser; the standalone ada-3dtiles prototype is dropped (the reader belongs here, in the cesium/3dgs line).

Scope / boundary

  • No Cargo.toml change — stays dependency-free.
  • .3tz ZIP ingestion deferred (needs a ZIP reader + OGC 22-025r4 §13 grounding); the Archive* ParseError variants are reserved for it.
  • Group-A siblings khr_gs.rs and implicit_tiling.rs remain scaffold (separate follow-up; khr_gs's SH_DEGREE_n attrs are the sh.rs surface the ASG-leaf thread rides).

Test plan

  • 10 unit tests: asset/root, all three BV variants, refine inheritance, content/url unification + conflicting-content rejection, implicit tiling, malformed JSON, unicode/surrogate escapes.
  • cargo test -p cesium67/67 pass.
  • tileset.rs is clippy-clean (0 errors attributable to this file).

Heads-up — pre-existing clippy debt (NOT from this PR)

cargo clippy -p cesium --all-targets -- -D warnings currently fails on 9 errors that predate this change (merged via #202/#204), surfaced only under --all-targets:

  • fixtures.rs:412–415 — 4× assertions_on_constants (wrap in const { assert!(..) }).
  • to_cam_soa.rs:518–519erasing_op ("this operation will always return zero") — possibly a real logic slip, worth a look — not a mechanical #[allow].

Per the crate's scaffold contract, this impl is submitted for Opus + CodeRabbit review before being considered "uncommented."

https://claude.ai/code/session_01UHfLwSzGfVNzkNrTEBijuA


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added complete 3D tileset parsing and processing capabilities, enabling traversal and analysis of tile hierarchies.
    • Implemented tileset inspection methods including node counting, leaf iteration, and content URI extraction.
    • Added comprehensive error handling and validation for tileset integrity.

Review Change Stack

…p-A entry)

Fill the commented tileset.rs scaffold with a live OGC 3D Tiles 1.1
parser per the crate's RULE 3 (no serde, no json crates): a dependency-
free hand-rolled tokeniser parses at the cold boundary into a transient
JSON model that is walked into owned structs and dropped before return —
no JSON value reaches the hot path.

- Owned model: Tileset / TilesetAsset / TileNode / enum BoundingVolume /
  Refine / TileContent / ImplicitTilingRef / SubdivisionScheme / ParseError.
- content+contents unified into one Vec; refine inheritance resolved at
  traversal; uri/legacy-url accepted; box/region/sphere dispatch.
- 10 unit tests; 67/67 crate tests pass; tileset.rs clippy-clean.

Fills the entry point of the Group-A ingest front-end (khr_gs.rs and
implicit_tiling.rs remain scaffold). Refactored from the audit session's
reader logic onto cesium's owned-struct contract. Proposed for
Opus + CodeRabbit review per the crate's scaffold contract.

https://claude.ai/code/session_01UHfLwSzGfVNzkNrTEBijuA
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ed352f3d-5e36-4986-a1f5-4ccf7b3603fc

📥 Commits

Reviewing files that changed from the base of the PR and between f373c75 and b5c0eda.

📒 Files selected for processing (1)
  • crates/cesium/src/tileset.rs

📝 Walkthrough

Walkthrough

This PR adds a complete, dependency-free tileset.json parser to the Cesium module. It defines an owned tile-tree data model with traversal helpers, implements a hand-rolled JSON tokenizer and parser, enforces schema constraints (content vs. contents, required fields, enum validation), and includes extensive unit tests covering parsing, inheritance, and error cases.

Changes

Tileset JSON Parser Implementation

Layer / File(s) Summary
Tile-tree data model and traversal API
crates/cesium/src/tileset.rs
Public structs (Tileset, TilesetAsset, TileNode) and enums (BoundingVolume, Refine, SubdivisionScheme, TileContent, ImplicitTilingRef) represent the parsed tileset. Methods on Tileset provide version(), node_count(), iter_leaves(), collect_content_uris(), and visit_preorder() with Refine inheritance resolution. TileNode exposes is_leaf() and is_implicit_root().
Parse error types and Display impl
crates/cesium/src/tileset.rs
ParseError enum covers invalid UTF-8, wrong types, missing required fields, enum value mismatches, conflicting content, and other validation failures. Implements fmt::Display and std::error::Error.
Tileset parsing entry point and tile-tree recursion
crates/cesium/src/tileset.rs
parse_tileset(bytes: &[u8]) validates UTF-8, parses JSON, and recursively walks the tree into owned TileNode structs. Enforces field requiredness, type checks, refine enum parsing, optional transform/viewerRequestVolume, and mutually exclusive content vs contents.
Value extraction and validation helpers
crates/cesium/src/tileset.rs
Parsing helpers for bounding volumes (box/sphere/region), tile content (unifying uri and legacy url), implicit tiling (subdivision schemes), string arrays, and fixed-length numeric arrays with error handling.
JSON tokenizer and tree builder
crates/cesium/src/tileset.rs
Hand-rolled JsonParser tokenizes and builds a transient Json AST tree from UTF-8 bytes, handling objects, arrays, strings (with escapes and unicode), literals, and numbers. No external JSON dependencies.
Comprehensive parser test suite
crates/cesium/src/tileset.rs
Tests validate successful parsing of tilesets with various bounding volumes, refine inheritance, content URIs, leaf iteration, and implicit tiling. Error cases cover conflicting fields, missing fields, malformed JSON, and string escape/unicode handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A parser born from the frost,
No serde, no json crate's cost,
With handcrafted tokenizer bright,
Tileset trees take sturdy flight,
Through validation's careful mist—
Quality that won't be missed!

✨ 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 claude/audit-pr-x12-hallucinations-wN5kw

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

@AdaWorldAPI AdaWorldAPI merged commit b58a284 into master May 26, 2026
16 of 17 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b5c0edaba2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

pub fn parse_tileset(bytes: &[u8]) -> Result<Tileset, ParseError> {
let text = std::str::from_utf8(bytes).map_err(|_| ParseError::InvalidUtf8)?;
let mut parser = JsonParser::new(text.as_bytes());
let doc = parser.parse_value()?;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject trailing bytes after the root JSON value

parse_tileset parses one JSON value and then immediately maps fields from it, but never checks that the parser reached end-of-input. This accepts malformed payloads where a valid tileset.json object is followed by extra bytes, so concatenated/corrupted inputs bypass JsonSyntax rejection and are treated as valid tilesets.

Useful? React with 👍 / 👎.

Comment on lines +387 to +390
if let Some(b) = v.get("box") {
Ok(BoundingVolume::Box(parse_f64_array::<12>(b, "boundingVolume.box")?))
} else if let Some(r) = v.get("region") {
Ok(BoundingVolume::Region(parse_f64_array::<6>(r, "boundingVolume.region")?))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Enforce exactly one boundingVolume shape key

parse_bounding_volume picks the first present key (box, then region, then sphere) and succeeds even if multiple shape keys are present in the same object. Because 3D Tiles requires exactly one shape, malformed inputs can silently select the wrong bounds and change culling/selection behavior instead of failing fast.

Useful? React with 👍 / 👎.

Comment on lines +423 to +427
let subtree_levels = v
.get("subtreeLevels")
.and_then(Json::as_f64)
.ok_or(ParseError::MissingField("implicitTiling.subtreeLevels"))? as u32;
let available_levels = v
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate implicit tiling levels before integer conversion

subtreeLevels and availableLevels are read as f64 and cast with as u32 without range/integer checks. Inputs like negative numbers, fractions, or NaN are silently coerced (e.g., to 0 or truncated), violating the documented >= 1 integer contract and allowing invalid implicit-tiling metadata to propagate instead of returning a parse error.

Useful? React with 👍 / 👎.

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