Skip to content

ring-096 and formats.t27 agree on f32 (Closes #5746) - #5921

Open
gHashTag wants to merge 1 commit into
masterfrom
fix/ring-096-formats-drift
Open

gHashTag wants to merge 1 commit into
masterfrom
fix/ring-096-formats-drift

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #5746
Part of #5906

Decision: the spec is the truth, so the ring follows it (option a)

The law that decides it:

  • docs/T27-CONSTITUTION.md Article SSOT-MATH: "The mathematical, numeric, and physical meaning of Trinity S³AI / t27 has one normative source of truth: specifications in the t27 language (*.t27 files), exercised through the official tri pipeline..."
  • AGENTS.md: "Specs are source of truth -- behavior belongs in .t27 / .tri"
  • SOUL.md: "T27 is a spec-first architecture where mathematical truth, not implementation, is the source of truth."
  • L6 (Constitution): "conformance/FORMAT-SPEC-001.json + specs/numeric/gf16.t27 are the numeric ceiling -- never forked"

The spec was wrong in one place. gf16_to_f32, ternary_to_f32 and quantize_value returned gf16, which lowers to u16, an encoding, although each one produces a float. They now return f32. That is the same boundary the L6 codec already uses: gf16_encode_f32(value: f32) GF16 and gf16_decode_to_f32(gf16: GF16) f32. So the change agrees with L6 and does not fork it.

Changes

  • specs/numeric/formats.t27
    • The three return types change from gf16 to f32.
    • Tests no longer call gf16.to_f64, which gf16.t27 never declares. They compare f32 values directly.
    • gf16_to_f32_normal_one now uses 0x3E00. Under FORMAT-SPEC-001.json (GF16 bias 31, 2^(E-31) * (1 + M/512)) that is 1.0. The old value 0x3C00 is 0.5; it is binary16's encoding of 1.0.
    • ternary_to_f32_is_inverse now checks all three trits.
  • rings/ring-096-rust/src/lib.rs
    • The five functions take and return f32 instead of f64. Internally the encoder still normalises in f64, which is lossless.
    • New test f32_boundary_is_lossless_for_every_normal_code: all 63,488 normal GF16 codes go through f32_to_gf16(gf16_to_f32(x)) and come back as the same 16 bits.
    • cargo test: 43 pass (42 before).
  • README: the signatures now say f32.
  • Seals: .trinity/seals/numeric_Formats.json and .trinity/seals/Formats.json were resealed with t27c seal specs/numeric/formats.t27 --save.
  • docs/now: new entry for this change.

Drift (python3 tools/check_ring_spec_drift.py)

Before (origin/master 7943bc4), rc 1:

DRIFTED ring-096-rust specs/numeric/formats.t27
  hand fns 7, spec fns 6, shared 6, differing 5
    differs: f32_to_gf16 / f32_to_ternary / gf16_to_f32 / quantize_value / ternary_to_f32

After, rc 0:

CONVERGED ring-096-rust specs/numeric/formats.t27
  hand fns 7, spec fns 6, shared 6, differing 0
CONVERGED 3

I did not touch tools/check_ring_spec_drift.py and did not raise any ledger.

Other spec-guards steps (run locally on this branch)

  • All five self-checks: rc 0.
  • Seal currency: rc 0, 1283 current, STALE 0.
  • Duplicate declarations: rc 0.
  • published_figures self-check: rc 0.
  • published_figures --check: rc 1, with 8 DRIFT figures. They are identical on master, so this red is pre-existing (Four advisory gates are red on master for inherited reasons, one cause per pull request #5497) and not caused by this PR. On CI the job stops at this step on master and on this branch alike.
  • diagnostic_capacity: rc 0.
  • ring_spec_differential.py: ring-090 rc 0 (936/936), ring-099 rc 0 (80/80), ring-096 rc 2. This red is new, and it appears because ring-096 converged: CONVERGED pairs now enter the differential. It cannot be fixed inside this issue's boundary:
    • gen-rust emits the spec's u5/u4 constants verbatim, so the harness does not compile (E0425).
    • The harness cannot synthesise Trit or Format values. Even with the constants patched, 4 functions are REFUSED.
    • The spec functions have no bodies, so the spec side is unimplemented!().
    • The harness compares f32 with ==, so code 0xFFFF (NaN on both sides) would always read as a disagreement.
  • t27c test-report specs/numeric/formats.t27: BLOCKED before and after. On master the cause is gf16.zig FileNotFound. Now it is the spec's bodyless functions (@compileError("not yet implemented")). The seal records tests.blocked. So "its tests pass" can only be met once formats.t27 has bodies.

Left open (outside this boundary)

  • The ring-096 differential red described above.
  • formats.t27 has no function bodies.
  • gf16.t27 contradicts itself:
    • its decode formula puts 1.0 at 0x3E00
    • its pow2_table[0] and gf16_from_components(0,0,0) tests say 0x3C00
    • its encode subtracts the wrong exponent bias
  • formats.t27 and the ring use NaN 0x7F01, while gf16.t27 uses GF16_NAN = 0xFE01.
  • The two sides give subnormals different meanings.
  • The ring's existing subnormal encode is off by a factor of 2 (2^-31 vs 2^-30). This predates the PR.

🤖 Generated with Claude Code

check_ring_spec_drift.py reported ring-096-rust DRIFTED against
specs/numeric/formats.t27 on five functions. The constitution decides
which side moves: Article SSOT-MATH gives numeric meaning "one normative
source of truth: specifications in the t27 language", so the spec is the
truth and the ring follows it.

The spec itself was wrong in one place: gf16_to_f32, ternary_to_f32 and
quantize_value returned `gf16` (a u16 encoding) while their names and
callers mean a float. They now return f32, which is the boundary the L6
codec specs/numeric/gf16.t27 already uses (gf16_encode_f32(f32),
gf16_decode_to_f32(GF16) f32). Its tests stop calling gf16.to_f64, which
gf16.t27 does not declare; gf16_to_f32_normal_one uses 0x3E00, which is
1.0 under FORMAT-SPEC-001.json's GF16 bias 31 (0x3C00 is 0.5).

rings/ring-096-rust moves its five functions from f64 to f32. A new test
re-encodes all 63,488 normal GF16 codes through the f32 boundary and gets
the same 16 bits back. 43 ring tests pass.

Both formats seals resealed with `t27c seal specs/numeric/formats.t27
--save`. Drift: ring-096 DRIFTED (differing 5, rc 1) -> CONVERGED
(differing 0, rc 0).

Part of #5906.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-04 06:43:47 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 47
PRs with All Checks Green 3
READY 2
FAILING 47
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 47 + 0 + 0 = 49, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=b45a356c2eb6 != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

This was referenced Oct 4, 2026
This was referenced Oct 5, 2026

This branch has not been deployed

No deployments
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.

spec-guards: ring-096-rust disagrees with specs/numeric/formats.t27 on 5 signatures (f32/gf16 vs f64)

1 participant