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.
This commit is contained in:
Hermes Agent
2026-05-04 15:32:25 +00:00
parent d7fc7606ec
commit c93eda9156
3 changed files with 7 additions and 7 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ export const OUTER_EC_OVERHEAD = 0.03;
/** Compute number of parity generations for G source generations. */
export function parityCount(sourceGenerations: number): number {
return Math.ceil(sourceGenerations * OUTER_EC_OVERHEAD);
return Math.floor(sourceGenerations * OUTER_EC_OVERHEAD);
}
/** Compute source generation count from total generations. */
+5 -5
View File
@@ -355,10 +355,10 @@ describe('Payload Assembly', () => {
solved.set(0, g0);
solved.set(1, g1);
// 2 source gens + 1 parity = 3 total. Both source gens present.
// 2 source gens + 0 parity = 2 total (small file, no outer RS). Both source gens present.
// dataLength spans into second generation so we can verify cross-gen assembly
const dataLength = K * MAX_PAYLOAD_SIZE + 4;
const data = assemblePayload(solved, 3, dataLength);
const data = assemblePayload(solved, 2, dataLength);
expect(data.length).toBe(dataLength);
expect(data[0]).toBe(1);
expect(data[1]).toBe(2);
@@ -385,8 +385,8 @@ describe('Payload Assembly', () => {
const solved = new Map<number, Uint8Array[]>();
solved.set(0, g0);
// 1 source gen + 1 parity = 2 total. Source gen present.
const data = assemblePayload(solved, 2, 3);
// 1 source gen + 0 parity = 1 total (small file, no outer RS). Source gen present.
const data = assemblePayload(solved, 1, 3);
expect(data.length).toBe(3);
expect(data[0]).toBe(1);
expect(data[1]).toBe(2);
@@ -403,7 +403,7 @@ describe('Payload Assembly', () => {
const solved = new Map<number, Uint8Array[]>();
solved.set(0, g0);
// 3 source gens + 1 parity = 4 total, but only 1 solved
// 4 source gens + 0 parity = 4 total, but only 1 solved
expect(() => assemblePayload(solved, 4, 3)).toThrow('only 1 generations solved');
});
});
+1 -1
View File
@@ -251,7 +251,7 @@ function reconstructData(state: DecodeState): void {
function reportProgress(state: DecodeState): void {
const totalGens = state.totalGenerations;
const solvedGens = state.solvedGenerations.size;
const needed = state.sourceGenerations > 0 ? K * state.sourceGenerations : 0;
const needed = state.totalGenerations > 0 ? K * state.totalGenerations : 0;
self.postMessage({
type: 'progress',