Projective gauge and strict decoding

The canonical equivalence is (P,Q) ~ (λP,λQ) for nonzero finite real λ. canonical_l2_qpositive_v1 validates representation, promotes calculations to float64, uses max-scaled L2 normalization, and chooses a deterministic global orientation: Q is non-negative, with the first nonzero numerator as the Q=0 tie-breaker.

The all-zero tuple is not a valid pole; it is REPRESENTATION_FAULT. Non-finite coordinates are execution faults. The dimensionless denominator score is the absolute normalized denominator. Rejection thresholds apply to that score.

Array inputs are elementwise scalar pairs by default. A vector-valued numerator with one shared denominator must pass coordinate_axis explicitly; the selected axis is then normalized as one tuple, receives one orientation witness, and requires the denominator to be identical across that axis. For example, normalize_projective(P, Q, coordinate_axis=-1) is the canonical multi-output-head boundary.

Schema-v3 ONNX export cannot preserve an eager Python equality assertion as a runtime guard. A custom tuple model must therefore declare both projective_coordinate_axis and projective_denominator_contract="shared_denominator_by_construction_v1". The latter is a reviewed capability assertion that every runtime input produces one denominator by construction; export refuses an axis declaration without it. Built-in shared-denominator rational heads carry this capability. The exported graph still compares the denominator coordinates: disagreement becomes REPRESENTATION_FAULT, rejects operationally, and records a task-domain-invalid cause.

StrictDecodePolicy.coordinate_axis carries the same choice through typed decoding and is included in policy serialization and hashing. Policy schema v1 is retained only as a read-only elementwise-pair identity; newly emitted policies use schema v2. Shared-denominator projective models declare their axis, and export refuses an explicitly mismatched policy.

The gauge is real-only. Python, NumPy, and Torch complex coordinates raise TypeError before float64 promotion; no backend may discard an imaginary part. Torch normalization replaces invalid coordinates before norm arithmetic, so non-finite and all-zero cells contribute zero gradient rather than allowing an inactive masked branch to inject NaN into shared parameters.

Every serialized gauge and decoder identity validates all algorithm-defining fields. A caller cannot relabel normalized-score execution as a raw-denominator threshold family or replace the global orientation rule under the same policy identifier.

canonical_denominator_v0.6 identifies legacy metadata only. Its raw denominator thresholds are gauge-dependent and must be recalibrated before use with the canonical gauge.

Strict decoding produces exact bottom only from proven exact-zero evidence. An unproved machine zero is an ambiguous rejected NO_CORE result. Threshold rejection preserves a finite decoded core whenever decoding itself is valid.