@golemio/pid 5.19.1-dev.2799089619 → 5.19.1-dev.2815853394

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/helpers/PositionsMapper.js +10 -4
  2. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/helpers/PositionsMapper.js.map +1 -1
  3. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.d.ts +30 -1
  4. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.js +73 -53
  5. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.js.map +1 -1
  6. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/DPPUtils.d.ts +2 -2
  7. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js +12 -20
  8. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js.map +1 -1
  9. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.d.ts +21 -1
  10. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.js +31 -0
  11. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.js.map +1 -1
  12. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/ComputeDelayHelper.js +35 -1
  13. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/ComputeDelayHelper.js.map +1 -1
  14. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/AbstractDelayAtStop.js +35 -5
  15. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/AbstractDelayAtStop.js.map +1 -1
  16. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/CommonDelayAtStop.js +37 -5
  17. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/CommonDelayAtStop.js.map +1 -1
  18. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/MetroDelayAtStop.js +37 -5
  19. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/MetroDelayAtStop.js.map +1 -1
  20. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js +12 -20
  21. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js.map +1 -1
  22. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/RegionalBusComputeDelayHelper.js +35 -1
  23. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/RegionalBusComputeDelayHelper.js.map +1 -1
  24. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/strategy/BusDelayAtStop.js +37 -5
  25. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/strategy/BusDelayAtStop.js.map +1 -1
  26. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.d.ts +68 -0
  27. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.js +216 -0
  28. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.js.map +1 -0
  29. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/abstract/AbstractPropagateDelayTask.js +37 -11
  30. package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/abstract/AbstractPropagateDelayTask.js.map +1 -1
  31. package/dist/schema-definitions/vehicle-positions/models/VPTripsModel.js +22 -10
  32. package/dist/schema-definitions/vehicle-positions/models/VPTripsModel.js.map +1 -1
  33. package/dist/schema-definitions/vehicle-positions/models/interfaces/VPTripsLastPositionInterfaces.d.ts +8 -8
  34. package/docs/asyncapi.yaml +0 -9
  35. package/docs/cache/types/psql.md +6 -11
  36. package/docs/processing/index.md +1 -0
  37. package/docs/processing/state_position_tracking/tcp_dpp_common.md +6 -0
  38. package/docs/processing/trip_context/index.md +149 -0
  39. package/package.json +1 -1
