fix(udpscope): bound the reconstructed timeline against the wall clock
Round 3 of the Task 4 review. Three defects, all in FrameDecoder rule 3. The resync backstop was one-directional. `predicted` is never below lastEmittedEnd + dt, so rejecting a correction that would step backwards meant only a LAGGING chain could ever be pulled back; a chain running fast drifted ahead without bound. Two hosts' crystals differ by tens of ppm, so a declared SamplingRate is always slightly wrong in one direction or the other and this is certain on a long session. A leading timeline cannot be corrected in one burst without going backwards -- lastEmittedEnd is by definition past arrival -- so the excess is bled off by drawing each burst 10 % narrower until the timeline is back inside the threshold. A repeated packet counter was treated as a normal packet. The C client de-duplicates fragments only, so an unfragmented update reaching a host that joined the group on two interfaces was emitted twice, doubling the values and advancing the timeline by a burst that never existed. The samplingRate == 0 path differenced two HrtRateFit::toSeconds() results. toSeconds() divides an absolute tick count -- ~1e11 on a producer that has been up a day -- by a rate refitted on every packet, so its few-parts-in-1e4 wobble arrives multiplied by the whole elapsed epoch: tens of milliseconds of jitter on a value whose consecutive difference is a few milliseconds. Raw ticks are differenced instead, anchored on the first usable packet so the wobble applies only to the interval since attach. The existing hrt-gap test could not have caught the last one: its 10 ms producer period made the expected answer exactly kDefaultDt, so a decoder that derived nothing passed. It now uses 25 ms. Four tests added, all sabotage-proven. The plan is updated to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
7102412a9f
commit
3270284cfe
@@ -50,7 +50,12 @@ private:
|
||||
ClockOffset offset;
|
||||
double lastPacketWall = 0.0;
|
||||
bool lastPacketValid = false;
|
||||
double lastAccHrtSec = 0.0;
|
||||
/** Raw ticks, not seconds — see the comment in the samplingRate == 0
|
||||
* branch for why a tick difference is the only safe way to measure a
|
||||
* producer-side interval while the rate is still being re-estimated. */
|
||||
uint64_t lastAccHrt = 0u;
|
||||
uint64_t hrtRef = 0u;
|
||||
bool hrtRefValid = false;
|
||||
bool lastAccValid = false;
|
||||
uint32_t prevAccCount = 0;
|
||||
/** For accumulated scalars with a declared sampling rate: end timestamp
|
||||
|
||||
Reference in New Issue
Block a user