The replicant says how hard each update moves it

A tick a few times a second survived render interpolation, and it would:
interpolation smooths WITHIN a fixed step, and this is a discontinuity in
the stepped values themselves. Between updates a replicant is dead-reckoned
from updateOrigin over (lastPerformance - lastUpdate); when the next update
lands the basis is replaced and the position jumps by however far the
prediction had drifted. A few updates a second is a tick a few times a
second.

So Entity::ReadUpdateRecord now measures the correction before applying it:
how many arrived in the last five seconds, and the mean and worst distance
between where we had the entity and where the update says it was. Replicants
only, behind RP412CAMLOG, on a clock so a busy race cannot bury the log.

If that reads a few per second at tens of centimetres, the tick is named
and the fix is to damp the correction in rather than apply it instantly -
which is a real piece of work and worth sizing on evidence. If the
corrections are tiny, the tick is something else and this rules it out.

Also worth recording: RP412GAUGEDIAG is blind on a camera station. It only
reports when a full display sweep completes, and the missing-MFD bail
resets that counter every cycle, so the gauge theory could not be tested
that way. The camera's own symptom description did the work instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-10 23:49:17 -05:00
co-authored by Claude Opus 5
parent adcb81e7fc
commit 46aef0691e
+55
View File
@@ -435,6 +435,61 @@ void
//-----------------------
//
UpdateRecord *update = (UpdateRecord*)record;
//
// RP412CAMLOG: how hard does an arriving update MOVE this
// entity, and how often?
//
// Between updates a replicant is dead-reckoned from
// updateOrigin over (lastPerformance - lastUpdate). When the
// next one lands the basis is replaced, so the drawn position
// jumps by however far the prediction had drifted. Render
// interpolation cannot hide that: it smooths within a step,
// and this is a discontinuity in the stepped values
// themselves. If the interval is a few per second and the
// correction is tens of centimetres, that is a tick a few
// times a second - which is the symptom being chased.
//
// Reported per entity, on a five second clock, so a busy race
// does not bury the log.
//
if (RPCameraLog() && GetInstance() == ReplicantInstance)
{
static Scalar next_say = 0.0f;
static int corrections = 0;
static Scalar worst = 0.0f;
static Scalar total = 0.0f;
Vector3D drift;
drift.Subtract(
update->localOrigin.linearPosition,
localOrigin.linearPosition
);
Scalar distance = drift.Length();
++corrections;
total += distance;
if (distance > worst)
{
worst = distance;
}
if ((Scalar) Now() >= next_say)
{
if (next_say > 0.0f && corrections > 0)
{
DEBUG_STREAM << "CamLog: replicant corrections - "
<< corrections << " in 5s ("
<< (corrections / 5) << "/s), mean "
<< (total / corrections) << "m, worst "
<< worst << "m\n" << std::flush;
}
next_say = ((Scalar) Now()) + 5.0f;
corrections = 0;
worst = 0.0f;
total = 0.0f;
}
}
updateOrigin = update->localOrigin;
//