Skip to content

Backpressure flush: per-update timestamp loses per-frame fidelity in buildFlushDeltas #2716

Description

@NearlCrews

Problem

buildFlushDeltas in src/LatestValuesAccumulator.ts regroups accumulated path values by context + $source, merging them into a single Update and assigning that update the max timestamp across the merged items (lines 113-119). Per the Signal K spec, an update's timestamp applies to every path value in that update (there is no per-pathvalue timestamp field), so this emits incorrect timestamps for any merged path value whose original frame timestamp differs from the newest one in the group.

Concrete case

Two frames arrive during backpressure from $source: gps:

  • T=10.000: { timestamp: '10.000', values: [{ path: 'navigation.speedOverGround', value: 5.0 }] }
  • T=10.005: { timestamp: '10.005', values: [{ path: 'navigation.headingTrue', value: 1.5 }] }

accumulateLatestValue keys per context:path:$source, so each lands in its own accumulator entry with its original timestamp. buildFlushDeltas then merges both into one update keyed by context + $source and assigns timestamp 10.005:

$source: 'gps',
timestamp: '10.005',
values: [
  { path: 'navigation.speedOverGround', value: 5.0 },  // actually sampled at 10.000
  { path: 'navigation.headingTrue',    value: 1.5 }    // actually sampled at 10.005
]

A downstream consumer is told speedOverGround=5.0 @ 10.005, which is wrong.

Pre-existing

The merge-and-max-timestamp logic predates #2661. #2661 only restructured the loop.

Proposed fix

Group by context + $source + timestamp so path values that originally shared a timestamp ride in one update and the rest go in their own. Preserves spec semantics exactly. The N2K-PGN-demuxed-into-multiple-paths case (the main concern for extra updates per flush) usually shares a timestamp at source, so it'll still coalesce in practice. The extra-updates cost only shows up when timestamps genuinely differ, which is when keeping them separate is the right thing.

Alternative: group by context + $source and drop timestamp (or set it to flush time). Honest "summarized snapshot" semantics but loses original-sample freshness.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions