ogdoad 1.0.0

Clifford algebras (with nilpotents) over the field-like subclasses of combinatorial games: nimbers, surreals, surcomplex.
Documentation
# AGENTS.md — `src/forms/`

The PILLAR of quadratic forms and their invariants. The organizing principle is
the **characteristic trichotomy**: the classification of a quadratic form
(equivalently, of the Clifford algebra it builds) is *one* theory split three ways
by `char F`. This axis cuts ACROSS the place table that organizes `scalar/`.

> Read `docs/OPEN.md` before touching `char2/`, `quadric_fit.rs`, `char0.rs`,
> `witt/`, or anything feeding the open play-semantics question.

`mod.rs` re-exports the legs + `classify` + diagonalize/equivalence + the `witt/`
invariant-group shelf + the `springer/` valuation-graded decomposition +
`local_global/` + `integral/` + `field_invariants` + the
symplectic/hermitian "form + involution" siblings, all flat (`poly_factor` is
`pub(crate)` machinery, not re-exported). The cross-cutting
machinery is grouped into shelves mirroring how `scalar/` groups by place: the
trichotomy legs (`char0.rs`/`oddchar/`/`char2/`), the invariant **groups**
(`witt/`), the valuation-graded **decomposition** (`springer/`), the **local↔global**
layer (`local_global/`), and the **integral** arithmetic view (`integral/`). Each
multi-file cluster is a subdir with a hub `mod.rs` re-exporting flat, so public paths
stay shallow (`forms::bw_class_real`, `forms::springer_decompose_qp`, …).

`integral/` has its own [`AGENTS.md`](integral/AGENTS.md) (the lattice/genus/
mass/code/theta/Weil chain).

Fixed-width payloads here are `u128`/`i128`: Arf bits, Artin-Schreier classes,
Dickson parities, Hilbert/Hasse signs, discriminant residues, lattice entries,
automorphism counts, node budgets. `usize` is for dimensions and matrix indices.

## The façade

