@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.
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/helpers/PositionsMapper.js +10 -4
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/data-access/helpers/PositionsMapper.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.d.ts +30 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.js +73 -53
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/BasePositionsManager.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/DPPUtils.d.ts +2 -2
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js +12 -20
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/PositionsManager.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.d.ts +21 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.js +31 -0
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/VPUtils.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/ComputeDelayHelper.js +35 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/ComputeDelayHelper.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/AbstractDelayAtStop.js +35 -5
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/AbstractDelayAtStop.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/CommonDelayAtStop.js +37 -5
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/CommonDelayAtStop.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/MetroDelayAtStop.js +37 -5
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/compute-positions/strategy/MetroDelayAtStop.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js +12 -20
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/RegionalBusPositionsManager.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/RegionalBusComputeDelayHelper.js +35 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/RegionalBusComputeDelayHelper.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/strategy/BusDelayAtStop.js +37 -5
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/regional-bus/compute-positions/strategy/BusDelayAtStop.js.map +1 -1
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.d.ts +68 -0
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.js +216 -0
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/helpers/trip-context/TripContextHelper.js.map +1 -0
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/abstract/AbstractPropagateDelayTask.js +37 -11
- package/dist/integration-engine/vehicle-positions/workers/vehicle-positions/tasks/abstract/AbstractPropagateDelayTask.js.map +1 -1
- package/dist/schema-definitions/vehicle-positions/models/VPTripsModel.js +22 -10
- package/dist/schema-definitions/vehicle-positions/models/VPTripsModel.js.map +1 -1
- package/dist/schema-definitions/vehicle-positions/models/interfaces/VPTripsLastPositionInterfaces.d.ts +8 -8
- package/docs/asyncapi.yaml +0 -9
- package/docs/cache/types/psql.md +6 -11
- package/docs/processing/index.md +1 -0
- package/docs/processing/state_position_tracking/tcp_dpp_common.md +6 -0
- package/docs/processing/trip_context/index.md +149 -0
- 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.
|