Skip to content

helix: 20260629b re-bake (vessel diameter + teeth→skeleton) + living-anatomy browser (search / x-ray / LOD)#66

Merged
AdaWorldAPI merged 6 commits into
mainfrom
claude/q2-fma-v3-bake
Jun 29, 2026
Merged

helix: 20260629b re-bake (vessel diameter + teeth→skeleton) + living-anatomy browser (search / x-ray / LOD)#66
AdaWorldAPI merged 6 commits into
mainfrom
claude/q2-fma-v3-bake

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 29, 2026

Copy link
Copy Markdown
Owner

What

Follow-up to #65 (merged). Six commits: two bake-quality fixes that drove a full re-bake, the deploy wiring for the new artifacts, and the /helix viewer's missing UI. Branch is deployed for Railway verification before merge.

Bake quality — drove the 20260629b re-bake

  • Per-vessel diameter boundary (2a7ac4a): the slicer-fill swept a solid core along one straight PCA axis per component, each ring's radius = the median perpendicular distance clamped to a single global RMAX (~aorta scale). At a sharp bend the straight axis can't follow the tube — both arms land in one axial bin, the centroid falls between them (outside the limb), the median balloons, and the global cap let a finger artery swell to aorta caliber. Those were the "stray fat children branching off outside the limbs." Fix: per-bin radius now reads a low percentile (near-wall) instead of the median, and every ring is clamped to this vessel's own caliber × 2.0. Synthetic L-bend: worst ring 2.6× true radius, was up to 20×.
  • Teeth → skeleton (db7bce8): teeth are in the dataset but tissue_of had no dental category and teeth aren't is_a bone in FMA (dentin/enamel), so all 28 fell through to the "flesh" default and vanished in the skeleton view — a toothless skull. Added the dental terms to the bone name-matcher; gingiva stays flesh.

Deploy wiring (1c24630)

  • Dockerfile + manifest point at the freshly published body.20260629b.soa.gz (/body) and body.20260629b.v6helix.soa.gz (/helix). Both come from one bake run off the same soa_v2 source, so the 1658-concept ordering is identical — which is what lets /helix reuse the server's per-concept body.blocks (also 1658) for its LOD cull. Old artifacts stay in the release; a bake is swapped in by bumping the manifest.

/helix freeze fix (ef6916e) + max-diameter clamp (be7faec)

  • Draw only enabled layers as geometry (rebuild the index on toggle) + FrontSide backface cull — never a fragment discard (which still rasterises every triangle, killing early-Z). This is the mobile lever.
  • Per-concept max-diameter clamp drops decimation-orphan strays (an aorta splat under the soles); also scopes /cesium.

/helix living-anatomy browser (7896f76) — the new UI

The viewer had only layer toggles. Added the rest so it reads as a living, browsable database:

  • Left-side browser: the 1658 FMA structures grouped by layer, each group expandable (▾/▸) with a live count. Names + display centroids parsed from the BSO2 labels_json + centroid columns at decode.
  • Search: filters every group as you type; matching groups auto-expand. Click a result to glide the orbit camera + dolly onto that structure (revealing its layer if hidden).
  • x-ray: a uAlpha uniform makes the whole body translucent so deeper structures show through; the fragment shader stays trivial.
  • LOD (opt-in): posts the live camera to the existing /api/body/lod HHTL depth-cascade (same protocol /body uses) and folds the per-concept reject byte into the same geometry index rebuild as the layer toggles — not a fragment discard — so early-Z survives and the GPU draws strictly fewer triangles when zoomed in. Absent endpoint (old deploy) silently keeps the full render; a near-total cull is treated as a camera-mapping miss and shows all.

Verification

  • tsc --noEmit + vite build clean.
  • /api/body/lod endpoint confirmed registered (crates/cockpit-server/src/main.rs) and its actions[] are per-concept-row aligned to the 1658-concept body.blocks the /helix LOD gate reads.
  • Both 20260629b artifacts published to the fma-body-soa-v3-v1 release.