- **`classify.rs`** — the classifier FAÇADE: `ClassifyForm` + `ClassifyWitt` +
  `ClassifyIsometry` + `DecomposeWitt` + `ClassifyBrauerWall`, keyed on the scalar so
  `metric.classify()` / `.witt_class()` / `.isometric_to()` / `.witt_decompose()` /
  `.bw_class()` pick the right leg **at compile time**. `ClassifyBrauerWall` has an
  associated return type because global fields carry richer Wall-coordinate records
  than the finite/real enum. The façade methods return
  `Result<_, ClassifyError>` (`#[non_exhaustive]`: `GeneralBilinearMetric` /
  `SingularForm` / `UnsupportedFieldOrWindow` / `DiagonalizerFailure`) so callers
  see *why* a metric is out of domain; the underlying leg functions keep their
  honest single-valued `Option`s.

  **Naming glossary** (the record-suffix discipline): `…Class` is reserved for an
  element of an actual group/classifying set carrying a law (`WittClass`,
  `BrauerWallClass`, `Brauer2Class`, `BrauerClass`, `FqmWittClass`); `…Decomp` is
  a decomposition; `…Invariants` is a classifier's report record
  (`ArfInvariants`, `BrownInvariants`, `CliffordInvariants`, `OddCharInvariants`,
  `FiniteFieldInvariants`, `NikulinExistenceInvariants`, `SymplecticInvariants`);
  `…Record` is a static catalogue record carrying no group law (`NiemeierRecord`,
  `KneserMassRecord`) — distinct from `…Class`, which is a group element with a
  law; `…Signature` stays for the literal mathematical signature; `…Isotropy` is a
  blessed pattern for a per-place isotropy breakdown (`AdelicIsotropy`,
  `FFAdelicIsotropy`) — the local-global sibling of `…Invariants`, kept as its own
  suffix because these types carry a `local` place-by-place map/vec plus a derived
  `is_global()` verdict rather than a single invariant value. The `…Report`
  suffix is retired: every report record now ends `…Invariants` (e.g.
  `OddMilgramInvariants`, `WeylVersorInvariants`, `KneserMassInvariants`,
  `CliffordBarnesWall16Invariants`). Façade traits are verb-first (`ClassifyForm`,
  `ClassifyWitt`, `ClassifyIsometry`, `ClassifyBrauerWall`, `DecomposeWitt`).
  **Rendering policy (a9, 2026-07-02): every classifier report renders.** Every
  glossary record type (`…Invariants`/`…Decomp`/`…Class`/`…Record`/`…Signature`/
  `…Isotropy`/certificates, crate-wide — games and clifford included) carries
  `impl Display` + the inherent `display()` alias, render-pinned by at least one
  exact-string test, with py `__repr__`s delegating to the core Display. Honesty
  markers ride in the rendering (`Char2WittDecomp`'s complement-dependent flag, an
  incomplete `RelationSearchCertificate` says INCOMPLETE up front, `QuadricFit`
  renders `bias=n/a (degenerate)` when the count formula doesn't apply).
  New types follow this glossary. Leg dispatch:
  - `Surreal``CliffordInvariants`
  - `Fp<P>` (odd primes only) → `OddCharInvariants`. `Fp<2>` is OUTSIDE the façade:
    `classify_finite_odd` returns `None` for `P=2` (the char-2 Arf path requires
    the `(q,b)` metric, not the char-0 diagonalizer). Use `Fpn<2,N>` for char-2
    extension fields.
  - `Fpn<P,N>``FiniteFieldInvariants::{Odd, Char2}` (dispatched on `P==2` at runtime)
  - `Nimber``ArfInvariants`
  - finite-window `Ordinal``ArfInvariants`

  `DecomposeWitt` returns the leg-specific decomp record
  (`RealWittDecomp` / `OddWittDecomp` / `Char2WittDecomp`, with `Fpn` wrapping the last
  two in `FiniteFieldWittDecomp { Odd, Char2 }`). It is impl'd for `Surreal`, `Fp<P>`,
  and `Fpn<P,N>` only — so `Char2WittDecomp` arises via the `Fpn<2,N>` path
  (`Nimber`/`Ordinal` do not impl it). Caveat: when `Char2WittDecomp.radical_anisotropic`
  is true, its `witt_index`/`core_anisotropic_dim`/`arf` are invariants of the chosen
  symplectic complement, **not** isometry invariants of the whole form. `ClassifyBrauerWall`
  covers Surreal, Surcomplex, Rational, odd finite fields, odd-characteristic
  `RationalFunction<F_q>` function fields, nonsingular Nimber metrics, supported
  `Fpn<2,N>` metrics, and the documented finite ordinal windows. Rational &
  Surcomplex impl `ClassifyForm` but not `ClassifyWitt` (their Witt data isn't a
  single `WittClassG` — honest, not a gap).

  **Cross-leg asymmetry in `ClassifyBrauerWall` for singular metrics.** The
  char-2 legs (`bw_class_nimber`, `ClassifyBrauerWall for Fpn<2,N>`) return `None`
  for singular (non-nonsingular-polar) metrics.  The char-0/global legs
  (`bw_class_real`, `bw_class_complex`, `bw_class_rational`,
  `bw_class_function_field`) and the odd-char finite leg (`bw_class_finite_odd`)
  silently project the radical away and return the Brauer-Wall class of the
  nondegenerate core `Cl(Q/rad)`. The rustdocs on those functions state this
  projection explicitly.
- **`diagonalize.rs`** — congruence diagonalization (char ≠ 2): `gram`,
  `diagonalize`, `as_diagonal`. Returns `None` in char 2 (nonsingular char-2 forms
  have an alternating polar form and are NOT diagonalizable — use the char-2
  symplectic Arf reduction). This is what lets char0/oddchar classify ARBITRARY
  (non-diagonal) metrics.
- **`equivalence.rs`** — isometry per backend (via the complete invariant:
  `isometric_finite_odd`, `isometric_finite_char2`/`isometric_fpn_char2`, real/
  rational/surcomplex/nimber) + Witt decomposition (`witt_decompose_real`  `RealWittDecomp`, `witt_decompose_finite_odd``OddWittDecomp`: k·H ⊥ anisotropic
  kernel).

## The three legs

- **`char0.rs`** — the char-0 Clifford classifier: Cl(p,q) → matrix algebra over
  ℝ/ℂ/ℍ via the 8-fold table (real-closed surreal/rational) and the 2-fold table
  (surcomplex). `classify_real(p,q,r)` / `classify_complex(n,r)` are the
  bare-signature entry points (no metric needed); non-diagonal metrics are
  diagonalized first.
- **`oddchar/`** — odd-characteristic forms (re-exported flat): `field.rs`
  (`FiniteOddField` unifies Fp and Fpn square classes), `invariants.rs`
  (`classify_finite_odd`/`finite_odd_witt`/`discriminant_finite_odd`/
  `hasse_invariant_finite_odd` ≡ +1 over finite fields — ONE generic implementation
  keyed off the trait; Fp and Fpn share the path). dim + disc complete.
- **`char2/`** — characteristic-2 invariants (re-exported flat): `arf.rs` (the Arf
  invariant: `arf_f2` F₂ bitmask, `arf_nimber` for the represented nimber field,
  `arf_char2`/`arf_fpn_char2` for supported finite char-2 fields, `arf_ordinal_finite`
  for detected finite ordinal-nimber subfields; all use symplectic reduction + trace and
  return `ArfInvariants { arf: u128, ... }`), `dickson.rs` (`dickson_matrix = rank(g−I)
  mod 2`, ker = SO; `dickson_of_versor` validates the input is a versor then delegates
  to the generic versor grade parity), `field.rs` (`FiniteChar2Field` — the
  **additive** mirror of `FiniteOddField`: carries `artin_schreier_class =
  Tr_{F_q/F₂}` instead of `is_square_value`, since in char 2 the multiplicative square
  class is trivial and the working datum is `F/℘(F) ≅ F₂`; impl for `Fp<2>`/`Fpn<2,N>`,
  NOT `Nimber` — same boundary as `FiniteOddField`), `extraspecial.rs` (the
  extraspecial 2-group `1→F₂→E→V→0` attached to a nonsingular `F₂` quadratic form,
  with commutator `B`, squaring map `Q`, plus/minus type classified by the Arf bit,
  and the finite Heisenberg/Pauli representation whose center acts by `-I` and whose
  projective transvection intertwiners give the bounded Weil/metaplectic layer),
  `brown.rs` (the **Brown invariant** `β ∈ ℤ/8` of a `ℤ/4`-valued quadratic
  refinement — the char-2 cell of
  the mod-8 spine, Bridge M: `brown_f2`/`double_f2` + `BrownInvariants`, computed by
  radical splitting plus line/plane reduction with exact-integer enumeration retained
  as a test oracle. `β(2q′) = 4·Arf(q′)` lands the Arf bit as the 2-torsion, and
  `DiscriminantForm::brown_invariant` gives `β ≡ sign(L) mod 8` on 2-elementary
  discriminant forms — a fifth, float-free route to `σ mod 8`; the integral
  `FqmGaussPhase` projection carries the same Milgram/Brown phase over all shipped
  discriminant groups, and `fqm_witt` upgrades that phase to a bounded exact
  Wall/Nikulin Witt normal form.
  Category trap:
  Brown's `b` is symmetric-not-alternating with `b_ii = q_i mod 2`, NOT the engine's
  alternating polar — `double_f2` is the only bridge between the categories).

The char0↔char2 classifier **symmetry** (the real 8-fold table mirrored by the
char-2 Arf/Brauer–Wall story) is one of the project's central threads.

## `witt/` — the invariant groups (Witt group, Witt ring, Brauer–Wall)

The three abelian groups the classifiers land in, one shelf (`mod.rs` re-exports
flat). Home of the **mod-8 spine**: `BW(ℝ) ≅ ℤ/8` is the same periodicity as the
char-0 8-fold table, Bott, and `E₈` in `integral/`.

- **`witt/class.rs`**`WittClass`: the Witt group `W_q(F) ≅ ℤ/2` of the nimber
  field, Arf-classified with `u128` bits (`try_from_metric` takes `Metric<Nimber>`;
  ordinal-window metrics go through the `classify` façade's `WittClassG::Char2`). Plus
  `WittClassG`: the Char0/OddChar/Char2 trichotomy enum (odd-char is order-4) with
  checked group and ring operations; `try_mul` rejects Char2 because `W_q` is a
  module, not a ring.
- **`witt/ring.rs`** — the Witt RING: `tensor_form`, Pfister forms, fundamental ideal
  Iⁿ, the eₙ staircase (e0=dim, e1=disc, e2=Hasse). Stabilization per field (I²=0 over
  F_q; infinite ℝ tower via `e_real`). DON'T claim Arf=e2 (char-2 indexing is Kato's,
  pinned).
- **`witt/brauer_wall.rs`** — the Brauer–Wall group BW(F): `bw_class_real` (Bott index
  (q−p) mod 8 ⇒ BW(ℝ)=ℤ/8), `bw_class_complex` (ℤ/2), `bw_class_rational`
  (`RationalBrauerWallClass` over ℚ: dimension parity + signed discriminant +
  Bridge-F `c(q)` with Wall's twisted law), `bw_class_function_field`
  (`FunctionFieldBrauerWallClass` over odd `F_q(t)`: the same Wall coordinates, with
  the ungraded Clifford component represented by ramified `FunctionFieldPlace`s),
  `bw_class_finite_odd` (order-4 ≅ W(F_q)), `bw_class_nimber`, and façade dispatch
  for supported finite char-2 fields/windows (char-2 Arf/Witt class `ℤ/2`,
  nonsingular metrics only). Law = graded_tensor/direct sum.
- **`witt/brauer_rational.rs`** — the **ungraded** rational 2-torsion Brauer class
  `Brauer2Class` (a set of ramified `Place`s, `add`/`local_invariant`/
  `satisfies_reciprocity`/`quaternion`): `hasse_brauer_class` (the Hasse–Witt
  invariant `s(q)`) and `clifford_brauer_class` (the *actual* Clifford-algebra class
  `c(q) = s(q) + δ(n mod 8, disc)`, corrected by Lam GSM 67 pp. 117–119). Kept strictly
  distinct from the graded rational `RationalBrauerWallClass` it projects out of.
- **`witt/cyclic.rs`** — Bridge K: the **full `ℚ/ℤ`** ungraded Brauer class
  `BrauerClass` (a `BTreeMap<Place, Rational>` of `inv_v ∈ [0,1)`, `add`/`invariant_sum`/
  `local_invariant`/`from_local`, plus the Bridge F embedding `from_two_torsion`/
  `two_torsion`) and `cyclic_algebra_invariant::<E: CyclicGaloisExtension>(a)` where
  `E::Base: Valued` = `v(a)/n mod ℤ` for the unramified local cyclic class (monomorphized
  at `Qq`; reads only the valuation, so exact even on the capped model). The tame Kummer
  slice is separate: `tame_symbol_exponent` / `tame_symbol_invariant` use valuation +
  angular component over `ResidueField` legs when `n | |κ*|`; wild symbols stay deferred.
  The 2-torsion `Brauer2Class` is the `½`-slice. The full-strength `F_q(t)` reciprocity
  legs (`constant_extension_invariants`, `tame_symbol_invariants_ff`) live in
  `local_global/function_field.rs`; the degree-2 norm-form oracle ties `inv` to the
  Hasse–Minkowski layer. Ungraded, distinct from `BrauerWallClass`; finite legs carry no
  Brauer content (Wedderburn).
- **`witt/milnor.rs`** — Milnor's map `W(ℚ) → ℤ ⊕ ⊕_p W(F_p)` as a computational
  complete invariant: `global_residues` returns the signature plus all nonzero
  residues. Odd `p` uses the second Springer residue; `p=2` uses Milnor's hand
  boundary, represented as the `W(F_2) ≅ Z/2` `Char2` carrier. The equal-characteristic
  twin is `global_residues_ff`, the split odd-`F_q(t)` map
  `W(F_q(t)) ≅ W(F_q) ⊕ ⊕_π W(F_q[t]/π)`: infinity gives the constant-field summand,
  finite monic irreducibles give the nonzero second residues. Cross-checked against
  `springer_decompose_qp`, Hasse–Minkowski reconstruction tests, and exact
  function-field place tests.

(The *numeric* field invariants the ring implies — level, u-invariant — live in
`field_invariants.rs`, not here.)

## `springer/` — the discrete-valuation decomposition (a local–global symmetry)

One generic engine for the discretely-valued legs + the surreal odd-one-out + the
char-2 mirror, one shelf (`mod.rs` re-exports flat).

- **`springer/local.rs`** — the GENERIC engine `springer_decompose_local<K:
  ResidueField>` (+ `LocalResidueForm`/`LocalSpringerDecomp`/`parity_layer`), keyed
  off `scalar::ResidueField`. ONE implementation; the residue field `k` is read
  through the trait (`residue_unit` = the angular component), the square-class via
  `is_square_finite`. Odd residue char only.
- **`springer/padic.rs`** — the **mixed-characteristic** named entry points (thin
  wrappers returning `LocalSpringerDecomp`): `springer_decompose_qp` over `Q_p`
  (residue F_p) AND `springer_decompose_qq` over `Q_q` (residue F_q; `F=1` recovers
  Q_p). Value group ℤ NOT 2-divisible ⇒ TWO residue layers survive (`parity_layer`) =
  W=W(k)².
- **`springer/laurent.rs`** — the **equal-characteristic** named entry point:
  `springer_decompose_laurent` over `F_q((t))` (char p, residue F_q). Same two-layer
  story; residue char 2 REJECTED (the char-2 Witt boundary). Used by
  `local_global/function_field.rs` as an independent oracle.
- **`springer/surreal.rs`** — over the surreals (char 0, residue ℝ). The ONE that
  does NOT fit the generic engine: value group 2-divisible ⇒ W(No)=W(ℝ)=ℤ (second
  layer collapses), residue ℝ is a signature not a finite square-class. Keeps its own
  engine (the flat `ResidueForm`/`SpringerDecomp`/`springer_decompose` names) — that
  mismatch IS the symmetry, not a gap. So it stays out of `ResidueField`.
- **`springer/char2/`** — the **char-2 local Witt/Springer decomposition**
  (Aravire–Jacob `(φ₀, ψ, φ₁)`) + global isotropy over `F_q(t)`. Tightly coupled to
  `local_global/function_field_char2.rs` (it reuses that engine's `pub(crate)`
  helpers); detailed in the local–global section.

## Local–global (`local_global/`)

- **`local_global/global_field.rs`** — the `GlobalField` TRAIT: the local–global
  principle written ONCE over the two kinds of global field, `Rational` (ℚ) and
  `RationalFunction<S>` (`F_q(t)`). Five checked per-field primitives
  (`try_relevant_places`/`try_hilbert_symbol_at`/`try_is_local_square`/
  `try_is_global_square`/`try_is_isotropic_at_place`) + four checked DEFAULT theorem
  methods (`try_hasse_at_place`/`try_reciprocity_product`/`try_ramified_places`/
  `try_is_isotropic_global` = Hasse–Minkowski). The arithmetic primitives stay
  per-field (ℚ is i128 number theory with an archimedean place; `F_q(t)` is `F_q[t]`
  factorization with none — the missing real place IS the content), so
  `padic`/`adelic`/`function_field` keep their named public modules as thin wrappers
  over the trait. NOT a `Valued` abstraction (a global field carries all places at
  once, like `Adele`). The mirror of what `ResidueField` does for the discrete
  Springer engine.
- **`local_global/padic.rs`** — the GENUINE Hilbert symbol over Q_p (odd-p + p=2
  mod-8) — nontrivial unlike oddchar's +1 — + checked Hasse–Minkowski
  `try_is_isotropic_q` over ℚ. Oracle: Hilbert reciprocity `∏_v=+1`.
- **`local_global/adelic.rs`** — local–global rational helpers: `hilbert_product` over
  all places, rank≥3 adelic Hasse–Minkowski breakdown
  (`isotropy_over_adeles`/`AdelicIsotropy`), Brauer local invariant sums. Reuses
  `local_global/padic.rs`.
- **`local_global/function_field.rs`** — the **equal-characteristic mirror** of
  `padic.rs` + `adelic.rs` over `F_q(t)`. Places `FunctionFieldPlace<S>{Infinite,
  Finite(Poly<S>)}` (monic irreducibles + the degree place) — the single place type,
  shared with the char-2 Artin–Schreier layer (below) and the `GlobalField::Place`
  associated type for `RationalFunction`. The **tame** Hilbert symbol
  `try_hilbert_symbol_ff` (the odd-`p` branch with the residue Legendre → `χ_κ`; no
  `p=2` branch since `q` is odd), reciprocity `try_hilbert_reciprocity_product_ff`,
  `try_is_isotropic_ff`/`try_is_isotropic_at_place_ff`/`try_isotropy_over_ff_adeles`
  (Hasse–Minkowski, u-invariant 4 like `Q_p`, but **no archimedean place** ⇒ no
  definiteness condition), `try_ramified_places_ff` (even count), and the tame Kummer
  surface `try_tame_symbol_exponent_ff` / `try_tame_symbol_invariant_ff`. Names carry
  `_ff` where `padic.rs` collides. Exact (the product formula is `deg`-counting); odd
  residue char only. Cross-checked against `springer_decompose_laurent`. Also carries
  Bridge K's full-`ℚ/ℤ` reciprocity legs: `constant_extension_invariants(n, a)`
  (`inv_v = deg(v)·v(a)/n`, the constant extension `F_{qⁿ}(t)` — unramified at every
  place, so `Σ_v inv_v = deg(div a)/n = 0`) and
  `tame_symbol_invariants_ff(n, a, b)` when `μ_n ⊂ F_q`; both return a `Vec` since
  `FunctionFieldPlace` is not `Ord`.
- **`local_global/function_field_char2.rs`** — the **equal-characteristic-2** mirror:
  the **asymmetric Artin–Schreier symbol** `[a,b)` over `F_{2^m}(t)` (`a` additive mod
  ``, `b` multiplicative), NOT the tame symbol. Local invariant = the **Schmid
  formula** `s_v(a,b) = Tr_{κ/F₂}(Res_v(a·dlog b))` (`artin_schreier_symbol_at`), via a
  from-scratch residue-of-differentials engine (Hensel series `T(u)`, `P(T)=u`; the
  `` place by `u=1/t`). Reciprocity `∑_v s_v = 0` (`artin_schreier_reciprocity_sum`, the
  gold oracle) + even ramification (`artin_schreier_ramified_places`). Generic over
  `FiniteChar2Field` (so `F₂(t)`, `F₄(t)`, `F₈(t)` share one engine). The symbol
  surface carries the `artin_schreier_*` prefix and reuses the SAME
  `FunctionFieldPlace` as the odd layer — but it stays a **separate, additive** layer
  that cannot implement the multiplicative `GlobalField` trait. That asymmetry is the
  content: an additive Artin–Schreier symbol with XOR reciprocity here, the
  multiplicative Hilbert symbol with product reciprocity over there — the same kind of
  honest gap as the missing real place over `F_q(t)`. The crate-private helpers
  (`strip_factor`/ `inverse_mod`/`trace_kappa_to_f2`, and
  `char2_monic_irreducible_factors` — a thin wrapper over the shared `poly_factor`
  finite-field factorizer) are `pub(crate)` so `springer/char2/` reuses them.
- **`springer/char2/`** (detail) — the equal-char-2 mirror of `springer/local.rs`
  (but NOT the odd story at `p=2`: the wild `R_π` summand the `W=W(k)²` grading
  misses). `springer_decompose_local_char2(form, place)` gives the **Aravire–Jacob**
  `(φ₀, ψ, φ₁)` (`Char2LocalDecomp`): split each block coeff by Laurent-parity
  (`K=K²⊕πK²`), apply `[a,b]≅[1,a_ev·b]⊥⟨π⟩[1,a_odd·b]`, push each `[1,c]` to
  **Artin–Schreier normal form** (`asnf`: drop positive poles, clear even neg poles
  via `c_{n/2}+=√c_n`, keep the `κ`-constant Arf bit + odd neg poles `R_π`). Local
  isotropy `local_anisotropic_dim_char2`/`local_is_isotropic_char2` is
  invariant-driven (`ab∈℘(K_v)` for binary blocks, the AJ kernel for nonsingular
  parts, valuation parity for totally-singular tails, the odd-dimensional Clifford
  invariant `Σ s_v(a_i b_i, c/a_i)` for one-class radical tails; `u(K_v)=4` ⇒ rank ≥ 5
  isotropic). The form is `Char2QuadForm` (binary blocks + a totally-singular tail).
  **Global isotropy** `is_isotropic_global_char2(form) → Option<bool>` is
  Hasse–Minkowski over `F_q(t)` itself, on three ingredients past the symbol:
  `global_is_pe(f)` (`f ∈ ℘(F_q(t))`? — finite sweep of `f`'s poles + ``, settles
  rank 2: `[a,b]` iso ⟺ `ab ∈ ℘`), `ff_is_square(f)` (`f ∈ K²`? — all odd-degree
  coeffs of `num·den` vanish, settles the totally-singular part via `[K:K²]=2`), and a
  bad-place sweep over `artin_schreier_form_places(form)` for rank 3/4 (good places
  isotropic by Chevalley–Warning). `u(F_q(t))=4` (`C₂`) ⇒ rank ≥ 5 isotropic.
  **Looks like a bug, isn't:** rank 2 is NOT a finite bad-place scan — the
  constant-trace ``-obstruction (`[1,1]/F₂(t)`) lives at infinitely many odd-degree
  places, caught only by the global `` test.

## The "form + involution" siblings

- **`symplectic.rs`** — alternating forms: `SymplecticForm`, `hyperbolic`,
  `direct_sum`, `classify` (rank + radical_dim — the complete invariant,
  char-uniform). `classify_symplectic(gram)` convenience. The char-2 polar form of a
  nonsingular quadratic form lives here.
- **`hermitian.rs`** — Hermitian forms, the involution sibling the symmetric leg never
  used. `HermitianForm` covers Surcomplex via `conj()`: conjugate-symmetric Gram,
  unitary congruence diagonalize → real diagonal, signature (Sylvester, complete
  invariant = U(p,q)); `from_skew` handles the skew-Hermitian case via mult by i.
  `FiniteHermitianForm<F>` covers finite fields of even prime-field degree using the
  middle Frobenius `x -> x^{p^k}` for `F_{p^{2k}}/F_{p^k}`; its complete invariant is
  `FiniteHermitianInvariants { rank, radical_dim, ... }`. This intentionally models
  intermediate fixed fields directly, rather than pretending the existing
  `FieldExtension` associated base can name every `F_{p^{2k}}/F_{p^k}` subextension.

## Field invariants, the trace-form bridge, and the game bench

- **`field_invariants.rs`** — numeric FIELD invariants the Witt ring implies:
  level/Stufe s(F), pythagoras_number, u_invariant, is_sum_of_n_squares — computed
  over finite F_p (level≤2, u=2); ℝ/Q_p textbook constants documented.
- **`poly_factor.rs`** — the shared finite-field polynomial factorizer
  (`pub(crate) monic_irreducible_factor_support`), the place-finding primitive behind
  both function-field symbol layers; the public wrappers `monic_irreducible_factors`
  (`local_global/function_field.rs`, odd) and `char2_monic_irreducible_factors`
  (`local_global/function_field_char2.rs`, char-2) call into it.
- **`trace_form.rs`** — the seam from `scalar::CyclicGaloisExtension` to the
  classifiers. `trace_twisted_form::<E>(k) -> Metric<E::Base>` builds the
  **Frobenius-twisted** trace form `Q_k(x) = Tr_{E/F}(x·σ^k(x))` (q on the diagonal,
  the alternating polar `Tr(eᵢσ^k eⱼ + eⱼσ^k eᵢ)` off it). NOT the naive `Tr(x²)`,
  whose polar form vanishes in char 2 (Frobenius is additive) — the trap the twist
  avoids. `transfer_diagonal(entries)` is the related Scharlau transfer
  `s_*(⟨λ₁,…,λᵣ⟩)` of a diagonal form along `Tr_{E/F}` (char ≠ 2; the `k=0` case).
  `cyclic_algebra_trace_form::<E>(&a)` builds the literal cyclic-algebra trace
  form `Trd_A(z²)` for `A=(E/F,σ,a)`: self-lines route through the same assembler,
  and `i`/`n-i` lines are pure polar pairs. It is not the reduced norm; for
  quaternions the honest relation is `Trd(z²)=Trd(z)^2-2·Nrd(z)`. Instances:
  `Surcomplex` k=1 → the **norm form** `⟨2,2⟩`; unramified `Qq/Qp`
  via the Teichmuller-lifted residue basis; odd `Fpn` → a diagonalizable trace form.
  Two char-2 entry points to the **Gold form** `Tr(x^{1+2^a})`, classified →
  `ArfInvariants` (rank `= m − gcd(2a,m)`, Arf → the zero-count): `trace_form_arf::<E:
  …<Base=Fp<2>>>(k)` (the typed `Fpn<2,m>` path — build over `F_2`, lift `F_2 ↪
  Nimber` via `Metric::map(|x| Nimber(x.value()))`), and `gold_form(m, a)` (the nim-native path over the
  subfield `F_{2^m} ⊂ Nimber`, m a power of two ≤ 128, reaching F_16/F_256/… that
  `Fpn` can't). The form has dim `[E:F]`, capped at `MAX_BASIS_DIM=128`. The same
  `CyclicGaloisExtension` basis/generator data also feeds
  `clifford::frobenius::{galois_linear_map, frobenius_linear_map}`, giving the bridge
  a Clifford outermorphism oracle.
- **`quadric_fit.rs`** — the "is this P-set a quadric?" research BENCH (split from the
  char2 classifier): `fit_f2_quadratic` (Boolean ANF/Möbius transform over the 2^k
  membership table) + `QuadricFit` + `is_genuinely_quadratic`. The instrument the game
  probes (misère_quotient / octal_hunt / loopy_quadric) feed P-positions into —
  distinct from the classifier.

## Things that look like bugs but are not (forms layer)

- **`diagonalize`/`as_diagonal` return `None` in characteristic 2.** Not a bug: a
  nonsingular char-2 form has an alternating polar form and is not diagonalizable. The
  char-2 leg classifies via the symplectic Arf reduction (`char2/`) on the full (q, b)
  metric instead.
- **The odd-char Hasse invariant is ≡ +1** over a finite field — genuinely trivial
  there, unlike the p-adic Hilbert symbol in `local_global/padic.rs` (where Hasse does
  real work).
- **Rational & Surcomplex impl `ClassifyForm` but not `ClassifyWitt`** — their Witt
  data isn't a single `WittClassG`. Honest, not a gap.