Skip to main content

Spectral lattice-fermion encoder for 2D and 4D chess (D4 / B4 symmetry, graph-Laplacian eigenbasis, 640-dim / 45 056-dim HDC)

Project description

chess_spectral (Python)

Python reference implementations of the 640-dim 2D and 45 056-dim 4D spectral chess encoders, plus the quantum-mechanical front-end (2D + 4D kinematics; 4D dynamics shipped in v1.5, 2D dynamics in v1.6.x), the v1.6 §16 search + tournament + sweep engine surface, the v5 unified wire format (three encoding modes — dense / per-channel replacement / XOR-stream — with empirical 7.23× compression on 4D fixtures vs dense gzipped), the v1.7 native bitboard fast-path

  • time-budget mid-iteration honoring (cumulative ~125× speedup on dense legal_moves() calls vs v1.6), and the v1.8 GameState4D push/pop + board accessors + check predicates consumer surface (chess4D-OC visualizer M11.40 unblocker).

Sibling of the C17 port in ../src/. Use the Python package for REPL / LLM / notebook analysis, Pyodide-bridge consumers, and the §16 ship-gate matrix runner; use the C binaries for batch encoding throughput.

The pieces ship under two top-level packages:

  • chess_spectral — 2D encoder + 4D encoder math + 4D phase operators + QM extension. Everything that's pure spectral / B_4 representation theory lives here.
  • chess_spectral_4d — 4D game-state surface (move history, side-to-move, draw status, FEN4 round-trip, the Pyodide chess_spectral_4d.bridge module). Splits cleanly from the encoder so the 4D-rules concerns don't bleed into the spectral math.

What's new in v1.8 (May 2026)

