Skip to content

Commit 6698969

Browse files
committed
feat(helix+contract): Signed360 signed full-sphere codec + right-size HelixResidue 48B->6B
Operator caught the slab over-allocation: HelixResidue reserved 48 BYTES but the intent was a 24-bit equal-area hemisphere DOUBLED = 48 BIT = 6 bytes (a bits->bytes slip; 42 dead bytes), and the tenant used NONE of the helix crate. helix crate (the math, where it belongs): - HemispherePoint::signed_lift(n,N,sign) -- y = sign*sqrt(1-u), the full sphere (y in [-1,1]); r^2+y^2=1 preserved; Sign{Pos,Neg}. - Signed360 -- 6-byte signed full-sphere residue {rim: ResidueEdge (unsigned hemisphere), polar: signed lift centred@128 (sign recoverable via .sign()), azimuth: u16 over the full 360deg (n*phi mod 2pi)}; ResidueEncoder::encode_signed. - +9 tests; helix 72 lib + 7 doctests green; lib clippy -D warnings + fmt clean. contract (right-size only, NO new type): - HelixResidue elems_per_row 48 -> 6; downstream tenants shifted (Turbovec 118 / Energy 134 / Plasticity 138 / EntityType 142); budgets re-locked (Full 154->112, Compressed 98->56). 613 contract lib green; clippy/fmt clean. - NO HelixFlavour enum: one canonical encoding, one tenant size (the fixed-offset SoA can't vary width per-class; Hemisphere = degenerate sign=+). Contract stays zero-dep; the producer writes helix::Signed360::to_bytes into the reserved 6 B. Cheap now (POC FULL default, no persisted real instances); after instances persist it is a version bump. Board: LATEST_STATE note + TD-HELIX-PROBE-CLIPPY (pre-existing probe_mantissa_fill clippy/fmt debt, NOT introduced here). https://claude.ai/code/session_01D2WSmezQBNC3bUdHuGfGmo
1 parent 5bee687 commit 6698969

6 files changed

Lines changed: 268 additions & 16 deletions

File tree

.claude/board/LATEST_STATE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
1111
---
1212

13+
> **2026-06-15 — branch work (post-#496)** — **helix `Signed360` codec + `HelixResidue` right-sized 48 B → 6 B.** Operator caught a slab over-allocation: `HelixResidue` reserved **48 *bytes*** but the intent was a 24-bit equal-area hemisphere **doubled = 48 *bit* = 6 B** (a bits→bytes slip; 42 dead bytes), and the tenant used **none** of the `helix` crate (zero-dep contract — only a doc string). Fixed: **(1) `helix::Signed360`** — the signed full-sphere codec: `HemispherePoint::signed_lift(n,N,sign)` (`y = sign·√(1−u)` → full sphere, `r²+y²=1`), `Sign{Pos,Neg}`, and `Signed360 {rim: ResidueEdge, polar: signed-lift centred@128 (sign recoverable), azimuth: u16 over 360°}` + `ResidueEncoder::encode_signed`. +9 tests; **helix 72 lib + 7 doctests green; lib clippy `-D warnings` + fmt clean.** **(2) contract** `HelixResidue.elems_per_row` 48→6, downstream tenants shifted (Turbovec 118 / Energy 134 / Plasticity 138 / EntityType 142), budgets re-locked (**Full 154→112, Compressed 98→56**); **613 contract green.** **NO `HelixFlavour` enum** — one canonical encoding, one tenant size (a fixed-offset SoA can't vary width per-class; Hemisphere = degenerate `sign=+`); the contract stays zero-dep, the producer writes `Signed360::to_bytes` into the 6 B. Cheap NOW (POC FULL default, no persisted real instances); after instances persist it's a version bump. Branch, not yet a PR. New: `TD-HELIX-PROBE-CLIPPY` (pre-existing `probe_mantissa_fill` clippy/fmt drift, NOT introduced here — helix is excluded so CI-invisible, same class as the standing `causal-edge` 47/1 red).
14+
>
1315
> **2026-06-15 — MERGED #496** (integrated-cognitive-planner reference map + ValueSchema + FULL POC default): `lance_graph_contract::canonical_node::{ValueSchema, ValueTenant, VALUE_TENANTS}` — the value-side `EdgeCodecFlavor` analog (9 append-only tenants carving `[32,186)`; presets Bootstrap/Cognitive/Compressed/Full). `ClassView::value_schema()` default flipped **Bootstrap→Full (TEMPORARY POC** — every unconfigured class materialises the full slab so consumers transcode against it; `TD-VALUESCHEMA-FULL-POC-DEFAULT` revert-when-POC-concludes; type-level `ValueSchema::default()` stays Bootstrap, only class→schema *resolution* flips). New reference plan `.claude/plans/integrated-cognitive-planner-v1.md` — **§0 ANTI-INVENTION GUARDRAIL (READ FIRST)**, §1–§7 grounded file:line map, §8 7-item additive ledger, §9 3-hardener verdicts; the SPEC for the integrated-planner refactor (~90% exists; remaining = the keystone + 6 seams, NOT a new build). CI 5/5 green; contract 613 lib tests; merge `2e58e034`. **The keystone = `NiblePath::from_guid_prefix` (the 20→≤16-nibble subset) + classid→ClassView read-mode on `lance-graph-ontology::registry` (already an immutable conflict-refusing `entity_type↔NiblePath` bijection)** — the single next unblock that converges the refactor, the tesseract-rs OCR transcode (`contract::ocr` → NodeRow), AND the OGAR-identity migration (`soa-migration-diff-resolution-2026-06-13.md`). HEEL=cache `dolce_id` / HIP·TWIG=deterministic subClassOf descent / registry=recorder-not-minter (verified `registry.rs`+`wikidata_hhtl.rs`). New: `TD-COARSERESIDUE-NO-VALUE-TENANT`, `TD-LAZY-IMPORT-VERSION-PIN`; IDEAS CLAM-residue-ladder TODO.
1416
>
1517
> **2026-06-13 — shipped (autoattended, cross-repo)** (turbovec ⇄ ndarray): new excluded standalone crate **`crates/lance-graph-turbovec`** — Google TurboQuant (arXiv 2504.19874, the AdaWorldAPI `turbovec` fork) bridged onto the spine. `TurboVec` wraps `turbovec::TurboQuantIndex` with a `Kernel::{NativeLut, PolyfillGemm}` A/B switch. **Cross-repo (branch `claude/wonderful-hawking-lodtql` in turbovec + ndarray + lance-graph):** turbovec re-pointed from crates.io `ndarray 0.17` → the AdaWorldAPI fork (path, P0 forks-only; `blas` opt-in so default builds BLAS-free; `rust-toolchain.toml` = 1.95.0); new `turbovec::search_polyfill` (feature `ndarray-simd`) expresses scoring as a batched int8 GEMM via **`ndarray::simd::matmul_i8_to_i32`** (re-exported through `simd.rs` — AMX `TDPBUSD` tile → AVX-512 VPDPBUSD → AVX-VNNI → scalar, dispatched inside ndarray, zero intrinsics in turbovec). **Measured finding (E-TURBOVEC-AMX-WRONG-TOOL-1):** the polyfill GEMM is 11.4× SLOWER than the native nibble-LUT (TurboQuant trades the matmul away → AMX accelerates the op it removed); native LUT stays production, polyfill is the AMX-ready baseline. Placement: index → spine, kernel-math → ndarray (already owns clam/cam_pq/cascade/amx_matmul). Synergy map (HDR popcount stacking early-exit, Belichtungsmesser σ thresholds, preheating vs palette256) in `crates/lance-graph-turbovec/KNOWLEDGE.md`. Tests green in all three repos; benchmark via `examples/kernel_speed.rs`. NOT a merged PR yet (branch work).

.claude/board/TECH_DEBT.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515

1616
## Open Debt
1717

18+
### TD-HELIX-PROBE-CLIPPY — `helix` `tests/probe_mantissa_fill.rs` pre-existing clippy + fmt drift (2026-06-15)
19+
20+
**Surfaced by** the helix `Signed360` work (2026-06-15): `cargo clippy --manifest-path crates/helix/Cargo.toml --all-targets -- -D warnings` fails on `tests/probe_mantissa_fill.rs:170``clippy::needless_range_loop` (`for b in 0..BINS*BINS` indexing `counts`), under clippy 1.95.0. The same file has pre-existing `cargo fmt` drift (the `SEEDS` const + several `assert_eq!`/`assert!` calls exceed the width, unwrapped). **Pre-existing, NOT caused by the `Signed360` addition** (that's all in `src/`, additive; this integration test was never touched). **CI-invisible** because `helix` is a root-`exclude`d crate — the lance-graph workspace gate never builds it. Same class as the standing `causal-edge` 47/1 red (`test_build_fast`) on main.
21+
22+
**Pay it by** rewriting the `for b in 0..BINS*BINS` loop as `counts.iter().enumerate()` (or `iter_mut`) + `cargo fmt --manifest-path crates/helix/Cargo.toml`. Trivial; deferred ONLY to keep the `Signed360` commit scoped. `cargo test` on helix is green (the probe passes as a test; only `clippy --all-targets -D warnings` flags the lint). Cross-ref: the helix `Signed360` branch commit.
23+
1824
### TD-LAZY-IMPORT-VERSION-PIN — lazy OGIT/ontology imports MUST be version-pinned + reserve-don't-reclaim sibling nibbles (2026-06-15)
1925

2026
**Surfaced by** operator design dialogue (2026-06-15: "OGIT as a lazy import in Rust-based OGAR — could DOLCE / Odoo etc. drift?"). The drift-control architecture is layered + sound; two disciplines must be LOCKED before the OGAR-identity migration runs a real (non-fixture) lazy import.

crates/helix/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub use constants::{
7474
pub use curve_ruler::CurveRuler;
7575
pub use distance::DistanceLut;
7676
pub use fisher_z::Similarity;
77-
pub use placement::HemispherePoint;
77+
pub use placement::{HemispherePoint, Sign};
7878
pub use prove::{prove, ProofResult};
7979
pub use quantize::RollingFloor;
80-
pub use residue::{ResidueEdge, ResidueEncoder};
80+
pub use residue::{ResidueEdge, ResidueEncoder, Signed360};

crates/helix/src/placement.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,42 @@
2222
2323
use crate::constants::GOLDEN_RATIO;
2424

25+
/// Hemisphere sign for the signed full-sphere lift
26+
/// ([`HemispherePoint::signed_lift`], the 48-bit
27+
/// [`Signed360`](crate::residue::Signed360) residue). `Pos` = upper hemisphere
28+
/// (`y ≥ 0`, the base [`lift`](HemispherePoint::lift)); `Neg` = the
29+
/// equator-mirrored lower hemisphere (`y ≤ 0`).
30+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31+
pub enum Sign {
32+
/// Upper hemisphere (`y ≥ 0`). Reproduces [`HemispherePoint::lift`] exactly.
33+
Pos,
34+
/// Lower hemisphere (`y ≤ 0`) — the base lift mirrored across the equator.
35+
Neg,
36+
}
37+
38+
impl Sign {
39+
/// `+1.0` for [`Pos`](Sign::Pos), `−1.0` for [`Neg`](Sign::Neg).
40+
#[inline]
41+
#[must_use]
42+
pub fn as_f64(self) -> f64 {
43+
match self {
44+
Sign::Pos => 1.0,
45+
Sign::Neg => -1.0,
46+
}
47+
}
48+
49+
/// The sign of a value: [`Neg`](Sign::Neg) iff `v < 0` (zero ⇒ [`Pos`](Sign::Pos)).
50+
#[inline]
51+
#[must_use]
52+
pub fn of(v: f64) -> Self {
53+
if v < 0.0 {
54+
Sign::Neg
55+
} else {
56+
Sign::Pos
57+
}
58+
}
59+
}
60+
2561
/// A single residue index lifted onto the equal-area hemisphere.
2662
///
2763
/// All three fields are computed in one call to [`HemispherePoint::lift`]; they
@@ -125,6 +161,32 @@ impl HemispherePoint {
125161
pub fn rim(&self) -> f64 {
126162
self.r
127163
}
164+
165+
/// Signed full-sphere lift — the equal-area hemisphere [`lift`](Self::lift)
166+
/// mirrored across the equator by `sign`, so `y = sign·√(1 − u)` ranges over
167+
/// the FULL sphere (`y ∈ [−1, 1]`) instead of one hemisphere (`y ∈ (0, 1]`).
168+
/// The unit-sphere identity `r² + y² = 1` still holds (`r` is unchanged).
169+
/// [`Sign::Pos`] reproduces [`lift`](Self::lift) exactly; [`Sign::Neg`] is the
170+
/// lower hemisphere. The two 24-bit hemispheres = the 48-bit
171+
/// [`Signed360`](crate::residue::Signed360) residue.
172+
///
173+
/// # Examples
174+
///
175+
/// ```
176+
/// use helix::placement::{HemispherePoint, Sign};
177+
///
178+
/// let up = HemispherePoint::lift(3, 10);
179+
/// let dn = HemispherePoint::signed_lift(3, 10, Sign::Neg);
180+
/// assert_eq!(dn.r, up.r); // same rim radius
181+
/// assert_eq!(dn.y, -up.y); // mirrored lift
182+
/// assert!((dn.r * dn.r + dn.y * dn.y - 1.0).abs() < 1e-12); // still on the sphere
183+
/// ```
184+
#[must_use]
185+
pub fn signed_lift(n: usize, total: usize, sign: Sign) -> Self {
186+
let mut p = Self::lift(n, total);
187+
p.y *= sign.as_f64();
188+
p
189+
}
128190
}
129191

130192
#[cfg(test)]
@@ -328,4 +390,48 @@ mod tests {
328390
frac_500 * 100.0
329391
);
330392
}
393+
394+
// ── signed full-sphere lift (Signed360) ──────────────────────────────────
395+
396+
#[test]
397+
fn signed_lift_pos_equals_lift() {
398+
for &(n, total) in &[(0usize, 10usize), (3, 10), (7, 17), (500, 1000)] {
399+
let up = HemispherePoint::lift(n, total);
400+
let s = HemispherePoint::signed_lift(n, total, Sign::Pos);
401+
assert_eq!(s, up, "Sign::Pos must reproduce lift exactly");
402+
}
403+
}
404+
405+
#[test]
406+
fn signed_lift_neg_mirrors_y_keeps_r() {
407+
for &(n, total) in &[(0usize, 10usize), (3, 10), (9, 10), (499, 1000)] {
408+
let up = HemispherePoint::lift(n, total);
409+
let dn = HemispherePoint::signed_lift(n, total, Sign::Neg);
410+
assert_eq!(dn.r, up.r, "Neg must keep the rim radius");
411+
assert_eq!(dn.y, -up.y, "Neg must mirror the lift across the equator");
412+
}
413+
}
414+
415+
#[test]
416+
fn signed_lift_stays_on_unit_sphere_both_signs() {
417+
for &(n, total) in &[(0usize, 1usize), (5, 10), (999, 1000), (7, 17)] {
418+
for sign in [Sign::Pos, Sign::Neg] {
419+
let p = HemispherePoint::signed_lift(n, total, sign);
420+
let sum = p.r * p.r + p.y * p.y;
421+
assert!(
422+
(sum - 1.0).abs() < 1e-12,
423+
"r²+y² must be 1 for ({n},{total},{sign:?}), got {sum}"
424+
);
425+
}
426+
}
427+
}
428+
429+
#[test]
430+
fn sign_helpers() {
431+
assert_eq!(Sign::Pos.as_f64(), 1.0);
432+
assert_eq!(Sign::Neg.as_f64(), -1.0);
433+
assert_eq!(Sign::of(-0.5), Sign::Neg);
434+
assert_eq!(Sign::of(0.0), Sign::Pos);
435+
assert_eq!(Sign::of(2.0), Sign::Pos);
436+
}
331437
}

crates/helix/src/residue.rs

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
//! *is* the residue. `encode` is the compute path (`&self`, read-only); `observe`
77
//! / `roll` are the calibration paths (`&mut self`) — honouring "no `&mut self`
88
//! during computation".
9-
use crate::constants::{EULER_GAMMA, LN_17, MODULUS, STRIDE};
9+
use crate::constants::{EULER_GAMMA, GOLDEN_RATIO, LN_17, MODULUS, STRIDE};
1010
use crate::curve_ruler::CurveRuler;
1111
use crate::distance::DistanceLut;
1212
use crate::fisher_z::Similarity;
13-
use crate::placement::HemispherePoint;
13+
use crate::placement::{HemispherePoint, Sign};
1414
use crate::quantize::RollingFloor;
1515

1616
/// A residue edge: the `(start, end)` endpoint pair on the φ-spiral curve-ruler,
@@ -60,6 +60,58 @@ impl ResidueEdge {
6060
}
6161
}
6262

63+
/// Signed full-sphere residue — the 24-bit hemisphere [`ResidueEdge`] **doubled
64+
/// to 48 bit (6 bytes)**. Maps a signed magnitude to the FULL sphere: the
65+
/// unsigned hemisphere `rim` edge (rim radius + place anchor via the existing
66+
/// pipeline), the signed `polar` byte (the equal-area lift `y = sign·√(1 − u)`
67+
/// quantised, centred at 128 — `> 128` upper hemisphere, `< 128` lower, so the
68+
/// hemisphere sign is recoverable), and the 16-bit `azimuth` (`n·φ` wrapped to
69+
/// `[0, 2π)` over the full **360°**). Wire layout (LE):
70+
/// `[rim.start, rim.end, rim.floor_version, polar, azimuth_lo, azimuth_hi]`.
71+
///
72+
/// This is the codec the contract `HelixResidue` value-tenant reserves 6 bytes
73+
/// for; the producer writes [`to_bytes`](Signed360::to_bytes). The contract
74+
/// itself is zero-dep and only reserves the bytes.
75+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76+
pub struct Signed360 {
77+
/// Unsigned hemisphere edge (rim radius + place anchor). 3 bytes.
78+
pub rim: ResidueEdge,
79+
/// Signed equal-area lift `y` quantised, centred at 128 (128 = equator,
80+
/// `> 128` = upper hemisphere, `< 128` = lower). 1 byte.
81+
pub polar: u8,
82+
/// Golden azimuth `n·φ mod 2π` mapped to `[0, 65536)` over the full 360°. 2 bytes.
83+
pub azimuth: u16,
84+
}
85+
86+
impl Signed360 {
87+
/// Serialise to 6 bytes (LE):
88+
/// `[rim.start, rim.end, rim.floor_version, polar, azimuth_lo, azimuth_hi]`.
89+
pub fn to_bytes(self) -> [u8; 6] {
90+
let r = self.rim.to_bytes();
91+
let a = self.azimuth.to_le_bytes();
92+
[r[0], r[1], r[2], self.polar, a[0], a[1]]
93+
}
94+
95+
/// Deserialise from 6 bytes.
96+
pub fn from_bytes(b: [u8; 6]) -> Self {
97+
Self {
98+
rim: ResidueEdge::from_bytes([b[0], b[1], b[2]]),
99+
polar: b[3],
100+
azimuth: u16::from_le_bytes([b[4], b[5]]),
101+
}
102+
}
103+
104+
/// Which hemisphere this residue sits in — recovered from the `polar` byte
105+
/// (`>= 128` ⇒ upper [`Sign::Pos`], `< 128` ⇒ lower [`Sign::Neg`]).
106+
pub fn sign(&self) -> Sign {
107+
if self.polar >= 128 {
108+
Sign::Pos
109+
} else {
110+
Sign::Neg
111+
}
112+
}
113+
}
114+
63115
/// The four-stage residue encoder: total residue count `N` + the rolling
64116
/// 256-palette floor.
65117
#[derive(Debug, Clone)]
@@ -117,6 +169,28 @@ impl ResidueEncoder {
117169
}
118170
}
119171