Scope / safety

  • /helix UI + bake tooling + deploy wiring. /body (BodyV3) is untouched; the LOD endpoint is shared read-only.
  • Additive: the decode / Signed360-rim / int8-normal / Gouraud hot path is unchanged; the LOD cull and layer mask share one linear index pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added concept search, x-ray viewing, and optional quality-based visibility controls in the body viewer.
    • Improved layer interaction so selecting a concept can reveal its related content more easily.
  • Bug Fixes

    • Reduced out-of-bounds geometry artifacts in the helix view.
    • Improved core-fill shaping to better handle bends and prevent over-expansion.
    • Expanded classification so dental structures are grouped more accurately.
  • Chores

    • Refreshed bundled viewer assets to the latest baked version.

claude added 6 commits June 29, 2026 05:49
… + /cesium scope

Adds a viewer-side per-concept extent clamp to /helix: robust median centre +
p95 radius × margin, dropping triangles that touch an out-of-bounds vertex.
Verified on the real 4.28M-vert bake — conservative: 154 stray tris dropped
(0.00%), all genuine decimation orphans in eye parts (cornea/lens/sclera),
worst 8× p95. Nothing aorta- or foot-related (those vessels sit within their
concept extents).

NOTE for the record: the reported "aorta under the feet" is NOT a misplaced
aorta — all 7 aorta concepts are anatomically correct (torso, z+0.19..+0.61,
zero feet verts). The red mass at the soles is the foot's own vasculature
(plantar/dorsal digital veins + arteries), vessel-red like the aorta. Both
that and the "too-thick aorta" share one cause: /helix draws vessels opaque
at full thickness while /body draws them in a translucent pass. The true fix
(translucent layer-5 pass) is deferred pending a design call.

Also lands the /cesium HHTL-splat activation scope (claude-notes/plans), with
the J1 result recorded: two place-relative Signed360 carry a full 3-DOF
rotation (Σ rel-err 0.34% mean), confirming "2×2 DOF → 3D/4D".

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
…y, not discard)

The Gouraud change cut per-fragment lighting but /helix was still geometry-
bound: it drew all 6.8M triangles DoubleSide every frame, and disabled layers
(skin+muscle, off by default) were still fully rasterised then thrown away by a
fragment discard (which also kills early-Z). That is the freeze.

Now visible layers are excluded as GEOMETRY: the index is rebuilt from the
enabled layers (on toggle) and the fragment shader drops the discard, so the GPU
never touches hidden triangles and early-Z survives. Material switches to
FrontSide (backface cull). Measured on the real mesh: default view (skin+muscle
off) draws 3.6M tris instead of 6.8M, and FrontSide removes DoubleSide's
doubling → 13.6M → 3.6M rasterised triangles (~3.8×), before early-Z gains.

tsc + vite build clean.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
… bends)

The vessel slicer-fill swept a solid core along a single straight PCA axis per
component, with each ring's radius = MEDIAN perpendicular distance clamped to a
single global RMAX (~34 mm, aorta scale). At a strong bend the straight axis
cannot follow the tube: both arms fall in one axial bin, the bin centroid lands
between them (outside the limb), and the median perp-distance balloons — and the
global RMAX let a finger artery swell to aorta caliber. Those are the "stray fat
children branching off outside the limbs".

Fix = per-vessel diameter boundary:
- per-bin radius now reads a LOW percentile (PCTL=0.30, near-wall) instead of the
  median, so a bend bin sharing two arms no longer reports ~half-the-gap.
- every ring is clamped to this vessel's OWN caliber (robust median of bin radii)
  × CAP=2.0, then RMAX. A capillary stays a capillary through its bends; the aorta
  still reaches RMAX.

Validated on a synthetic 1 mm L-bent vessel: max ring 2.6× true radius (was up to
20× under the global cap). Bake-pipeline change — takes effect on next body re-bake.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
Teeth (all 28 + both gingivae) are in the dataset, but tissue_of had no dental
category and teeth are not is_a bone in FMA (dentin/enamel, not skeletal element),
so every tooth fell through to the "flesh" default → layer 1 (skin). With skin off
(e.g. the skeleton view) the jaw bones showed but the teeth vanished — a toothless
skull. Add tooth/molar/incisor/canine/premolar/cuspid to the bone name-matcher so
teeth bucket with the skeleton (layer 4); gingiva stays flesh.

Bake-pipeline change — takes effect on the body re-bake (in progress).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
Point the Dockerfile and the helix manifest at the freshly published
20260629b artifacts on the fma-body-soa-v3-v1 release:

- /body   → body.20260629b.soa.gz       (served same-origin AS body.soa.gz)
- /helix  → body.20260629b.v6helix.soa.gz (BSO2 ver 6: F16 pos + Signed360
            NORMAL column + HXFL floor trailer)