The chess4D-OC visualizer's M11.40 unblocker release. Tier-1 of the upstream wishlist ships in 1.8.0 — GameState4D graduates from a position+history snapshot to a persistent mutation type, mirroring python-chess.Board's push/pop ergonomics so the chess4D-OC worker can drop the python-chess4d-oana-chiru runtime dep. No API breaks vs. 1.7.x — every addition is opt-in surface.

  • GameState4D.push(move) / GameState4D.pop() — apply / undo a ply, mutating in place. push accepts a Move4D or a ((from_xyzw), (to_xyzw)[, promote_to]) tuple. pop raises IndexError on an empty history (parallel to chess.Board.pop()'s contract). Returns the recorded / popped Move4D so callers can recover capture / promotion metadata.

  • GameState4D.board view — read-only proxy over the live position dict. Exposes occupant(sq) and pieces_of(side) accessors plus __contains__ and __len__. sq accepts both the linear int and the (x,y,z,w) Coord4D tuple. The view does not copy — push / pop mutations are reflected immediately.

  • GameState4D.to_fen() / GameState4D.from_fen(fen4) — symmetric aliases for to_fen4 / from_fen4 (the 1.7.1 slash-tolerant FEN4 form is accepted on both names).

  • GameState4D.iter_pieces() — yields (sq_idx, piece_value) tuples in the format chess_spectral.encoder_4d.encode_4d consumes directly. dict(state.iter_pieces()) is a one-liner replacement for the chess4D-OC worker's previous _state_to_pos4 helper.

  • chess_spectral_4d.engine.search.search() accepts GameState4D — same SearchResult shape as before; the engine constructs a transient Board4D internally. Drops the Board4D.from_fen(state.to_fen4()) hop chess4D-OC was previously paying per search call.

  • GameState4D.is_check() / is_checkmate() / is_stalemate() — wraps Board4D.is_check() plus a short-circuit legal-moves probe for mate / stalemate. is_checkmate / is_stalemate bail on the first legal move via next(iter(...), None), so the dense-position cost is O(legal-move generation) worst case — about 2s at the dense 28-king start with the 1.7.0 native bitboard fast-path active.

  • 16 new immolation tests in tests/test_gamestate4d_consumer_surface.py lock down the contract shape and at least one concrete behaviour per wishlist item. Hard gate — chess4D-OC's M11.40 PR will fail loudly if any of these regress.

Tier-2 (ψ-driven density / current, partial-trace density matrices) and the canonical initial_position() factory are deferred to 1.8.1+; consumers should continue passing their own FEN4 to GameState4D.from_fen(fen4) until then.

What's new in v1.7 (May 2026)

The chess4D-OC visualizer wishlist release. Headline pieces:

  • SearchOptions.time_budget_ms honored mid-iteration (chess_spectral_4d.engine.search). Previously the deadline was checked only between iterative-deepening iterations — a 5-second budget on the dense 28-king starting position could overrun by ~100× before depth-1 alone completed. v1.7 threads the deadline into the alpha-beta inner loop and returns the deepest-completed- so-far best move on deadline exit. New SearchResult.timed_out: bool field distinguishes deadline-exit from natural completion.

  • Native bitboard fast-path (chess_spectral.spatial_4d, cs_bitboard4d shared library). Pure-C primitives for the 4096-bit Bitboard4D — popcount, bitwise AND/OR/XOR/NOT/sub, per-square set/clear/toggle/test, predicates, and the load-bearing cs_bb4_to_squares iteration helper (per-bit LSB extraction in C plus b &= b - 1 clear, all without crossing the ctypes boundary per square). Ships in the wheel under chess_spectral/_native/; loaded via ctypes at import. Pure-Python Bitboard4D continues to work as fallback (sdist install, Pyodide / micropip) — verified by a dedicated fallback-test CI job. Bitboard4D.to_squares() / .squares() route through the native helper when chess_spectral.HAS_NATIVE_BITBOARD is True; ~16× faster iteration on dense bitboards.

  • Board4D.legal_moves() algorithmic refactor. The legal-move filter at the dense 28-king start position previously called _is_attacked once per own king (K=28 calls, each iterating all N opponent attackers from scratch). v1.7 iterates attackers once and tests king_bb.intersects(attack_set) per attacker, short- circuiting on the first hit — same per-op cost (O(1) bitboard test) but one call replaces K. ~12.7× faster on the representative non-in-check 264-piece position.

  • Cumulative wishlist outcome. The chess4D-OC visualizer's reported legal_moves() ~250s pain point at the standard 28-king start is now ~2s on the same hardware (~125× faster) with no API changes. Time-budget-checked search now respects user budgets within ~0.5s grace regardless of position density.

  • Downstream consumer flag. HAS_NATIVE_BITBOARD is exposed at the top-level chess_spectral package — consumers can do from chess_spectral import HAS_NATIVE_BITBOARD to badge "native fast-path active" or fall back cleanly when the native lib isn't present.

For the full release history see CHANGELOG.md.

What's new in v1.6 (April 2026)

The §16 ship-gate release. Headline pieces:

  • Search core, tournament harness, and sweep ship-gate runner ship as CLI commands at both 2D and 4D. Per-side symmetric agent specs let white and black be configured independently in the same single-process tournament loop:

    spectral_py sweep \
        --evaluators material,spectral,qm \
        --depths 1,2,3,4 \
        --n-games-per-pair 10 \
        --time-budget-ms 5000 \
        -o sweep.json
    
  • Three §16.1 evaluator families (material, spectral, qm) ship at both 2D and 4D with a uniform evaluate(position, side_to_move) -> float contract — drop in any of them as the search heuristic.

  • Three independent in-house move-rule oracles — each encodes the same legality predicate ("is move m legal in position p?") through a different mathematical lens, validated head-to-head against the python-chess[4d] reference and against each other. Not because one is more correct — they all agree on the same legal set — but because each lens is a standalone artifact for studying how spatial motion can be encoded:

    1. Bitboard / attack-tables (chess_spectral.spatial_4d) — the engineering lens. Bitboard4D primitive, per-piece attack tables (knight, king, rook, bishop, queen via magic-bitboard- style ray casting), axis-typed pawn moves (Pw/Py per Oana-Chiru §3 Def 11), Board4D game state, and draw rules. Same idea as a classic chess engine, lifted to Z_8^4.
    2. Phase-space operators (chess_spectral.phase_operators, chess_spectral.phase_operators_4d) — the algebraic lens. Per-piece move generation as group actions on a phase-space representation; legality is "the candidate move is in the orbit of the piece operator, intersected with the occupation oracle." 2D ships under §11; 4D under §13.
    3. Discrete-Laplacian eigenbasis oracle (2D + 4D) — the spectral lens. The lattice's discrete Laplacian (Kron-sum of P_8 path-graph Laplacians; eigenvectors form a DCT-style basis) doubles as a structural lookup table for move legality — the same eigenbasis the spectral encoder uses to embed positions also tells you which moves are reachable. Concrete demonstration that "encode the geometry" and "encode the rules" share one foundation.
  • v5 unified .spectral[z] / .spectralz4 wire format (chess_spectral.frame_v5) — single 256-byte header serves both 2D and 4D via explicit n_dimensions field. Three encoding modes selected by encoding_mode: dense (= legacy v2/v4 frame body), per-channel replacement (variable-size, ~2.84× compression on 4D stable workloads), and XOR-stream (fixed-size, 7.23× compression on 4D vs dense gzipped). See docs/WIRE_FORMAT.md for the byte-level spec covering all four shipped versions (v2/v3/v4/v5) and the reader-dispatch convention.

  • CI gate: the 15-cell verify-wheels matrix is now opt-in via the wheel-check PR label (was running on every PR; saves ~150 runner-min/PR while keeping the publish-time matrix as the load-bearing wheel-correctness gate).

For the full release history see CHANGELOG.md.

Both packages share a single dist version derived from importlib.metadata; see Install below.

Install

From PyPI (recommended):

pip install chess-spectral

The base install pulls only numpy and scipy — sufficient for encoding, the 4D phase operators, the kinematic QM layer, and the full §17.1 bridge surface.

Optional extras:

# PGN ingest via chess_spectral.corpus (adds python-chess)
pip install "chess-spectral[corpus]"

# 4D phase-operator validation gates against the Oana & Chiru oracle
pip install "chess-spectral[test]"   # adds python-chess4d-oana-chiru

Package page: https://pypi.org/project/chess-spectral/

From source

Editable install from a local checkout:

pip install -e docs/chess-maths/chess-spectral/python/

From a git URL (pin a commit in production):

pip install "git+https://github.com/lemonforest/mlehaptics.git@COMMIT#subdirectory=docs/chess-maths/chess-spectral/python"

After install, two console scripts are on your $PATH:

chess-spectral --help            # 2D CLI
chess-spectral-4d --help         # 4D CLI

Both packages also expose __version__, derived dynamically from the installed dist:

>>> import chess_spectral, chess_spectral_4d
>>> chess_spectral.__version__ == chess_spectral_4d.__version__
True   # both derive from importlib.metadata.version("chess-spectral");
       # they cannot drift from each other or from the wheel.

In-place (no install)

The legacy workflow still works: every test and analysis script uses sys.path.insert to bootstrap off the python/ directory, so pytest docs/chess-maths/chess-spectral/python/tests/ runs without any install.

Quick start (2D, 640-dim)

>>> from chess_spectral import (
...     encode_640, channel_energies, read_encodings, fen_to_pos,
... )

>>> pos = fen_to_pos("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
>>> enc = encode_640(pos)
>>> enc.shape
(640,)

>>> channel_energies(enc)
{'A1': 0.0, 'A2': 19.845, 'B1': 45.2825, 'B2': 45.2825,
 'E': 322.57, 'F1': 88.77, 'F2': 1851.01, 'F3': 1507.65,
 'FA': 19.92, 'FD': 0.0}

# Read a whole game that was encoded by either C or Python
>>> hdr, arr = read_encodings("game.spectralz")  # transparent gzip
>>> arr.shape
(161, 640)

Quick start (4D, 45 056-dim)

The 4D encoder runs on the Z_8^4 hypercubic lattice with B_4 hyperoctahedral symmetry adaptation (per Oana & Chiru, AppliedMath 6(3):48, 2026). Output is a 45 056-dim float32 vector partitioned into 11 channels of 4096 modes each: A1, STD4_X/Y/Z/W, FIB_SYM_1/2/3, FA_PAWN_W, FA_PAWN_Y, FD_DIAG.

>>> from chess_spectral.fen_4d import parse
>>> from chess_spectral.encoder_4d import (
...     encode_4d, channel_energies_4d, CHANNELS_4D,
... )

>>> pos = parse("4d-fen v1: K@4,0,0,0; k@4,7,7,7")
>>> v = encode_4d(pos)
>>> v.shape, v.dtype
((45056,), dtype('float32'))

>>> energies = channel_energies_4d(v)   # per-channel L2 energies
>>> sorted(energies)
['A1', 'FA_PAWN_W', 'FA_PAWN_Y', 'FD_DIAG',
 'FIB_SYM_1', 'FIB_SYM_2', 'FIB_SYM_3',
 'STD4_W', 'STD4_X', 'STD4_Y', 'STD4_Z']

The 4D game-state surface (move history, draw detection, FEN4 round-trip, promotion-piece argument) lives in chess_spectral_4d:

>>> from chess_spectral_4d import GameState4D, apply_move, MoveHistory4D
>>> from chess_spectral_4d import bridge

# Load a placement from a FEN4 string (white-to-move by default)
>>> result = bridge.load_state("4d-fen v1: K@4,0,0,0; k@4,7,7,7")
>>> state = result['state']
>>> isinstance(state, GameState4D)
True

# apply_move(state, from_sq, to_sq, *, promote_to='Q') is the v1.4 API
>>> # state2 = apply_move(state, from_sq=4, to_sq=5, promote_to='Q')

# Draw status: priority threefold > 50-move > insufficient > stalemate
>>> bridge.get_draw_status(state, has_legal_moves=True)
{'ok': True, 'status': 'none'}

For raw move-rule logic (legal-move generation, check detection) on Z_8^4, see chess_spectral.phase_operators_4d below.

Quick start (QM extension, v1.5+)

The QM extension ships in two layers, mirroring the standard physics split:

  • Kinematicschess_spectral.qm_4d. What states and operators look like: state space, observables, measurement structure, the B_4 group action. Lifts encoder output to ψ ∈ ℂ^{45056}, exposes the 11-channel decomposition as a built-in projection-valued measure (PVM), builds five Hermitian piece-reach observables (rook / bishop / queen / king / knight) on the per-channel ℂ^{4096} factor, and ships the 384-element B_4 unitary representation as a cached LUT.
  • Dynamicschess_spectral.qm_4d_dynamics. How states change: the 11 per-channel u_move_* builders for move-as-unitary transitions (discrete) plus evolve_under_h0 for Zeno-style continuous time evolution between move boundaries.

Consumers that want a Pyodide-JSON-shaped surface use the chess_spectral.qm_4d_bridge dispatch layer described in the next section.

>>> from chess_spectral.fen_4d import parse
>>> from chess_spectral.qm_4d import (
...     state_to_psi,
...     prob_channel, measure_channel_distribution,
...     channel_projector,
...     H_rook_4, H_bishop_4, H_queen_4, H_king_4, H_knight_4,
...     measure_observable_distribution,
...     b4_unitary_rep_4096, b4_unitary_rep_full,
...     expectation, is_normalized, is_hermitian, is_unitary,
... )

>>> pos = parse("4d-fen v1: K@4,0,0,0; k@4,7,7,7; R@0,0,0,0")
>>> psi = state_to_psi(pos, side_to_move=True)
>>> psi.shape, psi.dtype
((45056,), dtype('complex128'))
>>> is_normalized(psi)
True

# Born-rule channel measurement: probability mass per channel
>>> prob_channel(psi, c=0)            # A1 channel
3.3e-08
>>> probs = measure_channel_distribution(psi)   # all 11 channels
>>> abs(probs.sum() - 1.0) < 1e-10
True

# ⟨ψ|H_rook|ψ⟩ on the rook channel block
>>> # expectation(H_rook_4, psi[0:4096])    # H_piece_4 is sparse 4096x4096

# Born-rule eigenbasis distribution: |⟨φ_k|ψ⟩|² grouped by eigenvalue
>>> # eigvals, probs = measure_observable_distribution(H_rook_4, psi[0:4096])

# B_4 group action (384 elements). 4096-dim per-channel block, or the
# I_11 ⊗ U_4096(g) Kronecker extension to the full 45 056-dim space.
>>> # U = b4_unitary_rep_full(g)            # cached; sparse 45056x45056

The Hermitian piece-reach observables H_rook_4, H_bishop_4, H_queen_4, H_king_4, H_knight_4 are built on demand and cached. They are real-symmetric on ℂ^{4096} with integer / near-integer spectra (Hermiticity verified at floating residual ~5e-15; Pre-flight 2 in qm_4d.py). Pawn observables break Hermiticity under the standard inner product (directed push) — the pseudo-Hermitian η-metric construction is deferred to v1.8+ per ADR-005.

b4_unitary_rep_4096(g) and b4_unitary_rep_full(g) realize the order-384 hyperoctahedral group as sparse unitaries on ℂ^{4096} and ℂ^{45056} respectively (the latter is I_{11} ⊗ U_{4096}(g) — same B_4 action applied independently to each of the 11 channels). Both are cached per group element. measure_observable_distribution(H, ψ) diagonalizes any Hermitian observable on ℂ^{4096} and returns the Born-rule probability distribution over distinct eigenvalues.

Move-as-unitary dynamics (Phase 4, Track B) live in chess_spectral.qm_4d_dynamics. The module ships per-channel builders for all 11 channels and both non-capture and capture moves:

  • u_move_a1 — A_1 channel via projector-sandwich (B1).
  • u_move_std4 — STD4_X/Y/Z/W via similarity-transform; same-orbit is strict-unitary, cross-orbit returns a measurement-only marker (B3a, ADR-003 amendment).
  • u_move_fa_pawn — FA_PAWN_W/Y via axis-parity-odd projector sandwich (B3b).
  • u_move_fib_meas — FIB_SYM_1/2/3 via measurement-only re-encode (B3c, per the Phase 3.5 amendment to ADR-003 §3.3).
  • u_move_fd_diag — FD_DIAG via rank-1 update + renormalization (B3d/e).
  • evolve_under_h0 + H_FREE_4D — Zeno-style continuous evolution between move boundaries, where H_0 = -Δ is the lattice Laplacian (B2, ADR-002).

§17.1 Pyodide bridge surface (v1.5)

chess_spectral.qm_4d_bridge is the consumer-facing bridge — the 7 §17.1 QM-extension methods plus 6 §17.5 dev/debug methods — designed for Pyodide consumers (e.g., the chess4D-OC visualizer) that need Pyodide-JSON-serializable returns and Float32 ψ-amplitudes ready for Float32Array shader uploads.

>>> from chess_spectral.qm_4d_bridge import (
...     # §17.1 (QM-extension surface)
...     get_qm_state, get_qm_density, apply_move_qm, apply_move_qm_full,
...     measure_at, get_density_matrix_of, get_probability_current,
...     get_qm_expectation,
...     # §17.5 (dev / debug surface)
...     get_version, get_encoder_shape, get_fen4_state, load_fen4,
...     load_jsonl_fixture, has_legal_moves,
... )

# Round-trip: load a FEN4, get ψ as Float32 interleaved, apply a move,
# get the updated ψ.
>>> r = load_fen4("4d-fen v1: K@0,0,0,0; k@7,7,7,7; R@1,0,0,0")
>>> state = r['state']

>>> r = get_qm_state(state, side_to_move=True)
>>> r['basisDim'], r['psi'].dtype, r['psi'].shape
(45056, dtype('float32'), (90112,))   # 2 × 45 056 — real+imag interleaved
>>> abs(r['normSq'] - 1.0) < 1e-6
True

# Per-cell density: |ψ|² summed across the 11 channels per cell
>>> r = get_qm_density(state)
>>> r['density'].shape, abs(r['density'].sum() - 1.0) < 1e-6
((4096,), True)

# Apply a move and get the assembled ψ_post (Float32 interleaved).
# move format: (from_sq, to_sq) as ints OR ((x,y,z,w), (x,y,z,w))
>>> # r = apply_move_qm_full(state, move=(1, 2))
>>> # r['ok'], r['psi'].shape
>>> # (True, (90112,))

# §17.5 debug surface
>>> get_version()['version']         # e.g., '1.5.0'
>>> get_encoder_shape()['totalDim']  # 45056
>>> get_encoder_shape()['channels']  # [{'name': 'A1', 'offset': 0, 'dim': 4096}, ...]

Wire format (ComplexArray, Float32Array-friendly): every ψ return is a 1-D Float32 array of length 2 * 45056 = 90112, where psi[2k] is Re(ψ_k) and psi[2k+1] is Im(ψ_k). This matches the §17.1 contract documented in the research notebook §17.1.

apply_move_qm vs apply_move_qm_full. The low-level apply_move_qm returns a per-channel dispatch dict (mixed csr_matrix

  • marker dict values) for consumers that want to reason about per- channel structure. The high-level apply_move_qm_full does the block-by-block assembly (csr_matrixU_chan @ ψ_pre[block]; marker dict → psi_post_block splice) and returns the assembled ψ_post as Float32 interleaved. Most consumers want the _full variant.

The B5 milestone (April 2026) closed the last unshipped channels, so the bridge no longer raises for any move type — non-captures and captures both succeed via the channels' B5 capture-path branches. See qm_4d_bridge.py for per-method docstrings and qm_4d_dynamics.py for the per-channel construction details.

Deferred to v1.8+:

  • get_density_matrix_of (reduced density matrix; needs partial- trace machinery on channel labels).
  • get_qm_density(piece_id=...) (per-piece marginal; same blocker).

Both raise NotImplementedError with a pointer to the v1.8+ milestone. (v1.7.0 shipped the D1 / D2 native fast-path workstream — see the "What's new in v1.7" section below — and rolled the partial-trace work to a follow-up.)

CLI

The 2D CLI (chess-spectral, entry point chess_spectral.cli:main) mirrors the C spectral CLI subcommand-for-subcommand. Output is byte-identical to the C binary on the same input — the spectral csv command produces the same bytes on either side.

chess-spectral csv         game.spectralz -o game.csv
chess-spectral encode      -i game.ndjson -o game.spectralz -z
chess-spectral encode-fen  --fen "..."   -o single.spectral
chess-spectral compare     a.spectralz b.spectralz
chess-spectral query       game.spectralz --ply 30
chess-spectral heatmap     game.spectralz --ply 30 --channel A1
chess-spectral analyze     game.spectralz
chess-spectral export      game.spectralz -o game.json
chess-spectral version

The 4D CLI (chess-spectral-4d):

chess-spectral-4d tables-verify  --phase all
chess-spectral-4d encode-fen4    --fen4 "4d-fen v1: K@0,0,0,0; ..."
chess-spectral-4d encode-moves4  --moves game.ndjson4 -o game.spectralz4 -z
chess-spectral-4d corpus-gen     --games game1.ndjson4 game2.ndjson4 ...
chess-spectral-4d version

Both CLIs follow the --help discipline: every subcommand and every argument has non-empty help text. Run <cmd> --help (or <cmd> <subcommand> --help) before invoking; the immolation suite gates this in CI.

Layout

chess_spectral/                # 2D + 4D encoder math + QM extension
  __init__.py                  # __version__ via importlib.metadata
  encoder.py                   # encode_640(pos) → np.ndarray(640,)
  frame.py                     # v2 .spectral[z] binary I/O + transparent gzip
  csv_export.py                # dist_prev / cos_prev / energies CSV
  cli.py                       # `chess-spectral` (2D CLI)
  phase_operators/             # 2D §11 phase-space move generator (1.2.0+)

  encoder_4d.py                # encode_4d(pos4) → float32(45056,)
  frame_4d.py                  # v3/v4 .spectralz4 binary I/O (legacy reader)
  frame_v5.py                  # v5 unified wire format (2D + 4D, 3 encoding modes; default for new writes from v1.6)
  tables_4d.py                 # B_4 group, lattice tables, eigenmodes
  fen_4d.py                    # FEN4 v1 placement-literal parser + serialize
  phase_operators_4d/          # 4D §13 phase-operator move engine (1.3.0+)

  qm_4d.py                     # Track A kinematic QM front-end (1.5.0+)
  qm_4d_dynamics.py            # Track B per-channel U_move builders (1.5.0+)
  qm_4d_bridge.py              # §17.1 + §17.5 Pyodide bridge surface (1.5.0+)

chess_spectral_4d/             # 4D game-state surface (1.4.0+)
  __init__.py                  # GameState4D, Move4D, MoveHistory4D, apply_move, bridge
  move_history.py              # ply log, side-to-move, 50-move clock, repetition hash
  apply_move.py                # apply_move(state, from_sq, to_sq, *, promote_to='Q')
  bridge.py                    # load_state, get_draw_status, get_move_history,
                               #   is_insufficient_material_2d
  cli.py                       # `chess-spectral-4d` (4D CLI)

pyproject.toml                 # PEP 621 packaging metadata
tests/                         # pytest suite (see test count below)

Test count (post-v1.5): 45 895 tests collected. Breakdown: ~44 876 parametric 4D phase-operator tests (the bulk), 81-test end-to-end immolation suite (test_smoke_e2e.py, expanded from 41 for v1.5 surface coverage), 272 v1.5 QM tests across the kinematic front-end (test_qm_4d.py, test_qm_4d_z2_grading.py), the Track B B1..B5 dynamics gates (test_qm_4d_dynamics_b{1,2,3a,3b,3c,3d,5}.py), and the §17.1/§17.5 bridge surface (test_qm_4d_bridge_v15.py), plus 102 fast tests, 260 pawn-axis / phase-4d-check / phase-4d- unobstructed tests, 92 2D phase_operators tests, and 210 v1.4 game-state tests. Run via pytest docs/chess-maths/chess-spectral/python/tests/.

Phase operators (2D, §11)

chess_spectral.phase_operators ships a phase-space move generator and check detector (added in 1.2.0). The primitives compute all moves and check relationships as modular arithmetic on a single integer per square — phi(r, c) = r·67 + c·7 mod 640 — rather than geometric coordinates. They are a drop-in equivalent to python-chess's pseudo_legal_moves + is_check, validated at 100% on the reference corpus, and compose naturally with the spectral encoder's coprime phase structure.

import chess
from chess_spectral.phase_operators import (
    occupation_aware_moves_c,   # pseudo-legal dests from a square
    available_castles,          # legal castles for side-to-move
    phasecast_is_check,         # is the mover's king attacked?
    move_leaves_king_in_check,  # would this move expose our king?
)

board = chess.Board()
dests = occupation_aware_moves_c(board, "N", 0, 1, +1)
# -> frozenset({(2, 0), (2, 2)})   (a3 and c3)

phasecast_is_check(board)  # False on the starting position

Validation coverage and rationale: see PHASE_OPERATOR_SUPPLEMENT.md.

Phase operators (4D, §13)

chess_spectral.phase_operators_4d (1.3.0+) is the 4D analogue — mixed-radix tower with modulus 145451 and ladder coefficient 14 (vs the 2D framework's 8). Validated against python-chess4d-oana-chiru at 44 803 (state, origin, piece) cases for occupation-aware moves and 232 cases for check detection.

from chess_spectral.phase_operators_4d import (
    phi4,
    P_rook4, P_bishop4, P_queen4, P_king4, P_knight4,
    P_pawn4_white, P_pawn4_black,
    occupation_aware_moves_a_4d,    # phase-op candidates ∩ chess4d oracle
    phasecast_is_check_4d,
    move_leaves_king_in_check_4d,
)

Full design + experimental record: PHASE_OPERATOR_SUPPLEMENT_4D.md.

When to use what

The 2D and 4D encoders are independent build targets that share table generation discipline. Pick by what you're encoding; the QM extension sits on top of the 4D encoder.

2D (chess_spectral) 4D (chess_spectral + chess_spectral_4d)
Encoding dim 640 45 056
Lattice Z_8 × Z_8 Z_8^4
Symmetry group D_4 (order 8) B_4 hyperoctahedral (order 384)
Game rules python-chess (fen_to_pos) Oana & Chiru (python-chess4d-oana-chiru)
Channels 10 (A1, A2, B1, B2, E, F1, F2, F3, FA, FD) 11 (A1, STD4_X/Y/Z/W, FIB_SYM_1/2/3, FA_PAWN_W/Y, FD_DIAG)
Phase operators phase_operators (1.2.0+) phase_operators_4d (1.3.0+)
QM extension not yet shipped qm_4d + qm_4d_dynamics + qm_4d_bridge (1.5.0+)

Python vs C — same encoders on either side, byte-identical output:

C (../src/) Python (this package)
Throughput µs/encode ms/encode
REPL / notebooks
LLM-pasteable binary code
scipy.linalg exploration
Embeds in mobile / web (Pyodide) ✓ (Pyodide)
Exact numerical reference tables baked at build rebuilt from primitives

Develop new channels in Python first (faster iteration, scipy.linalg at hand, no rebuild loop). Once the math is frozen, port to C and verify parity via the test suite — the critical test is test_csv_matches_c_byte_for_byte (2D) / test_e2e_spectralz4_parity.py (4D), which assert the C-produced encoded bytes equal the Python-produced bytes.

See also

  • Cross-disciplinary applications — research notebook §15 (chess_spectral_research_notebook.md) for the framing of chess-spectral as a H(4, 8) Hamming-scheme toolkit with B_4-equivariant frozen featurizer and Born-rule loss hooks.
  • §17 bridge contracts — same notebook, §17.1 / §17.5 for the consumer-facing method specs that this package implements.
  • 4D notebookchess_spectral_4d_notebook.md for the 4D-specific research record (encoder injectivity, B_4 spectral identity, qm_4d pre-flight findings).
  • Track B ADRsdocs/adr/qm_4d/ for the design record of the v1.5 QM extension:
    • ADR-001 phase convention for unitary moves
    • ADR-002 time-evolution semantics (continuous H_0 between move boundaries; evolve_under_h0)
    • ADR-003 per-channel move transformation (+ Phase 3.5 orbit-restriction amendment for cross-orbit STD4 / FIB_SYM measurement-only re-encode)
    • ADR-004 Z_2 superselection structure (side-to-move sign multiplier, resolves the 8-collision encoder hash issue)
    • ADR-005 pawn pseudo-Hermitian η-metric (deferred to v1.8+)
    • PHASE_3_5_PROBE_RESULTS.md — empirical probe record that drove the ADR-003 amendment.
  • Pawn-axis split (v1.1.1) — Oana & Chiru Definition 11; the encoder splits the pawn antisymmetric channel into W-axis and Y-axis sub-channels (FA_PAWN_W, FA_PAWN_Y) and grew from 40 960-dim to 45 056-dim. See encoder_4d.py header for the rationale.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chess_spectral-1.8.0.tar.gz (4.2 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

chess_spectral-1.8.0-py3-none-any.whl (1.9 MB view details)

Uploaded Python 3

chess_spectral-1.8.0-cp314-cp314-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.14Windows x86-64

chess_spectral-1.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.5 MB view details)

Uploaded CPython 3.14manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

chess_spectral-1.8.0-cp314-cp314-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.14macOS 11.0+ ARM64

chess_spectral-1.8.0-cp313-cp313-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.13Windows x86-64

chess_spectral-1.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.5 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

chess_spectral-1.8.0-cp313-cp313-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.13macOS 11.0+ ARM64

chess_spectral-1.8.0-cp312-cp312-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.12Windows x86-64

chess_spectral-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

chess_spectral-1.8.0-cp312-cp312-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

chess_spectral-1.8.0-cp311-cp311-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.11Windows x86-64

chess_spectral-1.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

chess_spectral-1.8.0-cp311-cp311-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

chess_spectral-1.8.0-cp310-cp310-win_amd64.whl (3.5 MB view details)

Uploaded CPython 3.10Windows x86-64

chess_spectral-1.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (3.5 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64manylinux: glibc 2.28+ x86-64

chess_spectral-1.8.0-cp310-cp310-macosx_11_0_arm64.whl (3.5 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

File details

Details for the file chess_spectral-1.8.0.tar.gz.

File metadata

  • Download URL: chess_spectral-1.8.0.tar.gz
  • Upload date:
  • Size: 4.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chess_spectral-1.8.0.tar.gz
Algorithm Hash digest
SHA256 9066e7d869f29c3108debbb2d4f6b8ee8d734460357f63073b5c6bead8a4da56
MD5 09b97e3627d37c6181d7831d89427615
BLAKE2b-256 ae962cfda03a052a883540a36941a09b76393ff7b180165afe94246ff43faba5

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0.tar.gz:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-py3-none-any.whl.

File metadata

  • Download URL: chess_spectral-1.8.0-py3-none-any.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chess_spectral-1.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b41e6cb7b5cd944871ba89e56c851316f9ff45d851a3782ff88c79ee79a75966
MD5 c4ac7e25500e48b9a56fdb1de6621272
BLAKE2b-256 61c9e8ddeddd3a5dec2f9874fd79982413c4f400cb9c59e42e7f1685a5621a4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-py3-none-any.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp314-cp314-win_amd64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 2727a92a629d65f3b950ed235f791fdcceba71754ae5b68dbd8ddfb30fbcdb2b
MD5 f91b4ffab7eb78cc2005bd8c7fb0dc97
BLAKE2b-256 d8332bb606b5fc45379dc56e01021a54efa52bfcac17f9a7185fd5298682ac09

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp314-cp314-win_amd64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 1a97011954e1cb051834e326fcbcfa61f0d71f7e71b1374cbceae42bd109bea0
MD5 155b86198d9ec63027cf162f8c291050
BLAKE2b-256 b6092e5db311a905f4832fb6160957ca7e4b4ba32495992806f8ab850494b9df

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp314-cp314-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp314-cp314-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 127bebe0e222db617f43570bb856edf57931c1f24771d4c3b55175769ab82dae
MD5 93ec1d500ad133e6015e9bba06c2c30d
BLAKE2b-256 f39b0a78a5a4d06914a9403eaf20c3a02b0b189216fdcab26b7d8ba5474b791f

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp314-cp314-macosx_11_0_arm64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp313-cp313-win_amd64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 ba6b8dc318ba006777e64841e05efd9f899a9336ae3b6234e27de5749aa629f7
MD5 e6a7a818f438441f6e7d4050da7132f5
BLAKE2b-256 e8b3ad465e5213fccdb5923e34bd643e0e8010bf6616bd5ad686e8bc4dd0d306

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp313-cp313-win_amd64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 24e629d4c29300193829910de2411509a533ebdf707f7ca5f29cf6e0bdb2d3cf
MD5 0881cc136761b3ed10eae6ed15887dad
BLAKE2b-256 c9af9f06555ab522e57405c2dc6dfe8bb7c0fed5c4212978a7d3578dc2553d14

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 436f383b74680166e175f95ad26fdf67d24b8c85d30849d7ecc3994317eba892
MD5 74a4ec42c83df48620bb43520cf4b32e
BLAKE2b-256 befdaf72828d492673a728ac136664e42a0700d5cad326d1d7b3cfb4d51fa347

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp313-cp313-macosx_11_0_arm64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 31589904dd15898da8ab7cd3ff6716cb2d72f3b5f272e0c91204dca3ba7eb14a
MD5 e59a6d9c06eabac35e09aeac09e63365
BLAKE2b-256 ec50bea620d6362ae48480f28885281d82231d1cd84110412db70bda269c7615

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp312-cp312-win_amd64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 da6bae21821e5c08b64340e2eca7428e60703e5acc6345a68ad1071d288bbdc5
MD5 7f8fdd0aa0f1a86f73b3d2c2131091fb
BLAKE2b-256 5a8d4c95727603dfb83ff43f9689d52f80545c1a7e1b1a80a192f49d0909bdea

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b298b4f216836a418b9a6dbc475f22d6cacff2d63456cccd0f37967eff94da00
MD5 cbadc87a37855c55ae3f27171d18dc14
BLAKE2b-256 81c898c9547fbc41c384849ce0aeabf585719adf45426f0c3e686a92fbde2ef2

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 2fd7bd4bf6525da894b9a0a4843c62f7649d15b2ab4b55f72d9df28cdf783b95
MD5 d5e3cc0e2979a2516aec10e465366885
BLAKE2b-256 0a288a67937e5251ea96c6fa373b4d9e95e0ededd9de751daab6d7f2afb5e26b

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp311-cp311-win_amd64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 b4846933510965e649e0062c5a3abce59fe45a9b17df7e999e3e308a609e8a8c
MD5 5e6aa3adb2c7a934cc741d008797b8ca
BLAKE2b-256 a8c7e77f47ac6c078bad74a5fcae9d35c0ab73316b7f77166ae5e937f5328b2c

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9d2bc881da0135dea078380c315b33beac65d63d1e77591b166e9dc1cb2d26be
MD5 2de0e97cf59d4f66555c04ef6eb55ca2
BLAKE2b-256 e109ac3f2da36363b5f18384f09623fdcbf18d3eaa1bac35bf6af97ef4fb5992

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 22a733af8444a6fd504e567a9b08beb049f343b1baf796b72a7ca33259f79971
MD5 dcd631dccbf210578f1825e07f4ae7c1
BLAKE2b-256 b35d5a32846160c18bf0bd140f4e0145a6882cb0b2f29a8aded0d2b7edb0342f

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp310-cp310-win_amd64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 33711d002884733cb584dc7b11152729c526793ad23c2de572db14e4a4532620
MD5 c52d58363442f7deea19dd62adc1d969
BLAKE2b-256 1353e68e50c2eadc2c9e53262115ce24e2ef72f26e77f881792936338064807b

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_spectral-1.8.0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_spectral-1.8.0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0795cd7a59493890c4a9cb6e972fd3cd92f55a745cdfdbdca4b96b90a290a63e
MD5 247beb20a42aeabc6c45e515ffcd88aa
BLAKE2b-256 f273e1f0edd2f748e8013f65fa25b8eb1446d6d91ce2e3f5553521fd1dc5da4d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_spectral-1.8.0-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: chess-spectral-publish.yml on lemonforest/mlehaptics

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page