Skip to content

Streaming decoding phase 0: descriptor invariants, loud decision points, and the frame schema split - #651

Open
ciaranra wants to merge 5 commits into
devfrom
streaming-phase0-foundations
Open

Streaming decoding phase 0: descriptor invariants, loud decision points, and the frame schema split#651
ciaranra wants to merge 5 commits into
devfrom
streaming-phase0-foundations

Conversation

@ciaranra

Copy link
Copy Markdown
Member

Phase 0 of the streaming/transversal-decoding program (design record: pecos-docs design/streaming-transversal-decoding.md, v2). Foundations only — no decoding behavior changes; every previously-silent wrong path now fails loud.

Summary

  • Descriptor invariants (AlgorithmDescriptor::validate): segment/boundary cardinality, every boundary-gate slot bounded by the frame width, and frame-slot schema checks (zero and odd slot counts rejected — the schema is two slots per patch, X then Z). All three decoder constructors validate; bindings validate before any DEM/subgraph build.
  • Logical gates after a patch's last memory op are emitted after final measurement and dropped from the algorithm descriptor #595's loud form: logical gates recorded after a patch's final MEMORY now raise instead of silently vanishing from the descriptor — and the review's probe found the mirror case, gates before the first MEMORY, which were silently re-attributed to the wrong boundary and produced a self-contradictory descriptor (stabilizer coordinates already swapped while boundary_gates claimed otherwise). Both directions now reject with distinct messages. The semantic redesign (terminal segments) remains tracked in Logical gates after a patch's last memory op are emitted after final measurement and dropped from the algorithm descriptor #595.
  • BoundaryGate::TGateInjection is documented as a feed-forward decision point but never consulted during decoding #596's loud form: descriptors containing TGateInjection decision points are rejected at construction by every decoder — no path can silently decode a T injection as Clifford. has_decision_points/num_decision_points are documented as constant in phase 0.
  • Frame schema split: new FrameBits (ObsMask-backed, no 64-slot ceiling) with an explicit num_frame_slots on the descriptor; num_observables now reports the DEM's actual declared count (previously 2 * num_patches, which doubled as the frame width and disagreed with the DEM). Per-segment observable counts now come from each segment's own sub-DEM. The dead per-qubit Vec<u64> frames and the dead ObservableBitOutOfRange variant are gone.
  • Broken helpers removed (closes propagate_s_gate_frame is a no-op for disjoint X/Z observable masks #645): propagate_s_gate_frame was provably a no-op for its documented disjoint-mask convention; propagate_h_gate_frame one function below carried the same mask-pairing trap (sets the whole Z mask for any X bit — wrong for multiple pairs). Both had zero production callers and are deleted, with a module note explaining why mask pairs cannot express per-pair frame ops. propagate_cnot_frames was audited (maskwise XOR is correct for multiple pairs) and gained a multi-bit regression test.
  • Phase-2 interface, defined not consulted: DecisionConsultingStrategy (consult(boundary_index, raw_ancilla_outcome, frame) -> Ready { corrected_bit } | NeedMoreData { extra_rounds }, #[non_exhaustive], bounded-retry contract documented) plus a defaulted DecodeStrategy::as_decision_consulting hook so the stored dyn DecodeStrategy can reach the subtrait without a future breaking constructor change.

Verification

  • 26 Rust suites across pecos-decoder-core / pecos-uf-decoder / pecos-qec; full tests/qec/surface/ Python suite green (733 passed) against a freshly built module including the LLVM lane.
  • Nine guards mutation-tested (leading/trailing gate rejection, empty-segment ordering, both cardinality checks, zero/odd slot counts, slot bounds, decision-point rejection), plus an out-of-range #[should_panic] pin on apply_boundary_gate so the hard assert cannot silently become debug-only.
  • Two independent adversarial review rounds; every finding verified against the code (the leading-gate defect and the unreachable-subtrait finding both came with executed repros) and closed.
  • clippy -D warnings including pecos-rslib, fmt, and the full pre-commit lane all pass.

Breaking notes (experimental surfaces): descriptor dicts gain num_frame_slots; LogicalAlgorithmDecoder::new/LogicalCircuitDecoder::new are fallible; frame accessors moved from u64 to FrameBits; DecoderError::ObservableBitOutOfRange removed.

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.

propagate_s_gate_frame is a no-op for disjoint X/Z observable masks

1 participant