Both come from the same soa_v2 source in one bake run, so the 1658-concept
ordering is identical across the two — which is what lets /helix reuse the
server's per-concept body.blocks (also 1658) for its LOD cull. The re-bake
carries the two bake-pipeline fixes already committed (2a7ac4a per-vessel
slicer-fill diameter boundary, db7bce8 teeth→skeleton). Old artifacts stay
in the release untouched; a new bake is swapped in by bumping the manifest.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
…rver LOD

The /helix viewer had only the layer toggles. Add the rest of the cockpit so
it reads as a living, browsable database rather than a static mesh:

- Left-side browser: the 1658 FMA structures grouped by layer (skin / muscle /
  organ / skeleton / vessel / nervous / connective / other), each group
  expandable (▾/▸), with a live per-group count. Concept names + display
  centroids are parsed from the BSO2 labels_json + centroid columns at decode.
- Search: filters every group as you type; matching groups auto-expand. Click a
  result to glide the orbit camera + dolly onto that structure's centroid
  (revealing its layer if it was hidden).
- x-ray: a uAlpha uniform makes the whole body translucent so deeper structures
  show through (depthWrite off; the fragment shader stays trivial).
- LOD: opt-in server HHTL depth-cascade. Posts the live camera to the existing
  /api/body/lod endpoint (same protocol /body uses) and folds the per-concept
  reject byte into the SAME geometry index rebuild as the layer toggles — not a
  fragment discard — so early-Z survives and the GPU draws strictly fewer
  triangles when zoomed in. Absent endpoint (old deploy) silently keeps the full
  render; a near-total cull is treated as a camera-mapping miss and shows all.

All additive: the decode/normal/Gouraud hot path is unchanged; the LOD cull and
the layer mask share one linear index pass, so the mobile geometry-exclusion
lever still holds. tsc + vite build clean.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhpwkHGgia2TuDFvdnuQdE
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Re-bakes body/helix SoA assets to version 20260629b, updates Docker and manifest references accordingly. Fixes lumen fill radius ballooning with a two-pass CAP/PCTL algorithm, extends dental bone classification, and substantially upgrades BodyHelix.tsx with per-concept outlier rejection, dynamic geometry index rebuild, server LOD, and x-ray mode. Adds a planning doc for a future /cesium splat viewer.

Changes

Bake Pipeline Fixes and Asset Re-versioning

Layer / File(s) Summary
Two-pass lumen fill radius clamping
crates/osint-bake/tools/fill_body_soa.py
Adds CAP and PCTL tuning constants and replaces the single-pass ring accumulation with a two-pass strategy: collects raw per-bin radii at a low percentile, derives per-vessel caliber, then clamps final rings to [RMIN, cap].
Dental bone classification
crates/osint-bake/tools/bake_torso_splat.py
Extends the NAMEKEYS "bone" fallback keyword list with tooth/dentition terms so dental structures are bucketed with the skeleton layer rather than flesh/skin.
Asset version bump to 20260629b
Dockerfile, cockpit/public/body.manifest.json
Updates curl targets in the Dockerfile and helix_latest in the manifest from 20260629 to 20260629b bake filenames.

BodyHelix Viewer Decode and Render Upgrade

Layer / File(s) Summary
Decoded interface and binary layout
cockpit/src/BodyHelix.tsx
Extends Decoded with vrow and conceptList; adjusts binary offset math for the per-concept label index and centroid region.
Per-concept outlier rejection and conceptList construction
cockpit/src/BodyHelix.tsx
After per-vertex array construction, groups vertices by concept, computes a p95-radius outlier mask, drops triangles touching outlier vertices, and builds conceptList with centroid positions and names.
Shader/mount API and dynamic index rebuild
cockpit/src/BodyHelix.tsx
Removes the fragment-discard shader approach; introduces uAlpha uniform, Focus type, and mount signature accepting xray/lod refs. Mount precomputes per-triangle layer/concept IDs and rebuilds the active index buffer on demand when layer toggles change.
Server-driven LOD and x-ray tick loop
cockpit/src/BodyHelix.tsx
Adds periodic POST to /api/body/lod with camera view parameters, updates per-concept lodAction gate on response, forces geometry re-filtering via dirty flags, falls back to full rendering on failure. Tick loop toggles material transparent/depthWrite and sets uAlpha for x-ray.
React state, effects, and concept search UI
cockpit/src/BodyHelix.tsx
Adds xray/lod/query state and matching refs, synchronizes refs via effects, re-instantiates mount with expanded parameters. Sidebar gains search filtering and grouped expandable layer lists with focus-on-concept click.