172+
/// Encode `(place, n, sign)` into a 6-byte [`Signed360`] — the signed
173+
/// full-sphere residue (the doubled-hemisphere companion to
174+
/// [`encode`](Self::encode)). The `rim` reuses the unsigned hemisphere
175+
/// pipeline; `polar` carries the signed equal-area lift `y = sign·√(1 − u)`
176+
/// (centred at 128, so the hemisphere sign is recoverable via
177+
/// [`Signed360::sign`]); `azimuth` is the golden angle `n·φ` over the full 360°.
178+
pub fn encode_signed(&self, place: u64, n: usize, sign: Sign) -> Signed360 {
179+
let n = n.min(self.total - 1);
180+
let rim = self.encode(place, n);
181+
// Signed equal-area lift y ∈ [−1, 1] → byte centred at 128.
182+
let p = HemispherePoint::signed_lift(n, self.total, sign);
183+
let polar = (128.0 + p.y * 127.0).round().clamp(0.0, 255.0) as u8;
184+
// Golden azimuth n·φ wrapped to [0, 2π) → u16 over the full 360°.
185+
let az = (n as f64 * GOLDEN_RATIO).rem_euclid(core::f64::consts::TAU);
186+
let azimuth = ((az / core::f64::consts::TAU) * 65536.0) as u16;
187+
Signed360 {
188+
rim,
189+
polar,
190+
azimuth,
191+
}
192+
}
193+
120194
/// Calibration: feed an observation through the floor's occupancy monitor.
121195
pub fn observe(&mut self, place: u64, n: usize) {
122196
let n = n.min(self.total - 1);
@@ -213,4 +287,64 @@ mod tests {
213287
let (_d, _below) = a.distance_heuristic(&a);
214288
assert_eq!(a.distance_heuristic(&a).0, 0);
215289
}
290+
291+
// ── Signed360 (signed full-sphere, 48-bit) ───────────────────────────────
292+
293+
#[test]
294+
fn signed360_byte_roundtrip_is_6_bytes() {
295+
let enc = ResidueEncoder::new(4096);
296+
let s = enc.encode_signed(0x1234, 1700, Sign::Neg);
297+
assert_eq!(Signed360::from_bytes(s.to_bytes()), s);
298+
assert_eq!(
299+
s.to_bytes().len(),
300+
6,
301+
"Signed360 is exactly 6 bytes (48 bit)"
302+
);
303+
}
304+
305+
#[test]
306+
fn signed360_rim_matches_unsigned_encode() {
307+
let enc = ResidueEncoder::new(4096);
308+
// The rim edge is the existing unsigned hemisphere encode (sign-independent).
309+
let rim = enc.encode(0x1234, 1700);
310+
assert_eq!(enc.encode_signed(0x1234, 1700, Sign::Pos).rim, rim);
311+
assert_eq!(enc.encode_signed(0x1234, 1700, Sign::Neg).rim, rim);
312+
}
313+
314+
#[test]
315+
fn signed360_sign_recoverable_from_polar() {
316+
let enc = ResidueEncoder::new(4096);
317+
for n in [1usize, 100, 1700, 4000] {
318+
let pos = enc.encode_signed(7, n, Sign::Pos);
319+
let neg = enc.encode_signed(7, n, Sign::Neg);
320+
assert_eq!(
321+
pos.sign(),
322+
Sign::Pos,
323+
"Pos ⇒ upper hemisphere (polar ≥ 128)"
324+
);
325+
assert_eq!(
326+
neg.sign(),
327+
Sign::Neg,
328+
"Neg ⇒ lower hemisphere (polar < 128)"
329+
);
330+
assert!(pos.polar >= 128 && neg.polar < 128);
331+
}
332+
}
333+
334+
#[test]
335+
fn signed360_azimuth_varies_with_n() {
336+
let enc = ResidueEncoder::new(4096);
337+
let a = enc.encode_signed(7, 100, Sign::Pos).azimuth;
338+
let b = enc.encode_signed(7, 101, Sign::Pos).azimuth;
339+
assert_ne!(a, b, "consecutive residues get distinct golden azimuths");
340+
}
341+
342+
#[test]
343+
fn signed360_is_deterministic() {
344+
let enc = ResidueEncoder::new(4096);
345+
assert_eq!(
346+
enc.encode_signed(0x99, 2000, Sign::Neg),
347+
enc.encode_signed(0x99, 2000, Sign::Neg)
348+
);
349+
}
216350
}

0 commit comments

Comments
 (0)