@@ -0,0 +1,149 @@
1
+ # Trip context (`IVPTripsLastPositionContext`)
2
+
3
+ Per-trip state carried between consecutive vehicle position updates. It represents what is known
4
+ about a trip's last processed position - id, coordinates, state, delay bookkeeping, cancellation
5
+ and a small tracking snapshot. One context instance exists per `tripId` for the lifetime of the
6
+ trip's real-time processing. Defined in
7
+ `src/schema-definitions/vehicle-positions/models/interfaces/VPTripsLastPositionInterfaces.ts`.
8
+
9
+ - **Created**: `TripContextHelper.createInitial(tripId)` when a trip is seen for the first time
10
+ in a processing run and has no persisted context yet.
11
+ - **Updated**: mutated in place while positions for the trip are processed (see below).
12
+ - **Persisted**: serialized to JSON and stored (Postgres); reloaded on the next run and merged back
13
+ into the working context.
14
+
15
+ This document covers, in order:
16
+
17
+ 1. [Core lifecycle rules](#core-lifecycle-rules) - the write boundary and the timestamp rule that
18
+ apply to every context mutation.
19
+ 2. [Field-specific contracts](#field-specific-contracts) - quirks of individual fields
20
+ (cancellation, the before-track-delayed seed, the date/string duality, last-stop delay
21
+ bookkeeping, the at-stop streak's asymmetric clear).
22
+ 3. [Fallback behavior](#fallback-behavior) - what happens when the incoming GPS position is
23
+ invalid, and the lean shape used to persist tracking snapshots.
24
+
25
+ ## Core lifecycle rules
26
+
27
+ ### Helper write boundary
28
+
29
+ - [`TripContextHelper.ts`](../../../src/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.ts)
30
+ is the only module allowed to mutate `IVPTripsLastPositionContext` fields.
31
+ - Callers (`PositionsManager`, `RegionalBusPositionsManager`, `ComputeDelayHelper`,
32
+ delay-propagation tasks, ...) always go through one of its exported functions instead of writing
33
+ to the context object directly.
34
+ - New processing logic that needs to change the context must add or reuse a function here rather
35
+ than mutating the context inline.
36
+
37
+ ### Timestamp rule (`transitionState`)
38
+
39
+ - `transitionState(context, state, options?)` stamps `lastPositionStateChange` (ISO string,
40
+ `new Date().toISOString()`) only when `state` actually differs from `context.lastPositionState`
41
+ - a state that repeats across consecutive positions does not re-stamp the timestamp.
42
+ - The one exception is `options.forceTimestamp`, used by delay propagation
43
+ (`TripContextHelper.recordPropagatedDelay`) to force a fresh `BEFORE_TRACK_DELAYED` transition and
44
+ timestamp even when the state did not change, since the propagated delay itself is new information.
45
+
46
+ ## Field-specific contracts
47
+
48
+ ### Cancellation: sticky vs. plain
49
+
50
+ `lastPositionCanceled` means different things depending on which manager writes it, both via the same
51
+ `TripContextHelper.commitValidPosition(context, position, positionToUpdate, canceled)` call:
52
+
53
+ - **`PositionsManager`** treats it as a sticky accumulator: once a position sets it (via
54
+ `lastPositionStaysCanceled`, driven by `hasTcpEventOrCancel`), later positions keep it canceled
55
+ even if they themselves are not canceled (`lastPositionStaysCanceled || position.is_canceled`).
56
+ - A trip cannot un-cancel itself here.
57
+ - **`RegionalBusPositionsManager`** passes the plain per-position `position.is_canceled` with no
58
+ stickiness - the flag reflects only the current position.
59
+ - Do not assume `lastPositionCanceled` is sticky across all managers; check which manager owns the trip.
60
+
61
+ ### Sticky seed: `lastPositionBeforeTrackDelayed`
62
+
63
+ - `context.lastPositionBeforeTrackDelayed` stores `{ delay, origin_timestamp }` for the last
64
+ `BEFORE_TRACK_DELAYED` position, written by `TripContextHelper.recordBeforeTrackDelayed` and
65
+ `TripContextHelper.recordPropagatedDelay`.
66
+ - The timestamp is stored as-is (`Date` or whatever was passed in) - it is never re-derived by
67
+ calling `.getTime()` on an already-stored value.
68
+ - Treat it as an opaque, already-resolved snapshot rather than something to recompute from.
69
+
70
+ ### Date/string contract on `origin_timestamp`-family fields
71
+
72
+ - `lastPositionBeforeTrackDelayed.origin_timestamp` is typed `string | Date | null`.
73
+ - A context persisted to Postgres round-trips through `JSON.stringify`/`JSON.parse`, which
74
+ serializes a `Date` to an ISO string - so a freshly created context in memory holds a `Date`,
75
+ while one reloaded from storage holds a `string`.
76
+ - Both must be handled on read.
77
+ - Because of this, and because `null` is a valid value distinct from "not a Date/string", consumers
78
+ must never narrow with `=== null` (or `!== null`) alone - use `??`/`== null` so both `null` and
79
+ `undefined` are treated consistently.
80
+
81
+ ### Last-stop delay bookkeeping: `lastPositionLastStop`
82
+
83
+ - `context.lastPositionLastStop` holds `{ sequence, arrival_delay, departure_delay }` for the last
84
+ stop the trip was at.
85
+ - `TripContextHelper.resetLastStopDelay` clears all three fields to `null` together.
86
+ - `TripContextHelper.updateLastStopSequenceIfUnset` only writes `sequence` when it is currently
87
+ `null` - it never overwrites an already-set sequence.
88
+ - `TripContextHelper.setLastStopArrivalDelay`/`setLastStopDepartureDelay` are verbatim
89
+ pass-throughs: `undefined` must remain `undefined` (dropped by `JSON.stringify`) rather than
90
+ being coerced to `null`, since that would change the persisted bytes.
91
+
92
+ ### Asymmetric clear: `atStopStreak`
93
+
94
+ - `context.atStopStreak` holds `{ stop_sequence, firstPositionTimestamp, firstPositionDelay }`,
95
+ tracking how long a trip has stayed at the same stop.
96
+ - `TripContextHelper.clearAtStopStreak` zeroes **only** `stop_sequence` to `null`.
97
+ - `firstPositionTimestamp` and `firstPositionDelay` are intentionally left untouched, persisted
98
+ as-is.
99
+ - Do not assume clearing the streak resets the whole object; check `stop_sequence` specifically
100
+ when deciding whether a streak is active.
101
+
102
+ ## Fallback behavior
103
+
104
+ ### Invalid GPS coordinates: stop-based fallback
105
+
106
+ `BasePositionsManager.resolveTrackingPosition` - guard before `lat`/`lng` feed into `turf.point`.
107
+
108
+ - Trigger: `VPUtils.hasValidCoordinates` fails (null, non-finite, outside `(0, 100)` on either axis).
109
+ - Step 1: `VPUtils.findStopCoordinatesForFallback` - look up `this_stop_id` (preferred) or
110
+ `last_stop_id` in trip's loaded GTFS `stop_times`. Covers: GPS dead, onboard stop-matching
111
+ (CIS/ASW) still correct.
112
+ - Step 2, match found: use stop's coords instead of raw GPS, build `turf` point, run normal
113
+ `getEstimatedPoint`/delay pipeline - real `AT_STOP`/`ON_TRACK` + delay, not frozen stale state.
114
+ Stop's own coords re-checked via `hasValidCoordinates` too - bad GTFS stop data falls through
115
+ to step 3, not trusted.
116
+ - Step 3, no match (no stop id, or id not in trip schedule): `buildInvalidCoordinatesFallback`.
117
+ - `lat`/`lng`: `position.lat`/`lng` re-checked via `hasValidCoordinates` (not plain `??`, since a
118
+ `NaN` from a bad upstream parse is not `null`/`undefined` and would otherwise pass through
119
+ unchanged); only on failure falls back to `context.lastPositionLat`/`Lng`, then `0` as last
120
+ resort.
121
+ - `state_position` from `context.lastPositionState`.
122
+ - `last_stop_id`/`last_stop_sequence`: current position's own fields first
123
+ (`this_stop_sequence ?? last_stop_sequence`), stale `context.lastPositionTracking` snapshot
124
+ only as last resort - avoids sticking at old sequence once GPS recovers.
125
+ - All branches: `state_process = PROCESSED` unconditionally. Why: pre-fix, crash on invalid
126
+ coords left row unprocessed - same bad row re-fetched + re-crashed worker every run (one bad
127
+ GPS event → hundreds of crashes/hour). Unconditional PROCESSED breaks that loop.
128
+ - Shared via base class by `PositionsManager` + `RegionalBusPositionsManager` - don't reimplement
129
+ inline in either subclass.
130
+
131
+ ### Lean tracking shape: `lastPositionTracking`
132
+
133
+ `context.lastPositionTracking` is a GeoJSON `Feature<Point, IVPTripsTrackingProperties>` written by
134
+ `TripContextHelper.recordTracking`, only for positions in `AT_STOP` or `ON_TRACK` state.
135
+ `IVPTripsTrackingProperties` (`VPTripsLastPositionInterfaces.ts`) is a `Pick` limited to exactly the
136
+ 7 fields actually read downstream:
137
+
138
+ - `bearing`
139
+ - `shape_dist_traveled`
140
+ - `tcp_event`
141
+ - `last_stop_sequence`
142
+ - `last_stop_id`
143
+ - `last_stop_arrival_time`
144
+ - `last_stop_departure_time`
145
+
146
+ This replaces a wider legacy shape that carried unused fields. Each field is written as an explicit
147
+ `?? null` literal, so a missing value persists as `null` (kept by `JSON.stringify`) rather than
148
+ `undefined` (dropped) - do not add new fields to this shape without confirming they are actually
149
+ consumed elsewhere.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@golemio/pid",
3
- "version": "5.19.1-dev.2799089619",
3
+ "version": "5.19.1-dev.2815853394",
4
4
  "description": "Golemio PID Module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",