Cesium HHTL Splat Viewer Planning Doc

Layer / File(s) Summary
Cesium splat viewer plan P0–P5
claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md
New doc defining the Signed360/quat_wxyz core insight, existing module inventory, staged phases with falsification gates J1/J3, cross-repo format rules, and the first provable native Rust probe for J1 round-trip validation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • AdaWorldAPI/q2#41: The root multi-stage Dockerfile introduced there is the same file whose asset download URLs are updated in this PR.
  • AdaWorldAPI/q2#64: Introduces the /api/body/lod server endpoint that the new LOD subsystem in BodyHelix.tsx POSTs to.
  • AdaWorldAPI/q2#65: Touches the same helix SoA bake pipeline and BodyHelix.tsx viewer decode/render path as this PR.

Poem

🐇 A new bake is born, 20260629b!
The lumen no longer balloons at each bend,
Teeth now join bones — the skeleton grows,
X-ray and LOD: concepts come and go,
And /cesium awaits, just a plan for now,
Hop hop, little splat, we'll get there somehow! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the 20260629b helix re-bake plus the new browser features like search, x-ray, and LOD.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@AdaWorldAPI AdaWorldAPI merged commit e32429d into main Jun 29, 2026
3 of 5 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md (2)

74-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Clarify WebGL2 vs WebGPU target priority in P4.

P4 states "WebGL2/WebGPU" as the rasterization target. These have substantially different 3DGS performance characteristics — WebGPU's compute shaders enable proper tile-based sorting and splatting, while WebGL2 requires slower fragment-shader workarounds. Given that /cesium is explicitly the path where "ndarray→wasm pays off because 3DGS rasterization is heavy SoA compute," specifying the primary target (likely WebGPU with WebGL2 fallback) would help scope the wasm boundary and J3 precision gate correctly.

🤖 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 `@claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md` around lines 74 -
79, Clarify the rasterization target in the P4 section by explicitly naming the
primary path and fallback, since “WebGL2/WebGPU” is ambiguous. Update the
`/cesium` description to state whether `splat3d` is intended for WebGPU-first
with WebGL2 fallback (or vice versa), and align the wasm scope wording so
`splat3d`, `sse`, and the “ndarray→wasm” boundary reflect that chosen priority.

98-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add explicit J1 tolerance thresholds and probe place-anchor specification.

The J1 probe description is excellent in scope, but two details would make it immediately actionable:

  1. Tolerance thresholds: The normal-path benchmark cites "mean 0.26°" — the quaternion path should specify both a per-gaussian rotation error bound (e.g., mean/max degrees) and a covariance Σ relative error bound (e.g., Frobenius norm < 1e-3) for the "green" verdict.
  2. Place anchor: start = CurveRuler::from_hhtl(tile_path, depth) requires a HHTL context. For the standalone probe, specify whether start is derived from a synthetic fixed tile (e.g., HEEL/0/0/0/0), the centroid of the .ply bounding box, or another deterministic reference — otherwise J1 results may vary by place and fail reproducibility.
🤖 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 `@claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md` around lines 98 -
104, The J1 probe description is missing the exact pass/fail criteria and the
deterministic place anchor needed to make it reproducible. Update the J1 probe
spec to explicitly define the “green” thresholds for per-gaussian rotation error
and covariance Σ relative error, and state the anchor source used to derive the
place-relative `Signed360` reference for the standalone Rust probe. Reference
the J1 probe, `Signed360`, `GaussianBatch`, and `CurveRuler::from_hhtl` when
clarifying how the real `.ply` input is normalized and evaluated.
🤖 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 `@claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md`:
- Around line 12-23: The dimensionality description for Signed360 is overstated
and should match the actual codec used by BodyHelix.tsx. Update the prose in
this note so it clearly says the full 6-byte Signed360 payload (the rim endpoint
pair plus polar and azimuth fields) carries the 3-DOF orientation, and avoid
implying that the two Fisher-Z rim values alone provide the full
quaternion-equivalent information. Refer to Signed360, BodyHelix.tsx, and the
“rimu/end, polar, az16” decode terms to keep the wording aligned with the
implementation.

