Skip to content

feat(orbit64): add the Orbit64 V2 color-model facelet bridge - #42

Merged
wstein merged 10 commits into
mainfrom
orbit64-v2-facelets
Nov 1, 2026
Merged

wstein merged 10 commits into
mainfrom
orbit64-v2-facelets

Conversation

@wstein

@wstein wstein commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Ports the COLOR-model facelet bridge of Orbit64 V2 from flix-orbit64 (src/Orbit64/V2/Facelets.flix, FORMAT-V2.md, FORMAT-V2-SLOTS.md) to ReScript, as a sibling of the V2 codec.

What it adds

  • Orbit64V2Facelets.res/.resi and the typed adapter orbit64V2Facelets.ts:
    • slotTables(n), derived like the reference for n = 2..15 (5x5x5 corners and midges, 4x4x4 wings, the n >= 8 extension, centers from geometry), and the 24 frameFaces
    • toFacelets(n, model, pose, cube) and fromFacelets(n, model, pose, facelets) for canonical and framed; a canonical read accepts any whole-cube orientation
    • encodeFacelets(id, facelets) and decodeFacelets(token)
    • an unknown pose, a cube size that is not an integer in 2..15 and a registry entry that is not an integer are errors with fixed reasons that echo no caller text
    • every failure is a result error with the reference's reason; hostile input (non-strings, non-integer sizes) is an error, never an exception
    • the picture model returns the picture model has no letters (a sibling task defines it later)
  • Orbit64V2.resi exposes snapshot and faultOf (no behavior change) so the bridge validates exactly like the codec.
  • Existing NotationOutput is not reused for reading: it trims, upper-cases, accepts any white space and warns instead of giving a reason, none of which the format allows.

Tests

  • scripts/orbit64V2FaceletFixture.jl (Julia, standard library only) writes test/cube/notation/orbit64V2Facelets.json from FORMAT-V2-SLOTS.md and test/TestV2FaceletData.flix (448 rows, count derived from the input). Regenerating gives identical bytes, and biome format leaves it unchanged.
  • orbit64V2Facelets.test.ts: slot tables equal FORMAT-V2-SLOTS.md for n = 2..15; the 24 frames equal their wire-order derivation; every row encodes and decodes in both directions, including canonical reads of other orientations; hostile values (throwing getters, Proxies, thrown primitives, non-integer sizes and ids, unknown poses) with exact reasons; the generator fails on a dropped or extra row (structure and pinned counts); invalid input with exact reasons (length, bad letter including tab and newline, color counts, wrong handedness of fixed centers, twisted corner, flipped midge, doubled piece, mirrored cube).

Checks run as CI does

npm run typecheck, npm run lint, npm run format:check, typos, npm run build pass. npm test: 82 files, 1217 tests passed (6 expected fail, 2 skipped), run with --testTimeout=60000 because a few image tests exceed the 5 s default on a 2-core machine. npm run test:e2e could not run locally (Playwright Chromium mismatch); CI runs it.

https://claude.ai/code/session_01VB53JGakrcQ5QAU95yXdMz


Generated by Claude Code

wstein and others added 10 commits November 1, 2026 13:11
Orbit64V2Facelets turns a V2 color-model cube into its U R F D L B facelet
string and back, for 2x2x2-15x15x15, canonical and framed. The slot tables
are derived like the reference (5x5x5 corners and midges, 4x4x4 wings,
centers from geometry); a whole-cube rotation goes through the geometry of
FORMAT.md. Every failure is an Error with its reason. The picture model has
no letters and is an Error. Token helpers go from a facelet string to a
token and back.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A Julia script copies the slot tables of FORMAT-V2-SLOTS.md and the 448
facelet rows of flix-orbit64's TestV2FaceletData.flix into a JSON fixture.
The row count comes from the input and the output is written the way the
formatter leaves it, so regenerating it changes nothing.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Checks the slot tables against FORMAT-V2-SLOTS.md for n = 2..15, the 24
frames against their wire-order derivation, every fixture row in both
directions, and invalid input with exact reasons: length, bad letters
including tab and newline, color counts, wrong handedness of fixed centers,
a twisted corner, a flipped midge, a doubled piece and a mirrored cube.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…t bridge

An unknown pose such as 'Bogus' was read as a pose of its own. The type
check now rejects anything but Canonical and Framed with "unknown pose".
The cube size is checked as a number before any arithmetic or conversion,
so slotTables no longer throws for objects, symbols or bigints, and the
error says the size is not an integer in 2..15 without echoing it.

The tests assert the exact reasons, check that the canonical rows read as
Ok, add the mirrored 3x3x3 case, and note two deliberate differences from
the reference.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… input

The generator now checks the parsed row count against the tuple lines of
TestV2FaceletData.flix, rejects unparsed slot lines, checks the center
orbits per size, and records the full commit hash and whether the source
tree had uncommitted changes. The fixture changes only in its source line.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An unknown id was written into the message with String(), which echoed
caller text and ran a caller's toString. Only a genuine integer is quoted
now; anything else says the registry entry is not an integer. The V2
codec's own message gets the same rule.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Every move sequence of a size must have one row for each of its two color
entries, and every size 2..15 must appear. A dropped row now stops the
generator instead of shrinking the fixture. The fixture is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…2 bridge

Asserts the exact reasons for throwing getters, Proxies, thrown primitives
and a throwing message, for non-string facelets and tokens, and for unknown
registry entries that are not integers, including that no caller code runs.
The fixture test checks that every move sequence has both color entries,
which fails when a row is dropped.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… fixture

Dropping both rows of one move sequence kept the structure checks intact.
The generator and the test now pin the 448 rows and the number of move
sequences per size, so such a drop fails both.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@wstein
wstein marked this pull request as ready for review November 1, 2026 15:17
@wstein
wstein merged commit e465962 into main Nov 1, 2026
2 checks passed
@wstein
wstein deleted the orbit64-v2-facelets branch November 1, 2026 15:20
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.

1 participant