parityCount: Math.ceil → Math.floor
- Small files (G ≤ 33) now truly get 0 parity generations
- Large files (G ≥ 34) still get proportional parity (≈3%)
- Previously Math.ceil always gave ≥1 parity for any G ≥ 1
neededPackets: K * sourceGenerations → K * totalGenerations
- Aligns with the round-robin scheduler: symbols are interleaved
across ALL generations, so practical minimum is K × totalGens
- Fixes the mismatch where 'needed' showed 32 but actual
decode required ~48 frames (for 2 source + 1 parity case)
Tests: Updated assembly test comments and totalGenerations params
to match new parityCount behavior.
Closes the long-standing 'needed frames count is off because of
outer error correction' issue.
- framesWithQR now counts ALL frames with a valid QR (including duplicates),
not just deduplicated ones. Moved increment before dedup check.
- acceptedPackets already correctly counts linearly-independent packets
(rank increase), capped at K per generation by the decoder.
- neededPackets = K * sourceGenerations, computed from constants.
- Keep generation count (solvedGens/sourceGens) as secondary indicator.
This gives an honest rough progress bar: useful can approach or briefly
touch required while some generations are still partially filled, but the
generation count is the definitive completion signal.
The compact indicator previously showed framesWithQR/acceptedPackets/neededPackets.
Because acceptedPackets counts parity-generation packets and uneven distribution
across generations, it could exceed neededPackets while the file was still not
decoded. This is confusing.
Change the primary compact indicator to generation counts:
framesWithQR / solvedGens / sourceGens gens
This is always meaningful: solved never exceeds required, and when they match,
the transfer is complete. Packet count is kept as a raw secondary number.
Small files are already well-protected by QR code ECC + fountain code.
Outer Reed-Solomon only kicks in when sourceGenerations ≥ 34,
where ceil(G * 0.03) ≥ 1. This eliminates 100% overhead for tiny files.
- parityCount(): remove Math.max(1, ...) floor
- Update tests to not assume parity always exists
- Increase outer_ec_benefit.test.ts payloads to >34 gens so
outer RS is actually active during benchmark
- Timer now starts when the first QR frame is detected (first progress
message from worker with totalFrames > 0) instead of when camera is
turned on. This eliminates the jump where elapsed time showed a few
seconds before any QR was actually seen.
- Replace separate 'scanned' and 'useful' stats with a compact
'QRs scanned/useful/required: X/Y/Z' indicator that clearly shows
progress toward the total packets needed for decode. The 'required'
count correctly accounts for outer RS overhead via K * sourceGens.
- Same display format applies to both camera and GIF-file input modes.