In `@cockpit/src/BodyHelix.tsx`:
- Around line 491-500: The layer header and concept row click targets in
BodyHelix are plain clickable divs, so they are not keyboard-operable. Update
the expandable header around setOpen/expanded and the concept row that calls
focusOn(c) to use semantic button elements where possible, or add tabIndex,
appropriate role, and keyboard handlers for Enter/Space so keyboard users can
expand groups and focus rows.
- Around line 179-196: The outlier pass in BodyHelix is doing heavy decode-time
allocation and sorting by building per-concept JS arrays, mapping positions
repeatedly, and sorting full distance lists. Refactor this block to use a
typed-array bucket pass and a cheaper percentile strategy (sampling or linear
selection) instead of allocating and sorting multiple arrays per concept. Keep
the logic centered around the outlier clustering section that uses byC, median,
dist, and p95, and consider applying the clamp only to concepts that actually
need it.
- Around line 326-333: Reset the LOD state back to full visibility when the LOD
fetch fails or returns unusable data. In the promise chain inside BodyHelix’s
LOD update logic, make the failure path and any incomplete action-set handling
restore lodAction to visible for all concepts and mark lodDirty/dirty.current so
the render refreshes, instead of only setting lodFail. Also guard the success
path in the .then handler so if j.actions is missing/short or the response is
otherwise incomplete, it falls back to full visibility rather than leaving stale
hidden entries.

In `@crates/osint-bake/tools/bake_torso_splat.py`:
- Around line 88-92: The dental substring list in bake_torso_splat.py is too
broad and can misclassify non-tooth concepts because tissue_of() uses raw
substring matching later on. Tighten the fix by limiting tooth bucketing to
safer, tooth-specific identifiers in the mapping logic around tissue_of() rather
than broad terms like incisor/canine/premolar, and ensure gingiva-related names
still resolve to flesh instead of bone.

In `@crates/osint-bake/tools/fill_body_soa.py`:
- Around line 38-43: The comments near CAP and PCTL use the Unicode
multiplication sign, which Ruff flags as ambiguous text. Update the affected
inline comments in fill_body_soa.py (including the later matching comment around
the same constant block) to use plain ASCII text instead of ×, keeping the
wording otherwise unchanged. Use the CAP and PCTL constant definitions as the
anchor points when locating the comments.

---

Nitpick comments:
In `@claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md`:
- Around line 74-79: Clarify the rasterization target in the P4 section by
explicitly naming the primary path and fallback, since “WebGL2/WebGPU” is
ambiguous. Update the `/cesium` description to state whether `splat3d` is
intended for WebGPU-first with WebGL2 fallback (or vice versa), and align the
wasm scope wording so `splat3d`, `sse`, and the “ndarray→wasm” boundary reflect
that chosen priority.
- Around line 98-104: The J1 probe description is missing the exact pass/fail
criteria and the deterministic place anchor needed to make it reproducible.
Update the J1 probe spec to explicitly define the “green” thresholds for
per-gaussian rotation error and covariance Σ relative error, and state the
anchor source used to derive the place-relative `Signed360` reference for the
standalone Rust probe. Reference the J1 probe, `Signed360`, `GaussianBatch`, and
`CurveRuler::from_hhtl` when clarifying how the real `.ply` input is normalized
and evaluated.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2d4fe08d-56e0-4080-ba6f-4a9689645d49

📥 Commits

Reviewing files that changed from the base of the PR and between 0fbc1fd and 7896f76.

📒 Files selected for processing (6)
  • Dockerfile
  • claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md
  • cockpit/public/body.manifest.json
  • cockpit/src/BodyHelix.tsx
  • crates/osint-bake/tools/bake_torso_splat.py
  • crates/osint-bake/tools/fill_body_soa.py

