Commit Graph

13 Commits

Author SHA1 Message Date
Hermes Agent c93eda9156 Fix parityCount to use Math.floor, neededPackets to use totalGenerations
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.
2026-05-04 15:32:25 +00:00
Hermes Agent d7fc7606ec fix(receiver): revert indicator to framesWithQR/accepted/needed with correct math
- 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.
2026-05-04 14:36:39 +00:00
Hermes Agent f4ef1bb473 fix(receiver): replace misleading packet ratio with generation progress
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.
2026-05-04 14:09:21 +00:00
Hermes Agent 87bd318adc v0.4: outer RS error correction, scanner timer, generation-based progress
- Add outer Reed-Solomon error correction across generations
  (3% overhead, 1 parity gen per ~33 source gens)
- Fix progress display: show generations solved/needed instead of
  raw packet counts, making outer EC benefit visible
- Add decode timer: tracks elapsed time from first frame to completion
  and shows throughput in KB/s
- Add benchmark test confirming outer EC reduces tail waiting time
  under biased frame loss
- Remove per-generation hash verification (superseded by outer RS)
- Update deployment base path to /hermes-web-demos/qr/
2026-05-03 19:04:06 +00:00
Hermes Agent 8d894b08e6 feat(receiver): remove sessions, add filename/mime, fix gen counter, compact UI
- Removed session tracking entirely; single global decode state
- Receiver UI: no sessions table, no big progress bar
- Inline stats above video: scanned / useful / need  ·  gen X of Y
- Sender passes filename and mimeType to encode worker
- Packetizer wraps file payloads with [filenameLen][name][mimeLen][mime] header
- Decode worker parses metadata and uses it for download name/type
- Fixed generation counter bug: final progress was skipped when reconstruction
  succeeded; now reportProgress is called right before early return
2026-05-03 13:31:47 +00:00
Hermes Agent 2017447e81 feat(receiver): informative frame stats, camera zoom, crop overlay, jsQR opts
- Frame count now shows: scanned / useful (linearly independent) / minimal needed
- Camera zoom via getUserMedia track.applyConstraints when supported
- Software crop fallback with visible dashed-square overlay on video
- Corner markers on scan region for visual feedback
- qr_decode accepts inversionAttempts option for faster GIF decoding
- Preserved attemptBoth for camera scanning (handles glare/reflections)
2026-05-03 13:10:08 +00:00
Hermes Agent bbe49ddee8 refactor: replace manifest with fixed header, single V10-M profile
- Remove CBOR manifest and manifest.ts entirely
- Fixed 18-byte packet header: sessionId, generationIndex, symbolIndex,
  packetType, totalGenerations, dataLength, flags, reserved
- Single hardcoded profile: QR V10, ECC M, K=16, R=8, payload=191 bytes
- Add isText flag (bit 0 of flags) for text vs binary routing
- Remove hash computation and profile selection UI
- Update all tests to match new protocol (33 tests passing)
- Fix generateCoefficients arg order bug in complete.test.ts
- Fix createQRGif dimension bug in tests
- Make prod_roundtrip frame loss deterministic

All 33 tests pass. Build succeeds.
2026-05-03 12:10:09 +00:00
Hermes Agent 2506ac317c Fix decode stalling: include packetType in dedup key to prevent manifest/data collision
The dedup key was `::`, which
caused manifest fragment 0 to collide with systematic symbol 0. The RLNC
decoder then never reached full rank, so generations never solved and the
receiver appeared to hang.

- Add packetType to dedup key so manifest/systematic/coded symbols are unique
- Add completed session flag to ignore late frames after reconstruction
- Prevent trailing progress message from overwriting complete status
- Add frame_decode and prod_roundtrip tests
2026-05-03 02:12:40 +00:00
Hermes Agent 98eaadfa87 Add debug logging to decode worker: track frame count, report QR null/error messages to UI. Error display now visible in GIF file mode. 2026-05-02 23:29:32 +00:00
Hermes Agent 067c4abbc7 Fix GIF file mode: send transferable ArrayBuffer pixels instead of ImageData objects (structured clone can fail in some browsers). Worker reconstructs ImageData from received buffer. 2026-05-02 23:19:56 +00:00
Hermes Agent cad1f91b92 Fix QR decode for binary data: use jsQR chunk.bytes instead of result.data (UTF-8 drops bytes>127). Fix GIF LZW decoder: don't reset bit buffer on clear code (discards valid bits). Fix receiver GIF file mode: use gif_parser instead of drawImage (only captured first frame). 2026-05-02 23:04:00 +00:00
Hermes Agent 6f3f0b2ee2 Fix receiver: stale closure + add GIF file test mode
- Fix stale closure bug in camera capture loop (scanning state
  captured as false, preventing any frame capture)
- Add GIF File input mode to receiver — upload a QR-over-GIF
  directly to test the decode pipeline without camera
- Update decode worker to accept imageData or frameData
- Receiver now shows two input modes: Camera and GIF File
2026-05-02 22:22:42 +00:00
Hermes Agent b20e5c9c17 Initial implementation: QR-over-GIF Transfer System
- Protocol: packet format, CRC32C, CBOR manifest, fragmentation
- FEC: GF(256) arithmetic, xoshiro128** PRNG, systematic RLNC encoder/decoder
- QR: generation (qrcode-generator), rasterization (3px/module), decoding (jsQR)
- GIF: animated GIF generation (gifenc) with 2-colour palette
- Preprocessing: deflate compression, SHA-256 hashing
- Sender pipeline: packetizer, frame scheduler with interleaving
- Workers: encode, gif generation, decode/reconstruction in Web Workers
- UI: Preact SPA with Sender/Receiver tabs, dark theme
- Tests: 93 passing (unit, property-based, integration, E2E)
- Default profile: Robust (V31-Q, K=24, R=12)
- Deployed to /hermes-web-demos/qr-transfer/
2026-05-02 21:37:06 +00:00