Comment on lines +12 to +23
helix `Signed360`'s rim is the **`(start, end)` endpoint pair**, each a Fisher-Z
point on the φ-spiral. Two sphere points = a great-circle **arc** = a **rotation**
(3-DOF, a 4D unit quaternion's worth). The crate frames it exactly so: `start` =
"where the arc begins" (the HHTL place anchor, `CurveRuler::from_hhtl(path,depth)`),
`end` = the residue. So the 2 Fisher-Z values do **3D/4D work** — a rotation
**relative to the HHTL tile frame**.

That is precisely a 3DGS gaussian's orientation: `GaussianBatch.quat_wxyz`,
consumed by `Spd3::from_scale_quat` → Σ = R·diag(s²)·Rᵀ. So **helix is the splat
orientation carrier** (place-relative), not sidelined by the quaternion
requirement — it satisfies it. The shading normal `/helix` decodes is just one
2-DOF projection of this fuller frame.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Clarify the Signed360 encoding dimensionality claim.

The document states "2 Fisher-Z values do 3D/4D work" and "3-DOF, a 4D unit quaternion's worth." However, the downstream BodyHelix.tsx decode (lines 140-180) shows Signed360 as a 6-byte encoding: end (rim endpoint), polar (signed polar lift), and az16 (golden azimuth). Two Fisher-Z sphere points define a great-circle arc (2-DOF), but the full normal decode requires the additional polar+azimuth bytes to resolve hemisphere and direction. For a full 3-DOF quaternion, the encoding must preserve all three degrees of freedom — the J1 gate will validate this, but the prose understates the actual 6-byte payload and risks confusing readers about whether the "2 Fisher-Z" rim alone suffices. Consider rephrasing to "the 6-byte Signed360 (rim pair + polar/azimuth) carries 3-DOF orientation" to match the real codec.

🤖 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 `@claude-notes/plans/2026-06-29-cesium-hhtl-splat-viewer.md` around lines 12 -
23, The dimensionality description for Signed360 is overstated and should match
the actual codec used by BodyHelix.tsx. Update the prose in this note so it
clearly says the full 6-byte Signed360 payload (the rim endpoint pair plus polar
and azimuth fields) carries the 3-DOF orientation, and avoid implying that the
two Fisher-Z rim values alone provide the full quaternion-equivalent
information. Refer to Signed360, BodyHelix.tsx, and the “rimu/end, polar, az16”
decode terms to keep the wording aligned with the implementation.

Comment thread cockpit/src/BodyHelix.tsx
Comment on lines +179 to +196
const byC: number[][] = Array.from({ length: nC }, () => []);
for (let i = 0; i < nV; i++) { const c = rowArr[i]; if (c < nC) byC[c].push(i); }
const median = (a: number[]) => { const s = a.slice().sort((x, y) => x - y); return s[s.length >> 1]; };
const outlier = new Uint8Array(nV);
let nOut = 0, worst = 0;
for (let c = 0; c < nC; c++) {
const vs = byC[c];
if (vs.length < 8) continue;
const cx = median(vs.map((i) => positions[i * 3]));
const cy = median(vs.map((i) => positions[i * 3 + 1]));
const cz = median(vs.map((i) => positions[i * 3 + 2]));
const dist = vs.map((i) => Math.hypot(positions[i * 3] - cx, positions[i * 3 + 1] - cy, positions[i * 3 + 2] - cz));
const ds = dist.slice().sort((a, b) => a - b);
const p95 = ds[Math.min(ds.length - 1, Math.floor(ds.length * 0.95))];
const thr = Math.max(p95 * 1.8, 1e-3); // generous margin → only true far strays drop
for (let k = 0; k < vs.length; k++) {
if (dist[k] > thr) { outlier[vs[k]] = 1; nOut++; worst = Math.max(worst, dist[k] / Math.max(p95, 1e-4)); }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Reduce decode-time allocation and sorting in the outlier pass.

This groups every vertex into JS arrays, then allocates and sorts multiple per-concept arrays. On the multi-million-triangle helix asset, that can reintroduce load-time freezes before rendering starts. Consider a typed-array bucket pass plus sampled/linear percentile selection, or limit the clamp to concepts/classes that need it.

🤖 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 `@cockpit/src/BodyHelix.tsx` around lines 179 - 196, The outlier pass in
BodyHelix is doing heavy decode-time allocation and sorting by building
per-concept JS arrays, mapping positions repeatedly, and sorting full distance
lists. Refactor this block to use a typed-array bucket pass and a cheaper
percentile strategy (sampling or linear selection) instead of allocating and
sorting multiple arrays per concept. Keep the logic centered around the outlier
clustering section that uses byC, median, dist, and p95, and consider applying
the clamp only to concepts that actually need it.

Comment thread cockpit/src/BodyHelix.tsx
Comment on lines +326 to +333
.then((j: { actions: number[]; n_concepts?: number; tally?: number[] }) => {
const a = j.actions;
const visible = (j.n_concepts ?? a.length) - (j.tally?.[0] ?? 0);
const degenerate = visible <= Math.max(1, a.length * 0.02); // cascade culled ~all ⇒ camera map suspect → show all
for (let i = 0; i < d.concepts && i < a.length; i++) lodAction[i] = degenerate ? 255 : a[i];
lodDirty = true; dirty.current = true;
})
.catch(() => { lodFail = true; }) // endpoint absent (old deploy) → keep full render

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset LOD gates when the endpoint fails or returns an incomplete action set.

After any successful LOD cull, a later error only sets lodFail; it does not restore lodAction to full visibility, so previously hidden concepts can stay hidden indefinitely while LOD appears enabled.

🐛 Proposed fix
-      .then((j: { actions: number[]; n_concepts?: number; tally?: number[] }) => {
-        const a = j.actions;
+      .then((j: { actions: number[]; n_concepts?: number; tally?: number[] }) => {
+        const a = Array.isArray(j.actions) ? j.actions : [];
+        if (a.length < d.concepts) {
+          lodAction.fill(255);
+          lodDirty = true; dirty.current = true;
+          return;
+        }
         const visible = (j.n_concepts ?? a.length) - (j.tally?.[0] ?? 0);
         const degenerate = visible <= Math.max(1, a.length * 0.02);   // cascade culled ~all ⇒ camera map suspect → show all
         for (let i = 0; i < d.concepts && i < a.length; i++) lodAction[i] = degenerate ? 255 : a[i];
         lodDirty = true; dirty.current = true;
       })
-      .catch(() => { lodFail = true; })   // endpoint absent (old deploy) → keep full render
+      .catch(() => {
+        lodFail = true;
+        lodAction.fill(255);
+        lodDirty = true; dirty.current = true;
+      })   // endpoint absent (old deploy) → keep full render
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.then((j: { actions: number[]; n_concepts?: number; tally?: number[] }) => {
const a = j.actions;
const visible = (j.n_concepts ?? a.length) - (j.tally?.[0] ?? 0);
const degenerate = visible <= Math.max(1, a.length * 0.02); // cascade culled ~all ⇒ camera map suspect → show all
for (let i = 0; i < d.concepts && i < a.length; i++) lodAction[i] = degenerate ? 255 : a[i];
lodDirty = true; dirty.current = true;
})
.catch(() => { lodFail = true; }) // endpoint absent (old deploy) → keep full render
.then((j: { actions: number[]; n_concepts?: number; tally?: number[] }) => {
const a = Array.isArray(j.actions) ? j.actions : [];
if (a.length < d.concepts) {
lodAction.fill(255);
lodDirty = true; dirty.current = true;
return;
}
const visible = (j.n_concepts ?? a.length) - (j.tally?.[0] ?? 0);
const degenerate = visible <= Math.max(1, a.length * 0.02); // cascade culled ~all ⇒ camera map suspect → show all
for (let i = 0; i < d.concepts && i < a.length; i++) lodAction[i] = degenerate ? 255 : a[i];
lodDirty = true; dirty.current = true;
})
.catch(() => {
lodFail = true;
lodAction.fill(255);
lodDirty = true; dirty.current = true;
}) // endpoint absent (old deploy) → keep full render
🤖 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 `@cockpit/src/BodyHelix.tsx` around lines 326 - 333, Reset the LOD state back
to full visibility when the LOD fetch fails or returns unusable data. In the
promise chain inside BodyHelix’s LOD update logic, make the failure path and any
incomplete action-set handling restore lodAction to visible for all concepts and
mark lodDirty/dirty.current so the render refreshes, instead of only setting
lodFail. Also guard the success path in the .then handler so if j.actions is
missing/short or the response is otherwise incomplete, it falls back to full
visibility rather than leaving stale hidden entries.

Comment thread cockpit/src/BodyHelix.tsx
Comment on lines +491 to +500
<div onClick={() => setOpen((p) => ({ ...p, [l.id]: !expanded }))}
style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '7px 8px', cursor: 'pointer', color: '#cdd9e5', font: '12px ui-monospace, monospace', userSelect: 'none' }}>
<span style={{ width: 8, opacity: 0.7 }}>{expanded ? '▾' : '▸'}</span>
<span style={{ display: 'inline-block', width: 9, height: 9, borderRadius: 5, background: l.color }} />
<span style={{ flex: 1 }}>{l.name}</span>
<span style={{ opacity: 0.45 }}>{items.length}</span>
</div>
{expanded && items.slice(0, 500).map((c) => (
<div key={c.row} onClick={() => focusOn(c)} title={c.name}
style={{ padding: '4px 8px 4px 30px', cursor: 'pointer', color: '#9fb0c2', font: '12px ui-monospace, monospace', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', borderRadius: 5 }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make browser rows keyboard-operable.

The expandable layer headers and concept rows are clickable <div> elements without tabIndex, role, or keyboard handlers, so keyboard users cannot expand groups or focus structures. Prefer <button> elements styled as rows, or add equivalent keyboard semantics.

🤖 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 `@cockpit/src/BodyHelix.tsx` around lines 491 - 500, The layer header and
concept row click targets in BodyHelix are plain clickable divs, so they are not
keyboard-operable. Update the expandable header around setOpen/expanded and the
concept row that calls focusOn(c) to use semantic button elements where
possible, or add tabIndex, appropriate role, and keyboard handlers for
Enter/Space so keyboard users can expand groups and focus rows.

Comment on lines +88 to +92
"ischium", "pubis", "sacrum", "manubrium", "xiphoid",
# teeth are not is_a bone in FMA (dentin/enamel, not skeletal element), so
# they fell through to "flesh" → layer 1 (skin), hidden in the skeleton view
# (toothless skull). Bucket them with the skeleton; gingiva stays flesh.
"tooth", "molar", "incisor", "canine", "premolar", "cuspid"]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

These dental substrings are broader than the intended fix.

tissue_of() falls back with raw substring checks at Lines 278-279, so adding "incisor", "canine", "premolar", etc. will also classify any non-tooth concept whose canonical name merely mentions a tooth as "bone". That means the "gingiva stays flesh" guarantee in this comment is not actually enforced.

🤖 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 `@crates/osint-bake/tools/bake_torso_splat.py` around lines 88 - 92, The dental
substring list in bake_torso_splat.py is too broad and can misclassify non-tooth
concepts because tissue_of() uses raw substring matching later on. Tighten the
fix by limiting tooth bucketing to safer, tooth-specific identifiers in the
mapping logic around tissue_of() rather than broad terms like
incisor/canine/premolar, and ensure gingiva-related names still resolve to flesh
instead of bone.

Comment on lines +38 to +43
CAP = 2.0 # PER-VESSEL diameter boundary: a ring may not exceed this vessel's own
# caliber × CAP. RMAX alone lets a finger artery balloon to aorta size at
# a bend; this keeps a capillary a capillary through its bends.
PCTL = 0.30 # per-bin radius percentile (NOT the median): at a strong bend two arms
# share one axial bin and the median perp-distance is ~half the gap (a
# balloon); the low percentile picks the near wall = the true radius.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the Unicode multiplication sign in these comments.

Ruff is already flagging × at Lines 39 and 140 as ambiguous text, so this change will keep lint noise around until those are switched to plain ASCII.

Minimal cleanup
-               # caliber × CAP. RMAX alone lets a finger artery balloon to aorta size at
+               # caliber x CAP. RMAX alone lets a finger artery balloon to aorta size at
...
-    # (robust median of the bin radii) × CAP, then the absolute RMAX. A capillary stays a
+    # (robust median of the bin radii) x CAP, then the absolute RMAX. A capillary stays a

Also applies to: 139-140

🧰 Tools
🪛 Ruff (0.15.18)

[warning] 39-39: Comment contains ambiguous × (MULTIPLICATION SIGN). Did you mean x (LATIN SMALL LETTER X)?

(RUF003)

🤖 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 `@crates/osint-bake/tools/fill_body_soa.py` around lines 38 - 43, The comments
near CAP and PCTL use the Unicode multiplication sign, which Ruff flags as
ambiguous text. Update the affected inline comments in fill_body_soa.py
(including the later matching comment around the same constant block) to use
plain ASCII text instead of ×, keeping the wording otherwise unchanged. Use the
CAP and PCTL constant definitions as the anchor points when locating the
comments.

Source: Linters/SAST tools

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