signalk-wakelogger 0.2.0-beta.0

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 (83) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +201 -0
  3. package/README.md +49 -0
  4. package/SECURITY.md +7 -0
  5. package/assets/screenshots/plugin-config.png +0 -0
  6. package/assets/screenshots/plugin-status.png +0 -0
  7. package/assets/wakelogger.svg +6 -0
  8. package/dist/config/defaults.d.ts +18 -0
  9. package/dist/config/defaults.js +30 -0
  10. package/dist/config/defaults.js.map +1 -0
  11. package/dist/config/schema.d.ts +43 -0
  12. package/dist/config/schema.js +47 -0
  13. package/dist/config/schema.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +338 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/outbox/database-outbox.d.ts +25 -0
  18. package/dist/outbox/database-outbox.js +186 -0
  19. package/dist/outbox/database-outbox.js.map +1 -0
  20. package/dist/outbox/database-types.d.ts +19 -0
  21. package/dist/outbox/database-types.js +3 -0
  22. package/dist/outbox/database-types.js.map +1 -0
  23. package/dist/outbox/factory.d.ts +12 -0
  24. package/dist/outbox/factory.js +98 -0
  25. package/dist/outbox/factory.js.map +1 -0
  26. package/dist/outbox/file-outbox.d.ts +27 -0
  27. package/dist/outbox/file-outbox.js +280 -0
  28. package/dist/outbox/file-outbox.js.map +1 -0
  29. package/dist/outbox/interface.d.ts +33 -0
  30. package/dist/outbox/interface.js +3 -0
  31. package/dist/outbox/interface.js.map +1 -0
  32. package/dist/pairing/association-client.d.ts +3 -0
  33. package/dist/pairing/association-client.js +31 -0
  34. package/dist/pairing/association-client.js.map +1 -0
  35. package/dist/pairing/credentials.d.ts +46 -0
  36. package/dist/pairing/credentials.js +168 -0
  37. package/dist/pairing/credentials.js.map +1 -0
  38. package/dist/pairing/pairing-client.d.ts +19 -0
  39. package/dist/pairing/pairing-client.js +102 -0
  40. package/dist/pairing/pairing-client.js.map +1 -0
  41. package/dist/signalk/normaliser.d.ts +11 -0
  42. package/dist/signalk/normaliser.js +119 -0
  43. package/dist/signalk/normaliser.js.map +1 -0
  44. package/dist/signalk/paths.d.ts +2 -0
  45. package/dist/signalk/paths.js +14 -0
  46. package/dist/signalk/paths.js.map +1 -0
  47. package/dist/signalk/subscriber.d.ts +2 -0
  48. package/dist/signalk/subscriber.js +20 -0
  49. package/dist/signalk/subscriber.js.map +1 -0
  50. package/dist/telemetry/profile-store.d.ts +7 -0
  51. package/dist/telemetry/profile-store.js +39 -0
  52. package/dist/telemetry/profile-store.js.map +1 -0
  53. package/dist/telemetry/profile.d.ts +32 -0
  54. package/dist/telemetry/profile.js +94 -0
  55. package/dist/telemetry/profile.js.map +1 -0
  56. package/dist/telemetry/sampler.d.ts +14 -0
  57. package/dist/telemetry/sampler.js +44 -0
  58. package/dist/telemetry/sampler.js.map +1 -0
  59. package/dist/telemetry/types.d.ts +73 -0
  60. package/dist/telemetry/types.js +3 -0
  61. package/dist/telemetry/types.js.map +1 -0
  62. package/dist/transport/adaptive-mode.d.ts +23 -0
  63. package/dist/transport/adaptive-mode.js +63 -0
  64. package/dist/transport/adaptive-mode.js.map +1 -0
  65. package/dist/transport/mqtt-client.d.ts +69 -0
  66. package/dist/transport/mqtt-client.js +365 -0
  67. package/dist/transport/mqtt-client.js.map +1 -0
  68. package/dist/transport/topics.d.ts +10 -0
  69. package/dist/transport/topics.js +13 -0
  70. package/dist/transport/topics.js.map +1 -0
  71. package/dist/trips/state-machine.d.ts +38 -0
  72. package/dist/trips/state-machine.js +118 -0
  73. package/dist/trips/state-machine.js.map +1 -0
  74. package/docs/architecture.md +17 -0
  75. package/docs/development.md +49 -0
  76. package/docs/implementation-plan.md +1943 -0
  77. package/docs/original-plan-gap-audit.md +47 -0
  78. package/docs/pairing.md +17 -0
  79. package/docs/release.md +52 -0
  80. package/docs/telemetry-protocol.md +50 -0
  81. package/docs/trip-detection.md +7 -0
  82. package/docs/validation.md +35 -0
  83. package/package.json +80 -0
@@ -0,0 +1,1943 @@
1
+ # Wake Logger Signal K Plugin — Implementation Plan
2
+
3
+ ## 2026-08-31 refined decisions and implementation status
4
+
5
+ This is the complete original implementation plan recovered from CachyOS, with the following agreed decisions as authoritative amendments. Where an example or undecided option later in this document conflicts with this section, this section wins.
6
+
7
+ ### Scope and ownership
8
+
9
+ - The eventual delivery is end-to-end: this plugin, Wake Logger pairing and device management, Mosquitto, ingestion, current state, provisional trips and private/public UI.
10
+ - This repository owns only live acquisition and resilient transport. Wake Logger owns authorization, entitlements, vessel mapping, derived wind, final trip boundaries and edits. Post-trip archival upload remains a separate system.
11
+ - Trip events from the plugin are advisory evidence. The cloud is authoritative. The first live milestone emits evidence and stores live telemetry; automatic cloud trip refinement is calibrated using real data.
12
+ - The feature uses the existing Race Analytics entitlement. All vessel crew may view private live telemetry read-only. Device management is restricted by Wake Logger's vessel-management policy, and only owners/site administrators control public sharing.
13
+ - Public tracking is owner opt-in, revocable and independently supports unlisted links and directory listing. Production rollout follows isolated validation and explicit approval.
14
+
15
+ ### Representative evidence and protocol v1
16
+
17
+ Representative NMEA/DAT fixtures confirm that protocol v1 can reliably carry:
18
+
19
+ ```text
20
+ lat, lon, capturedAt, receivedAt
21
+ sog_kn, cog_deg
22
+ heading_deg, heading_reference
23
+ depth_m
24
+ aws_kn, awa_deg
25
+ ```
26
+
27
+ Signal K provides speed in m/s and angles in radians; the plugin converts speeds to knots and angles to degrees in `[0,360)`. Depth remains metres. True heading is preferred and magnetic fallback is labelled. Wake Logger continues deriving `tws_kn`, `twd_deg`, VMG, tack, supported speed and calculation quality rather than trusting incoming true-wind frames.
28
+
29
+ Regression fixtures cover invalid historical time anchors, out-of-range depth sentinels, non-finite values and timed-out sensors. Rate of turn, attitude, GNSS diagnostics, water temperature, speed through water, engine, electrical and tanks are outside the current telemetry profile.
30
+
31
+ Each sample receives a persistent monotonic sequence before its durable append. Identity and deduplication use `device_id + sequence`, never `vessel_id + sequence`. The authenticated device maps to its vessel server-side and a payload vessel ID is not trusted. A batch may declare `droppedThrough` to explicitly close a device-side retention/recovery gap.
32
+
33
+ ### Pairing and MQTT contract
34
+
35
+ - Public pairing uses the Wake Logger HTTPS endpoint configured by the plugin.
36
+ - Non-production overrides remain local and are never committed.
37
+ - Request: `{ "code": "...", "name": "Signal K ..." }`.
38
+ - Response: `{ "device": { "id": "..." }, "credentials": { "broker_host": "...", "broker_port": 8883, "tls": true, "client_id": "...", "username": "...", "password": "...", "telemetry_profile": {}, "association_status_url": "https://...", "association_token": "..." } }`.
39
+ - Topics: `wakelogger/v1/devices/<device-id>/{telemetry,state,status,events,ack,profile,profile-ack}`.
40
+ - Cloud acknowledgement: `{ "v": 1, "deviceId": "...", "ackSequence": 123, "acknowledgedAt": 1788143912200 }`.
41
+
42
+ Use MQTT 5 and QoS 1. The state and status topics are retained; telemetry and events are not. Current state publishes before ordered backlog. Broker acknowledgement alone never removes a record: the application acknowledgement follows Wake Logger's durable commit. Live and backlog duplicates are harmless under the device/sequence uniqueness constraint.
43
+
44
+ The broker uses one credential per device, required client-ID binding, default-deny ACLs and access only to that device namespace. Endpoint and certificate topology are cloud-owned and returned during pairing rather than documented here. Require TLS 1.2+, hostname validation and no insecure bypass.
45
+
46
+ ### Selected implementation defaults
47
+
48
+ - Keep `OutboxStore` as the boundary. Prefer Signal K's emerging plugin-scoped Database API as a bounded delivery buffer when available, with the native-free segmented file outbox under `app.getDataDirPath()` as the portable fallback. SQLite is not shipped.
49
+ - Persist the backend selection per device. Never silently fall back from database to files because that could reuse a sequence; retain legacy files and select the database only after their pending queue is empty.
50
+ - Keep an independent outbox/sequence space per device ID. Pairing a replacement preserves the retired device's queue locally but never republishes those records under the new authenticated identity.
51
+ - Retry temporary pairing failures at most six times with bounded exponential delays; reject invalid/expired codes immediately and retain the current credential if replacement provisioning fails.
52
+ - Confirm broker revocation through a device-scoped outbound HTTPS status credential and expose `Device revoked — enter a new pairing code`. A local admin-only forget action removes credentials but preserves the consumed-code tombstone, retired outboxes and sequence records.
53
+ - Records are length-prefixed, SHA-256 checksummed and append-only, with synced appends and atomic metadata. Corrupt/incomplete tails are truncated during recovery.
54
+ - Defaults are 4 MiB segments, seven-day/250 MB retention, one-second live samples, batches up to 60 samples and a 64 KiB payload ceiling.
55
+ - Preserve newest data at a limit, report count/range of dropped samples and never crash Signal K. Restore retained current state from the outbox after restart.
56
+ - Start and stop remain safe/idempotent with empty configuration, no credentials, no DNS and no internet. Reconnect uses capped exponential backoff with jitter; authentication failures retain their distinct status and retry every five minutes with jitter so entitlement restoration recovers automatically.
57
+ - The plugin emits start/stop evidence using stable berth-cluster movement, not a moving origin, so slow marina departures are detected. MQTT disconnects never end a tracking session.
58
+
59
+ ### Milestones
60
+
61
+ Version 0.2 beta implements the plugin foundation, supported-field normalization, database-preferred durable outbox, pairing contract, MQTT transport, application acknowledgements, private trip evidence, remote telemetry profiles, adaptive transport, expanded status, tests, CI and documentation. Wake Logger cloud/broker/API/UI delivery is implemented in the private Wake Logger repository. Automated CI, packaging and registry preparation gate npm beta publication. Target-hardware multi-day/ARM, real-vessel and measured resource evidence remain separate first-vessel and stable-production gates; the published beta is used to collect them. Remaining evidence is recorded in `original-plan-gap-audit.md`.
62
+
63
+ ## 1. Purpose
64
+
65
+ Build a production-quality Signal K plugin that allows a vessel running Signal K to stream live telemetry securely and efficiently to Wake Logger.
66
+
67
+ The plugin will be distributed through the normal Signal K plugin ecosystem and should ultimately be installable from the Signal K AppStore.
68
+
69
+ The plugin is responsible only for **live vessel tracking and resilient live telemetry transport**.
70
+
71
+ It is **not responsible for post-trip or post-race data uploads**. Any separate full-resolution archival upload process is outside this repository and must remain architecturally separate.
72
+
73
+ The plugin must support worldwide vessel tracking and should not contain assumptions tied to a single country, jurisdiction, qualification system, race organisation or regulator.
74
+
75
+ ---
76
+
77
+ # 2. Primary design goals
78
+
79
+ The plugin must:
80
+
81
+ 1. Read selected live data from the local Signal K server.
82
+ 2. Convert that data into the Wake Logger live telemetry schema.
83
+ 3. Efficiently batch telemetry to minimise bandwidth.
84
+ 4. Maintain a durable local outbound queue.
85
+ 5. Continue operating while internet connectivity is unavailable.
86
+ 6. Automatically reconnect when connectivity returns.
87
+ 7. Prioritise current live state after reconnecting.
88
+ 8. Drain queued historical live telemetry without overwhelming the available connection.
89
+ 9. Publish telemetry over MQTT using TLS.
90
+ 10. Use MQTT QoS 1.
91
+ 11. prevent duplicate telemetry in Wake Logger through sequence numbers.
92
+ 12. Support tracking sessions lasting minutes, hours, days or longer.
93
+ 13. Detect probable trip start and trip end events.
94
+ 14. Allow the Wake Logger cloud service to provision vessel credentials through a pairing process.
95
+ 15. Require no inbound internet connection to the vessel.
96
+ 16. Start safely even when Wake Logger credentials or internet connectivity are unavailable.
97
+ 17. Be compatible with supported Signal K platforms, particularly Raspberry Pi/ARM installations.
98
+ 18. Meet Signal K plugin registry and CI expectations.
99
+ 19. Be fully testable without access to a real vessel.
100
+ 20. Avoid unnecessary dependencies, particularly architecture-specific native dependencies.
101
+
102
+ ---
103
+
104
+ # 3. High-level architecture
105
+
106
+ ```text
107
+ NMEA 2000 / NMEA 0183 / other vessel sources
108
+ │
109
+ ▼
110
+ Signal K Server
111
+ │
112
+ ▼
113
+ signalk-wakelogger
114
+ │
115
+ ┌─────────┴─────────┐
116
+ │ │
117
+ ▼ ▼
118
+ Signal K subscriber Trip state machine
119
+ │
120
+ ▼
121
+ Telemetry normaliser
122
+ │
123
+ ▼
124
+ Batcher
125
+ │
126
+ ▼
127
+ Durable local outbox
128
+ │
129
+ ▼
130
+ MQTT transport
131
+ │
132
+ TLS / QoS 1
133
+ │
134
+ ▼
135
+ Internet
136
+ │
137
+ ▼
138
+ Wake Logger MQTT broker
139
+ │
140
+ ▼
141
+ Telemetry ingestion service
142
+ │
143
+ ┌────┴──────────────┐
144
+ ▼ ▼
145
+ Current vessel state Historical live telemetry
146
+ ```
147
+
148
+ ---
149
+
150
+ # 4. Architectural boundaries
151
+
152
+ ## Plugin responsibilities
153
+
154
+ The plugin owns:
155
+
156
+ - Signal K subscriptions
157
+ - telemetry sampling
158
+ - telemetry normalisation
159
+ - telemetry batching
160
+ - local sequence numbering
161
+ - local persistent buffering
162
+ - MQTT connectivity
163
+ - TLS transport
164
+ - pairing
165
+ - credential storage
166
+ - connection health
167
+ - trip-state detection
168
+ - transmission retry behaviour
169
+ - live telemetry backlog recovery
170
+ - diagnostic status reporting
171
+
172
+ ## Wake Logger cloud responsibilities
173
+
174
+ The cloud owns:
175
+
176
+ - user accounts
177
+ - vessel ownership
178
+ - vessel identities
179
+ - pairing-code generation
180
+ - MQTT credential provisioning
181
+ - MQTT ACLs
182
+ - telemetry validation
183
+ - telemetry deduplication
184
+ - live vessel state
185
+ - historical live telemetry
186
+ - final trip construction
187
+ - trip editing/merging/splitting
188
+ - qualification calculations
189
+ - reporting and analytics
190
+
191
+ The plugin must never attempt to replicate Wake Logger business logic.
192
+
193
+ ---
194
+
195
+ # 5. Technology choices
196
+
197
+ ## Language
198
+
199
+ Use:
200
+
201
+ ```text
202
+ TypeScript
203
+ Node.js
204
+ ```
205
+
206
+ Signal K supports Node.js/TypeScript plugins through its Server API.
207
+
208
+ Use:
209
+
210
+ ```text
211
+ @signalk/server-api
212
+ ```
213
+
214
+ for Signal K types where practical.
215
+
216
+ Signal K currently documents Node.js 20 or later for plugin development.
217
+
218
+ ## MQTT client
219
+
220
+ Preferred library:
221
+
222
+ ```text
223
+ mqtt
224
+ ```
225
+
226
+ MQTT.js supports Node.js, MQTT 5 features and QoS 1.
227
+
228
+ Configure explicitly for MQTT 5 rather than relying on library defaults.
229
+
230
+ ## Durable queue
231
+
232
+ Create a storage abstraction:
233
+
234
+ ```text
235
+ OutboxStore
236
+ ```
237
+
238
+ Do not tightly couple the application architecture to SQLite.
239
+
240
+ Initial implementation should prioritise portability across:
241
+
242
+ - Linux x64
243
+ - Linux ARM64
244
+ - ARMv7
245
+ - Raspberry Pi
246
+ - Signal K Docker deployments
247
+ - Cerbo GX where practical
248
+
249
+ Signal K plugin testing installs packages with lifecycle scripts disabled, and native Node modules can create cross-platform packaging issues.
250
+
251
+ The implementation uses two replaceable approaches:
252
+
253
+ ### Option A — Signal K Database API
254
+
255
+ Preferred when the server exposes the emerging plugin-scoped API. Use it only as a bounded write-ahead delivery queue, not as a competing history or Track API.
256
+
257
+ ### Option B — file-backed append-only queue
258
+
259
+ Portable fallback.
260
+
261
+ Use:
262
+
263
+ ```text
264
+ segmented append-only files
265
+ +
266
+ persistent acknowledgement cursor
267
+ +
268
+ atomic metadata files
269
+ ```
270
+
271
+ Advantages:
272
+
273
+ - no native dependencies
274
+ - portable
275
+ - easy to inspect
276
+ - robust on Raspberry Pi
277
+ - simple recovery
278
+ - predictable disk usage
279
+
280
+ Do not ship a native SQLite dependency. The rest of the application interacts only through `OutboxStore`, keeping storage replaceable as Signal K's API evolves.
281
+
282
+ ---
283
+
284
+ # 6. Proposed repository structure
285
+
286
+ ```text
287
+ signalk-wakelogger/
288
+ │
289
+ ├── src/
290
+ │ ├── index.ts
291
+ │ │
292
+ │ ├── config/
293
+ │ │ ├── schema.ts
294
+ │ │ └── defaults.ts
295
+ │ │
296
+ │ ├── signalk/
297
+ │ │ ├── subscriber.ts
298
+ │ │ ├── paths.ts
299
+ │ │ └── normaliser.ts
300
+ │ │
301
+ │ ├── telemetry/
302
+ │ │ ├── types.ts
303
+ │ │ ├── batcher.ts
304
+ │ │ ├── sampler.ts
305
+ │ │ └── encoder.ts
306
+ │ │
307
+ │ ├── transport/
308
+ │ │ ├── mqtt-client.ts
309
+ │ │ ├── reconnect.ts
310
+ │ │ └── connection-state.ts
311
+ │ │
312
+ │ ├── outbox/
313
+ │ │ ├── interface.ts
314
+ │ │ ├── file-outbox.ts
315
+ │ │ └── recovery.ts
316
+ │ │
317
+ │ ├── pairing/
318
+ │ │ ├── pairing-client.ts
319
+ │ │ ├── credentials.ts
320
+ │ │ └── identity.ts
321
+ │ │
322
+ │ ├── trips/
323
+ │ │ ├── state-machine.ts
324
+ │ │ ├── movement.ts
325
+ │ │ └── types.ts
326
+ │ │
327
+ │ ├── status/
328
+ │ │ └── status.ts
329
+ │ │
330
+ │ └── util/
331
+ │ ├── clock.ts
332
+ │ ├── backoff.ts
333
+ │ └── logger.ts
334
+ │
335
+ ├── test/
336
+ │ ├── unit/
337
+ │ ├── integration/
338
+ │ ├── fixtures/
339
+ │ └── simulated-vessel/
340
+ │
341
+ ├── assets/
342
+ │
343
+ ├── docs/
344
+ │ ├── architecture.md
345
+ │ ├── telemetry-protocol.md
346
+ │ ├── trip-detection.md
347
+ │ ├── pairing.md
348
+ │ └── development.md
349
+ │
350
+ ├── .github/
351
+ │ └── workflows/
352
+ │ ├── ci.yml
353
+ │ ├── signalk-ci.yml
354
+ │ └── publish.yml
355
+ │
356
+ ├── package.json
357
+ ├── tsconfig.json
358
+ ├── README.md
359
+ ├── CHANGELOG.md
360
+ ├── CONTRIBUTING.md
361
+ ├── SECURITY.md
362
+ └── LICENSE
363
+ ```
364
+
365
+ ---
366
+
367
+ # 7. Signal K plugin lifecycle
368
+
369
+ The plugin must implement the standard Signal K plugin lifecycle:
370
+
371
+ ```text
372
+ id
373
+ name
374
+ schema
375
+ start()
376
+ stop()
377
+ ```
378
+
379
+ `start()` must never require a successful internet connection.
380
+
381
+ This is a critical requirement.
382
+
383
+ Valid startup states include:
384
+
385
+ ```text
386
+ Not configured
387
+ Configured but not paired
388
+ Paired but offline
389
+ Paired and connecting
390
+ Connected
391
+ ```
392
+
393
+ For example:
394
+
395
+ ```text
396
+ Signal K starts
397
+ ↓
398
+ Wake Logger plugin starts
399
+ ↓
400
+ No Wake Logger credentials
401
+ ↓
402
+ Plugin status:
403
+ "Not paired"
404
+ ```
405
+
406
+ That is a successful plugin startup.
407
+
408
+ Do not throw an exception because:
409
+
410
+ - DNS fails
411
+ - Wake Logger is unavailable
412
+ - MQTT is unavailable
413
+ - credentials are absent
414
+ - vessel has no internet connection
415
+
416
+ Network connectivity is a runtime state, not a plugin lifecycle requirement.
417
+
418
+ ---
419
+
420
+ # 8. Initial Signal K subscriptions
421
+
422
+ Create a central path definition file rather than scattering Signal K strings throughout the codebase.
423
+
424
+ Initial candidate paths:
425
+
426
+ ```text
427
+ navigation.position
428
+ navigation.speedOverGround
429
+ navigation.courseOverGroundTrue
430
+ navigation.headingTrue
431
+ navigation.headingMagnetic
432
+
433
+ environment.depth.belowTransducer
434
+
435
+ environment.wind.speedApparent
436
+ environment.wind.angleApparent
437
+ ```
438
+
439
+ Not every vessel will provide every path.
440
+
441
+ Missing data must be normal behaviour.
442
+
443
+ Do not require depth or wind information for basic tracking. Engine, battery, fuel and tank data are outside the product scope.
444
+
445
+ Minimum useful tracking dataset:
446
+
447
+ ```text
448
+ position
449
+ timestamp
450
+ ```
451
+
452
+ Preferred:
453
+
454
+ ```text
455
+ position
456
+ SOG
457
+ COG
458
+ heading
459
+ ```
460
+
461
+ ---
462
+
463
+ # 9. Sampling strategy
464
+
465
+ Do not blindly forward every Signal K delta.
466
+
467
+ Implement path-specific sampling.
468
+
469
+ Suggested starting defaults:
470
+
471
+ ```text
472
+ Position 1 Hz
473
+ SOG 1 Hz
474
+ COG 1 Hz
475
+ Heading 1 Hz
476
+ Depth 1 Hz
477
+ Wind 1 Hz
478
+ ```
479
+
480
+ Sampling rates are remotely configurable through an approved, versioned Wake Logger telemetry profile.
481
+
482
+ Changes should still be captured where appropriate even when the normal sampling period has not elapsed.
483
+
484
+ ---
485
+
486
+ # 10. Telemetry batching
487
+
488
+ Do not send one MQTT publication for every Signal K value.
489
+
490
+ Aggregate data into short batches.
491
+
492
+ Initial target:
493
+
494
+ ```text
495
+ 1 batch per second
496
+ ```
497
+
498
+ A batch may contain:
499
+
500
+ ```text
501
+ timestamp
502
+ sequence
503
+ position
504
+ SOG
505
+ COG
506
+ heading
507
+ RPM
508
+ depth
509
+ wind
510
+ other changed values
511
+ ```
512
+
513
+ Target average bandwidth should be comfortably below:
514
+
515
+ ```text
516
+ 1 kB/sec per vessel
517
+ ```
518
+
519
+ before TLS/TCP overhead.
520
+
521
+ Measure actual bandwidth during testing rather than relying on estimates.
522
+
523
+ ---
524
+
525
+ # 11. Telemetry protocol
526
+
527
+ Create a versioned Wake Logger protocol.
528
+
529
+ Example conceptual JSON:
530
+
531
+ ```json
532
+ {
533
+ "v": 1,
534
+ "vesselId": "vsl_xxx",
535
+ "sequence": 184291,
536
+ "capturedAt": 1788143912000,
537
+ "trackingSessionId": "trk_xxx",
538
+ "values": {
539
+ "lat": -27.41238,
540
+ "lon": 153.18291,
541
+ "sog": 6.42,
542
+ "cog": 241.3,
543
+ "heading": 238.8
544
+ }
545
+ }
546
+ ```
547
+
548
+ During early development use JSON.
549
+
550
+ This allows:
551
+
552
+ - packet inspection
553
+ - logging
554
+ - test fixture creation
555
+ - rapid protocol changes
556
+
557
+ Do not optimise prematurely.
558
+
559
+ Create an encoder abstraction so CBOR or another compact binary encoding can be introduced later without rewriting transport logic.
560
+
561
+ ---
562
+
563
+ # 12. Sequence numbers
564
+
565
+ Each vessel installation must maintain a monotonically increasing telemetry sequence.
566
+
567
+ Sequence numbers survive:
568
+
569
+ ```text
570
+ plugin restart
571
+ Signal K restart
572
+ Pi reboot
573
+ MQTT reconnect
574
+ internet outage
575
+ ```
576
+
577
+ Example:
578
+
579
+ ```text
580
+ 392001
581
+ 392002
582
+ 392003
583
+ ...
584
+ ```
585
+
586
+ Wake Logger backend should enforce conceptual uniqueness on:
587
+
588
+ ```text
589
+ vessel_id + sequence
590
+ ```
591
+
592
+ This makes MQTT QoS 1 duplicate delivery harmless.
593
+
594
+ The sequence must be assigned before the telemetry item enters the durable outbox.
595
+
596
+ ---
597
+
598
+ # 13. Persistent outbox
599
+
600
+ Data flow:
601
+
602
+ ```text
603
+ Telemetry created
604
+ ↓
605
+ Sequence assigned
606
+ ↓
607
+ Written durably to OutboxStore
608
+ ↓
609
+ MQTT publish QoS 1
610
+ ↓
611
+ Publish acknowledged
612
+ ↓
613
+ Outbox item marked delivered
614
+ ↓
615
+ Storage reclaimed later
616
+ ```
617
+
618
+ Never use:
619
+
620
+ ```text
621
+ create telemetry
622
+ → publish
623
+ → save only if publish fails
624
+ ```
625
+
626
+ because a crash between creation and publishing could lose data.
627
+
628
+ Persist first.
629
+
630
+ Transmit second.
631
+
632
+ ---
633
+
634
+ # 14. Outbox retention
635
+
636
+ The queue must have configurable limits.
637
+
638
+ Suggested initial limits:
639
+
640
+ ```text
641
+ Maximum age: 7 days
642
+ Maximum disk use: configurable
643
+ Default disk use: 250 MB
644
+ ```
645
+
646
+ Actual limits should be tuned after measuring real data volumes.
647
+
648
+ When limits are reached:
649
+
650
+ 1. Never crash Signal K.
651
+ 2. Preserve the newest data.
652
+ 3. Emit a visible warning.
653
+ 4. Record dropped-data metrics.
654
+ 5. Remove oldest backlog according to policy.
655
+
656
+ ---
657
+
658
+ # 15. MQTT transport
659
+
660
+ Use:
661
+
662
+ ```text
663
+ MQTT 5
664
+ TLS
665
+ QoS 1
666
+ ```
667
+
668
+ Initial endpoint concept:
669
+
670
+ ```text
671
+ mqtt.wakelogger.com:8883
672
+ ```
673
+
674
+ Topic structure:
675
+
676
+ ```text
677
+ wakelogger/v1/vessels/<vessel-id>/telemetry
678
+ wakelogger/v1/vessels/<vessel-id>/status
679
+ ```
680
+
681
+ Potential future topic:
682
+
683
+ ```text
684
+ wakelogger/v1/vessels/<vessel-id>/control
685
+ ```
686
+
687
+ Do not create a separate MQTT topic for every Signal K path.
688
+
689
+ ---
690
+
691
+ # 16. MQTT connection behaviour
692
+
693
+ Implement:
694
+
695
+ ```text
696
+ exponential reconnect backoff
697
+ +
698
+ jitter
699
+ +
700
+ upper reconnect limit
701
+ ```
702
+
703
+ Example conceptual sequence:
704
+
705
+ ```text
706
+ 1 sec
707
+ 2 sec
708
+ 4 sec
709
+ 8 sec
710
+ 15 sec
711
+ 30 sec
712
+ 60 sec
713
+ ```
714
+
715
+ Avoid synchronised fleet reconnect storms after a server outage.
716
+
717
+ MQTT connectivity must expose states such as:
718
+
719
+ ```text
720
+ disabled
721
+ unpaired
722
+ offline
723
+ connecting
724
+ online
725
+ degraded
726
+ ```
727
+
728
+ ---
729
+
730
+ # 17. Reconnection priorities
731
+
732
+ When connectivity returns after a substantial outage:
733
+
734
+ ## Priority 1
735
+
736
+ Publish current vessel state immediately.
737
+
738
+ ## Priority 2
739
+
740
+ Continue publishing new live telemetry.
741
+
742
+ ## Priority 3
743
+
744
+ Drain historical live backlog.
745
+
746
+ Do not make users wait for hours of queued telemetry before Wake Logger receives the vessel's current location.
747
+
748
+ Backlog draining must be rate limited.
749
+
750
+ Example:
751
+
752
+ ```text
753
+ live traffic always has priority
754
+
755
+ unused capacity
756
+ ↓
757
+ backlog replay
758
+ ```
759
+
760
+ ---
761
+
762
+ # 18. Poor connectivity behaviour
763
+
764
+ The plugin should recognise degraded transport.
765
+
766
+ Potential signals:
767
+
768
+ ```text
769
+ connection resets
770
+ slow publish acknowledgements
771
+ frequent reconnects
772
+ growing outbox depth
773
+ ```
774
+
775
+ Introduce transport states:
776
+
777
+ ```text
778
+ NORMAL
779
+ CONSTRAINED
780
+ OFFLINE
781
+ ```
782
+
783
+ Under constrained connectivity, reduce lower-priority telemetry rates before reducing essential navigation tracking.
784
+
785
+ Priority order:
786
+
787
+ ```text
788
+ 1. Position
789
+ 2. SOG
790
+ 3. COG
791
+ 4. Heading
792
+ 5. Depth
793
+ 6. Apparent wind
794
+ ```
795
+
796
+ Do not implement complicated adaptation until basic reliable transport is working.
797
+
798
+ ---
799
+
800
+ # 19. Pairing architecture
801
+
802
+ A user should not manually configure MQTT credentials.
803
+
804
+ Desired workflow:
805
+
806
+ ```text
807
+ Install Wake Logger plugin
808
+ ↓
809
+ Open Signal K Plugin Config
810
+ ↓
811
+ Enter Wake Logger pairing code
812
+ ↓
813
+ Plugin calls Wake Logger pairing API
814
+ ↓
815
+ Wake Logger validates code
816
+ ↓
817
+ Plugin receives vessel identity
818
+ and scoped credentials
819
+ ↓
820
+ Plugin stores credentials locally
821
+ ↓
822
+ MQTT connection begins
823
+ ```
824
+
825
+ Pairing codes should:
826
+
827
+ ```text
828
+ be short lived
829
+ be single use
830
+ be bound to an authorised Wake Logger account
831
+ ```
832
+
833
+ The provisioning API may return:
834
+
835
+ ```text
836
+ vesselId
837
+ clientId
838
+ MQTT host
839
+ MQTT port
840
+ credential/certificate
841
+ allowed protocol version
842
+ telemetry profile
843
+ association status URL and scoped token
844
+ ```
845
+
846
+ Temporary network, rate-limit and server failures are retried a bounded number of times while the code remains valid. Invalid or expired codes stop immediately. Replacement must be transactional: the old device remains active until new broker provisioning succeeds.
847
+
848
+ Wake Logger Owners/First Mates and site administrators can revoke an association without deleting telemetry history. The plugin confirms revocation through its device-scoped status endpoint and reports a specific status. A Signal K administrator can forget the local credential without deleting retired outboxes or sequence evidence, then enter a new pairing code.
849
+
850
+ Never place production credentials in source code.
851
+
852
+ ---
853
+
854
+ # 20. MQTT authorisation
855
+
856
+ Each vessel must have unique credentials.
857
+
858
+ Broker permissions should restrict a vessel to its own namespace.
859
+
860
+ For vessel:
861
+
862
+ ```text
863
+ vsl_123
864
+ ```
865
+
866
+ allow:
867
+
868
+ ```text
869
+ wakelogger/v1/vessels/vsl_123/*
870
+ ```
871
+
872
+ deny publishing into another vessel namespace.
873
+
874
+ Credential revocation must be possible from Wake Logger.
875
+
876
+ ---
877
+
878
+ # 21. Tracking sessions
879
+
880
+ Tracking sessions must be completely independent of MQTT connections.
881
+
882
+ A tracking session may last:
883
+
884
+ ```text
885
+ minutes
886
+ hours
887
+ days
888
+ weeks
889
+ ```
890
+
891
+ A vessel may reconnect to MQTT many times during one tracking session.
892
+
893
+ Example:
894
+
895
+ ```text
896
+ Tracking session
897
+ ──────────────────────────────────────────
898
+
899
+ MQTT #1 ───────X
900
+
901
+ MQTT #2 ───X
902
+
903
+ MQTT #3 ─────────
904
+
905
+ Same tracking session throughout.
906
+ ```
907
+
908
+ Never end a tracking session because:
909
+
910
+ ```text
911
+ MQTT disconnects
912
+ internet disappears
913
+ Signal K temporarily loses a sensor
914
+ ```
915
+
916
+ ---
917
+
918
+ # 22. Trip detection
919
+
920
+ Implement a local state machine:
921
+
922
+ ```text
923
+ STOPPED
924
+ ↓
925
+ START_CANDIDATE
926
+ ↓
927
+ MOVING
928
+ ↓
929
+ STOP_CANDIDATE
930
+ ↓
931
+ STOPPED
932
+ ```
933
+
934
+ Initial proposed thresholds:
935
+
936
+ ## Start candidate
937
+
938
+ Either:
939
+
940
+ ```text
941
+ SOG > 1.5 knots
942
+ ```
943
+
944
+ or:
945
+
946
+ ```text
947
+ movement > 200 metres from stationary cluster
948
+ ```
949
+
950
+ maintained for approximately:
951
+
952
+ ```text
953
+ 2 minutes
954
+ ```
955
+
956
+ When confirmed, backdate the trip start to the first credible movement.
957
+
958
+ ## Stop candidate
959
+
960
+ Require:
961
+
962
+ ```text
963
+ SOG < 0.5 knots
964
+ ```
965
+
966
+ and:
967
+
968
+ ```text
969
+ positions remain within approximately 75 metres
970
+ ```
971
+
972
+ for:
973
+
974
+ ```text
975
+ 15 minutes
976
+ ```
977
+
978
+ When confirmed, backdate the end to the beginning of the genuine stationary period.
979
+
980
+ These values are starting hypotheses only.
981
+
982
+ They must be tuned using real vessel data.
983
+
984
+ ---
985
+
986
+ # 23. Trip evidence
987
+
988
+ Trip events should record why the state machine changed.
989
+
990
+ Example:
991
+
992
+ ```json
993
+ {
994
+ "event": "trip_started",
995
+ "effectiveAt": 1788143912000,
996
+ "reason": {
997
+ "distanceMovedMetres": 236,
998
+ "movementDurationSeconds": 132,
999
+ "sogThresholdExceeded": true
1000
+ }
1001
+ }
1002
+ ```
1003
+
1004
+ This allows Wake Logger to:
1005
+
1006
+ - audit automatic detection
1007
+ - improve algorithms
1008
+ - explain boundaries
1009
+ - correct incorrect trips
1010
+ - tune thresholds
1011
+
1012
+ ---
1013
+
1014
+ # 24. Engine information
1015
+
1016
+ Engine state is not subscribed or transmitted. GPS movement is the universal source, which also keeps engine-off sailing valid.
1017
+
1018
+ ---
1019
+
1020
+ # 25. Time handling
1021
+
1022
+ Internally use:
1023
+
1024
+ ```text
1025
+ UTC
1026
+ ```
1027
+
1028
+ for all timestamps.
1029
+
1030
+ Never use local wall-clock time as the canonical trip timeline.
1031
+
1032
+ The UI may present local vessel/user time later.
1033
+
1034
+ Store source timestamps when supplied by Signal K.
1035
+
1036
+ Also retain local receipt time where useful for diagnosing delays.
1037
+
1038
+ ---
1039
+
1040
+ # 26. Plugin status
1041
+
1042
+ The Signal K Admin UI should expose meaningful status.
1043
+
1044
+ Examples:
1045
+
1046
+ ```text
1047
+ Wake Logger: Not paired
1048
+ Wake Logger: Connecting
1049
+ Wake Logger: Connected
1050
+ Wake Logger: Offline — 327 queued messages
1051
+ Wake Logger: Connected — replaying backlog
1052
+ Wake Logger: Authentication failed
1053
+ ```
1054
+
1055
+ Useful metrics:
1056
+
1057
+ ```text
1058
+ connection state
1059
+ last successful publish
1060
+ queue message count
1061
+ queue disk size
1062
+ oldest queued message age
1063
+ current sequence
1064
+ tracking state
1065
+ last position timestamp
1066
+ ```
1067
+
1068
+ Never expose secrets in logs or status text.
1069
+
1070
+ ---
1071
+
1072
+ # 27. Testing strategy
1073
+
1074
+ Testing is a first-class requirement.
1075
+
1076
+ ## Unit tests
1077
+
1078
+ Cover:
1079
+
1080
+ ```text
1081
+ telemetry sampling
1082
+ telemetry batching
1083
+ sequence generation
1084
+ outbox persistence
1085
+ outbox recovery
1086
+ MQTT retry logic
1087
+ trip state transitions
1088
+ movement calculations
1089
+ configuration validation
1090
+ protocol encoding
1091
+ credential handling
1092
+ ```
1093
+
1094
+ ## Crash tests
1095
+
1096
+ Simulate:
1097
+
1098
+ ```text
1099
+ process dies after queue write
1100
+ process dies during transmission
1101
+ Signal K restart
1102
+ machine reboot
1103
+ partially written queue segment
1104
+ ```
1105
+
1106
+ Data must recover safely.
1107
+
1108
+ ## Network tests
1109
+
1110
+ Simulate:
1111
+
1112
+ ```text
1113
+ DNS failure
1114
+ broker unavailable
1115
+ TLS failure
1116
+ connection reset
1117
+ 30-second outage
1118
+ 30-minute outage
1119
+ 24-hour outage
1120
+ very slow connection
1121
+ duplicate MQTT delivery
1122
+ out-of-order backlog arrival
1123
+ ```
1124
+
1125
+ ## Vessel simulation
1126
+
1127
+ Create reusable fixtures covering:
1128
+
1129
+ ```text
1130
+ stationary at berth
1131
+ GPS drift at berth
1132
+ slow marina departure
1133
+ normal motor trip
1134
+ sailing trip with engine off
1135
+ brief stop
1136
+ anchoring
1137
+ return to berth
1138
+ poor GPS
1139
+ long tracking session
1140
+ ```
1141
+
1142
+ ---
1143
+
1144
+ # 28. Signal K development testing
1145
+
1146
+ Agents should maintain a local Signal K development environment.
1147
+
1148
+ Signal K provides sample NMEA 2000 data for plugin development.
1149
+
1150
+ The plugin should also be linkable into a development server using `npm link`.
1151
+
1152
+ No agent should require access to the real vessel for routine development.
1153
+
1154
+ Hardware testing happens only after simulation passes.
1155
+
1156
+ ---
1157
+
1158
+ # 29. Continuous integration
1159
+
1160
+ Create normal project CI:
1161
+
1162
+ ```text
1163
+ lint
1164
+ typecheck
1165
+ unit tests
1166
+ build
1167
+ npm audit
1168
+ ```
1169
+
1170
+ Also use Signal K's reusable plugin CI workflow.
1171
+
1172
+ The Signal K workflow validates plugin behaviour across supported environments including multiple architectures.
1173
+
1174
+ The repository should not merge changes to `main` if:
1175
+
1176
+ ```text
1177
+ build fails
1178
+ tests fail
1179
+ Signal K plugin CI fails
1180
+ ```
1181
+
1182
+ ---
1183
+
1184
+ # 30. Signal K registry compatibility
1185
+
1186
+ The plugin should target a full Signal K registry quality score.
1187
+
1188
+ Registry tests currently evaluate areas including:
1189
+
1190
+ ```text
1191
+ installation
1192
+ plugin loading
1193
+ activation
1194
+ configuration schema
1195
+ automated tests
1196
+ npm security audit
1197
+ changelog
1198
+ screenshots
1199
+ core dependency freshness
1200
+ ```
1201
+
1202
+ Important:
1203
+
1204
+ The registry executes plugin code in a restricted environment with no network access.
1205
+
1206
+ Therefore:
1207
+
1208
+ ```text
1209
+ start()
1210
+ ```
1211
+
1212
+ must operate successfully when the Wake Logger cloud service cannot be reached.
1213
+
1214
+ ---
1215
+
1216
+ # 31. Dependency policy
1217
+
1218
+ Keep runtime dependencies minimal.
1219
+
1220
+ Before adding a dependency, agents should check:
1221
+
1222
+ ```text
1223
+ Is it maintained?
1224
+ Does it work on ARM?
1225
+ Does it require postinstall scripts?
1226
+ Does it compile native code?
1227
+ Does it materially improve the product?
1228
+ Can Node.js already do this?
1229
+ ```
1230
+
1231
+ Avoid native modules unless there is a strong reason.
1232
+
1233
+ Do not tightly pin Signal K core dependencies in ways that unnecessarily block current same-major releases.
1234
+
1235
+ ---
1236
+
1237
+ # 32. Security requirements
1238
+
1239
+ Never log:
1240
+
1241
+ ```text
1242
+ passwords
1243
+ private keys
1244
+ access tokens
1245
+ pairing secrets
1246
+ full credentials
1247
+ ```
1248
+
1249
+ Use TLS certificate validation.
1250
+
1251
+ Do not allow:
1252
+
1253
+ ```text
1254
+ rejectUnauthorized: false
1255
+ ```
1256
+
1257
+ in production.
1258
+
1259
+ Validate data received from pairing APIs.
1260
+
1261
+ Validate plugin configuration.
1262
+
1263
+ Use bounded inputs.
1264
+
1265
+ Ensure telemetry payload size is bounded.
1266
+
1267
+ Include:
1268
+
1269
+ ```text
1270
+ SECURITY.md
1271
+ ```
1272
+
1273
+ with a vulnerability reporting process before public release.
1274
+
1275
+ ---
1276
+
1277
+ # 33. Logging
1278
+
1279
+ Use Signal K's plugin logging facilities.
1280
+
1281
+ Log levels should conceptually include:
1282
+
1283
+ ```text
1284
+ status
1285
+ debug
1286
+ warning
1287
+ error
1288
+ ```
1289
+
1290
+ Normal operation must not produce excessive logs.
1291
+
1292
+ Avoid per-second telemetry logging except in explicit debug mode.
1293
+
1294
+ ---
1295
+
1296
+ # 34. Documentation
1297
+
1298
+ Before first public beta the repository must contain:
1299
+
1300
+ ## README
1301
+
1302
+ Cover:
1303
+
1304
+ ```text
1305
+ What Wake Logger is
1306
+ What the plugin does
1307
+ Requirements
1308
+ Installation
1309
+ Pairing
1310
+ How live telemetry works
1311
+ Offline behaviour
1312
+ Privacy/data transmitted
1313
+ Troubleshooting
1314
+ Development
1315
+ ```
1316
+
1317
+ ## architecture.md
1318
+
1319
+ Explain component boundaries.
1320
+
1321
+ ## telemetry-protocol.md
1322
+
1323
+ Document every protocol version and field.
1324
+
1325
+ ## trip-detection.md
1326
+
1327
+ Document state machine and thresholds.
1328
+
1329
+ ## development.md
1330
+
1331
+ Explain:
1332
+
1333
+ ```text
1334
+ npm install
1335
+ build
1336
+ test
1337
+ npm link
1338
+ Signal K development setup
1339
+ sample data
1340
+ ```
1341
+
1342
+ ---
1343
+
1344
+ # 35. Versioning
1345
+
1346
+ Use semantic versioning.
1347
+
1348
+ Suggested milestones:
1349
+
1350
+ ```text
1351
+ 0.1.0 Signal K subscription prototype
1352
+ 0.2.0 MQTT transmission
1353
+ 0.3.0 durable offline queue
1354
+ 0.4.0 Wake Logger pairing
1355
+ 0.5.0 trip detection
1356
+ 0.6.0 first vessel beta
1357
+ 0.9.0 public release candidate
1358
+ 1.0.0 production release
1359
+ ```
1360
+
1361
+ Do not treat these as mandatory release numbers if implementation order changes.
1362
+
1363
+ ---
1364
+
1365
+ # 36. Publishing
1366
+
1367
+ Eventually publish as an npm package containing:
1368
+
1369
+ ```text
1370
+ signalk-node-server-plugin
1371
+ ```
1372
+
1373
+ in its package keywords.
1374
+
1375
+ Add appropriate Signal K AppStore metadata including:
1376
+
1377
+ ```text
1378
+ display name
1379
+ icon
1380
+ screenshots
1381
+ description
1382
+ ```
1383
+
1384
+ Use GitHub Actions to publish releases.
1385
+
1386
+ Prefer npm trusted publishing/OIDC over long-lived npm publishing tokens.
1387
+
1388
+ Do not manually publish production releases from developer machines.
1389
+
1390
+ ---
1391
+
1392
+ # 37. Agent workstreams
1393
+
1394
+ The following workstreams can proceed in parallel after the initial contracts are agreed.
1395
+
1396
+ ---
1397
+
1398
+ ## EPIC 1 — Repository foundation
1399
+
1400
+ ### Agent tasks
1401
+
1402
+ - initialise TypeScript configuration
1403
+ - define linting
1404
+ - define test runner
1405
+ - establish directory structure
1406
+ - add Signal K plugin entry point
1407
+ - add package metadata
1408
+ - implement empty configuration schema
1409
+ - add standard CI
1410
+ - add Signal K CI
1411
+ - add README skeleton
1412
+ - add CHANGELOG
1413
+ - add licence
1414
+ - add SECURITY.md
1415
+
1416
+ ### Acceptance criteria
1417
+
1418
+ ```text
1419
+ npm ci
1420
+ npm run build
1421
+ npm test
1422
+ ```
1423
+
1424
+ all succeed.
1425
+
1426
+ Plugin loads in Signal K.
1427
+
1428
+ Plugin starts without configuration.
1429
+
1430
+ Signal K CI passes.
1431
+
1432
+ ---
1433
+
1434
+ ## EPIC 2 — Signal K data acquisition
1435
+
1436
+ ### Agent tasks
1437
+
1438
+ - implement subscription manager wrapper
1439
+ - centralise Signal K paths
1440
+ - capture timestamps
1441
+ - normalise vessel navigation values
1442
+ - implement path-specific sampling
1443
+ - handle missing paths cleanly
1444
+ - build sample-data tests
1445
+
1446
+ ### Acceptance criteria
1447
+
1448
+ Given simulated Signal K deltas, the plugin produces deterministic normalised telemetry.
1449
+
1450
+ No network connectivity is required.
1451
+
1452
+ ---
1453
+
1454
+ ## EPIC 3 — Telemetry protocol
1455
+
1456
+ ### Agent tasks
1457
+
1458
+ - define protocol v1
1459
+ - define telemetry types
1460
+ - define sequence behaviour
1461
+ - implement JSON encoder
1462
+ - document protocol
1463
+ - write compatibility tests
1464
+
1465
+ ### Acceptance criteria
1466
+
1467
+ The same input always generates schema-valid protocol output.
1468
+
1469
+ Protocol versioning is explicit.
1470
+
1471
+ ---
1472
+
1473
+ ## EPIC 4 — Persistent outbox
1474
+
1475
+ ### Agent tasks
1476
+
1477
+ - define `OutboxStore`
1478
+ - implement file-backed queue
1479
+ - add atomic writes
1480
+ - implement acknowledgement cursor
1481
+ - implement queue recovery
1482
+ - implement disk limits
1483
+ - expose queue statistics
1484
+ - implement crash/restart tests
1485
+
1486
+ ### Acceptance criteria
1487
+
1488
+ A simulated process restart loses no acknowledged or unacknowledged state beyond clearly documented guarantees.
1489
+
1490
+ Queue survives reboot/restart.
1491
+
1492
+ ---
1493
+
1494
+ ## EPIC 5 — MQTT transport
1495
+
1496
+ ### Agent tasks
1497
+
1498
+ - implement MQTT 5 client
1499
+ - implement TLS
1500
+ - QoS 1 publishing
1501
+ - connection state
1502
+ - reconnect backoff
1503
+ - jitter
1504
+ - publish acknowledgement handling
1505
+ - Last Will/status
1506
+ - graceful shutdown
1507
+ - integration tests using a local broker
1508
+
1509
+ ### Acceptance criteria
1510
+
1511
+ Telemetry is removed from the outbox only after successful publication acknowledgement.
1512
+
1513
+ Broker outages do not crash the plugin.
1514
+
1515
+ ---
1516
+
1517
+ ## EPIC 6 — Reconnect and backlog recovery
1518
+
1519
+ ### Agent tasks
1520
+
1521
+ - current-state priority publishing
1522
+ - live-vs-backlog scheduler
1523
+ - backlog throttling
1524
+ - duplicate safety
1525
+ - connection health metrics
1526
+ - degraded-network tests
1527
+
1528
+ ### Acceptance criteria
1529
+
1530
+ After a simulated one-hour outage:
1531
+
1532
+ 1. current vessel position appears first
1533
+ 2. new live data continues
1534
+ 3. historical backlog drains afterwards
1535
+ 4. no telemetry sequence is lost
1536
+ 5. duplicate delivery is safe
1537
+
1538
+ ---
1539
+
1540
+ ## EPIC 7 — Pairing
1541
+
1542
+ ### Agent tasks
1543
+
1544
+ - pairing API contract
1545
+ - pairing-code configuration
1546
+ - credential persistence
1547
+ - credential replacement
1548
+ - credential revocation handling
1549
+ - bounded retry and invalid-code handling
1550
+ - local credential-forget action with retained device state
1551
+ - authentication error states
1552
+ - status reporting
1553
+
1554
+ ### Acceptance criteria
1555
+
1556
+ A newly installed plugin can move through:
1557
+
1558
+ ```text
1559
+ unpaired
1560
+ → pairing
1561
+ → provisioned
1562
+ → connected
1563
+ ```
1564
+
1565
+ without manual MQTT configuration. Temporary service failures show a bounded retry state; confirmed revocation shows `Device revoked — enter a new pairing code`; forgetting local credentials preserves retired outboxes and requires a fresh code.
1566
+
1567
+ ---
1568
+
1569
+ ## EPIC 8 — Trip detection
1570
+
1571
+ ### Agent tasks
1572
+
1573
+ - movement-distance calculations
1574
+ - stationary cluster logic
1575
+ - trip state machine
1576
+ - start dwell timer
1577
+ - stop dwell timer
1578
+ - trip event generation
1579
+ - state persistence
1580
+ - simulated voyage tests
1581
+
1582
+ ### Acceptance criteria
1583
+
1584
+ The simulation suite correctly distinguishes:
1585
+
1586
+ ```text
1587
+ GPS drift
1588
+ real departure
1589
+ temporary stop
1590
+ anchoring
1591
+ arrival
1592
+ engine-off sailing
1593
+ ```
1594
+
1595
+ according to documented rules.
1596
+
1597
+ ---
1598
+
1599
+ ## EPIC 9 — Plugin UI/status
1600
+
1601
+ ### Agent tasks
1602
+
1603
+ - configuration schema
1604
+ - pairing input
1605
+ - status messages
1606
+ - queue metrics
1607
+ - connection information
1608
+ - basic troubleshooting feedback
1609
+
1610
+ ### Acceptance criteria
1611
+
1612
+ A vessel operator can determine whether the plugin is:
1613
+
1614
+ ```text
1615
+ paired
1616
+ connected
1617
+ offline
1618
+ buffering
1619
+ replaying
1620
+ faulted
1621
+ ```
1622
+
1623
+ without reading server logs.
1624
+
1625
+ ---
1626
+
1627
+ ## EPIC 10 — Production hardening
1628
+
1629
+ ### Agent tasks
1630
+
1631
+ - dependency audit
1632
+ - memory testing
1633
+ - CPU testing
1634
+ - long-duration testing
1635
+ - storage-limit testing
1636
+ - fuzz malformed input
1637
+ - log review
1638
+ - secret review
1639
+ - platform testing
1640
+ - documentation completion
1641
+
1642
+ ### Acceptance criteria
1643
+
1644
+ Run simulated tracking continuously for at least several days while introducing repeated outages and restarts.
1645
+
1646
+ No uncontrolled queue growth.
1647
+
1648
+ No memory growth.
1649
+
1650
+ No crashes.
1651
+
1652
+ No credentials in logs.
1653
+
1654
+ ---
1655
+
1656
+ # 38. Agent development rules
1657
+
1658
+ All agents working in this repository should follow these rules.
1659
+
1660
+ ## Rule 1
1661
+
1662
+ Do not alter protocol contracts silently.
1663
+
1664
+ Changes to telemetry protocol must update:
1665
+
1666
+ ```text
1667
+ telemetry-protocol.md
1668
+ tests
1669
+ protocol version where required
1670
+ ```
1671
+
1672
+ ## Rule 2
1673
+
1674
+ Do not introduce Wake Logger cloud business logic into this repository.
1675
+
1676
+ ## Rule 3
1677
+
1678
+ Do not combine post-trip archival uploads with live telemetry.
1679
+
1680
+ ## Rule 4
1681
+
1682
+ Internet outages are normal operating conditions, not exceptional failures.
1683
+
1684
+ ## Rule 5
1685
+
1686
+ Signal K sensors and paths may disappear at any time.
1687
+
1688
+ ## Rule 6
1689
+
1690
+ Never assume engine information exists.
1691
+
1692
+ ## Rule 7
1693
+
1694
+ Never assume one vessel timezone.
1695
+
1696
+ ## Rule 8
1697
+
1698
+ Never assume one jurisdiction.
1699
+
1700
+ ## Rule 9
1701
+
1702
+ Never require inbound connectivity to the vessel.
1703
+
1704
+ ## Rule 10
1705
+
1706
+ Do not introduce a native runtime dependency without demonstrating Signal K CI compatibility.
1707
+
1708
+ ## Rule 11
1709
+
1710
+ Tests accompany functional changes.
1711
+
1712
+ ## Rule 12
1713
+
1714
+ `start()` and `stop()` must remain safe and idempotent.
1715
+
1716
+ ## Rule 13
1717
+
1718
+ Do not expose secrets.
1719
+
1720
+ ## Rule 14
1721
+
1722
+ Keep bandwidth measurable and intentional.
1723
+
1724
+ ## Rule 15
1725
+
1726
+ Prioritise reliability and recoverability over clever optimisation.
1727
+
1728
+ ---
1729
+
1730
+ # 39. Recommended initial development sequence
1731
+
1732
+ Agents should not try to build everything simultaneously.
1733
+
1734
+ ### Phase 1
1735
+
1736
+ ```text
1737
+ Repo foundation
1738
+ Signal K plugin skeleton
1739
+ Signal K subscriptions
1740
+ Simulation fixtures
1741
+ ```
1742
+
1743
+ ### Phase 2
1744
+
1745
+ ```text
1746
+ Telemetry protocol
1747
+ Sampling
1748
+ Batching
1749
+ Sequence numbers
1750
+ ```
1751
+
1752
+ ### Phase 3
1753
+
1754
+ ```text
1755
+ Persistent outbox
1756
+ Crash recovery
1757
+ ```
1758
+
1759
+ ### Phase 4
1760
+
1761
+ ```text
1762
+ MQTT
1763
+ TLS
1764
+ QoS 1
1765
+ Reconnect behaviour
1766
+ ```
1767
+
1768
+ ### Phase 5
1769
+
1770
+ ```text
1771
+ Wake Logger ingestion integration
1772
+ Pairing
1773
+ ```
1774
+
1775
+ ### Phase 6
1776
+
1777
+ ```text
1778
+ Long outage handling
1779
+ Backlog scheduling
1780
+ ```
1781
+
1782
+ ### Phase 7
1783
+
1784
+ ```text
1785
+ Trip detection
1786
+ ```
1787
+
1788
+ ### Phase 8
1789
+
1790
+ ```text
1791
+ Real Raspberry Pi / Signal K vessel test
1792
+ ```
1793
+
1794
+ ### Phase 9
1795
+
1796
+ ```text
1797
+ Public beta
1798
+ Signal K registry
1799
+ npm/AppStore release
1800
+ ```
1801
+
1802
+ ---
1803
+
1804
+ # 40. First implementation milestone
1805
+
1806
+ The first genuinely useful milestone should be:
1807
+
1808
+ ```text
1809
+ Signal K sample NMEA 2000 data
1810
+ ↓
1811
+ signalk-wakelogger
1812
+ ↓
1813
+ position + SOG + COG
1814
+ ↓
1815
+ 1-second batches
1816
+ ↓
1817
+ persistent outbox
1818
+ ↓
1819
+ MQTT QoS 1
1820
+ ↓
1821
+ local test broker
1822
+ ↓
1823
+ test Wake Logger ingestion endpoint
1824
+ ```
1825
+
1826
+ Do not begin with:
1827
+
1828
+ ```text
1829
+ pairing UI
1830
+ adaptive bandwidth
1831
+ binary encoding
1832
+ complex trip detection
1833
+ full vessel telemetry
1834
+ ```
1835
+
1836
+ until this core pipeline works reliably.
1837
+
1838
+ ---
1839
+
1840
+ # 41. Definition of first-vessel-ready
1841
+
1842
+ The plugin is ready for installation on the first real vessel when all of the following are true:
1843
+
1844
+ - Signal K CI passes.
1845
+ - Plugin starts without internet.
1846
+ - Plugin starts without Wake Logger credentials.
1847
+ - Position/SOG/COG are captured correctly.
1848
+ - Telemetry survives Signal K restart.
1849
+ - Telemetry survives Pi restart.
1850
+ - MQTT disconnect/reconnect works.
1851
+ - A 30-minute outage produces no unintended telemetry loss.
1852
+ - Current position is prioritised when connectivity returns.
1853
+ - Backlog drains without blocking live telemetry.
1854
+ - QoS duplicates are handled.
1855
+ - Queue disk limits operate.
1856
+ - No secrets appear in logs.
1857
+ - CPU usage is acceptable on Raspberry Pi.
1858
+ - Memory usage remains stable.
1859
+ - Bandwidth usage has been measured.
1860
+ - Plugin status clearly reflects connection and queue state.
1861
+
1862
+ ---
1863
+
1864
+ # 42. Definition of public-release-ready
1865
+
1866
+ Before `1.0.0`:
1867
+
1868
+ - Complete README.
1869
+ - Complete architecture documentation.
1870
+ - Complete telemetry protocol documentation.
1871
+ - Complete trip detection documentation.
1872
+ - Screenshots available.
1873
+ - Changelog current.
1874
+ - Security policy available.
1875
+ - npm audit acceptable.
1876
+ - Signal K registry score reviewed.
1877
+ - Signal K CI green.
1878
+ - ARM testing completed.
1879
+ - Real vessel testing completed.
1880
+ - Multi-day session testing completed.
1881
+ - Poor-connectivity testing completed.
1882
+ - Wake Logger pairing operational.
1883
+ - Credential revocation tested.
1884
+ - MQTT ACL isolation tested.
1885
+ - Upgrade from previous plugin version tested.
1886
+ - Plugin uninstall/reinstall behaviour understood.
1887
+ - Privacy/data-transmission documentation complete.
1888
+
1889
+ ---
1890
+
1891
+ # 43. Non-goals for version 1
1892
+
1893
+ Do not allow scope creep into:
1894
+
1895
+ - full NMEA 2000 archival
1896
+ - CAN-frame uploads
1897
+ - historical file uploads
1898
+ - chart plotting
1899
+ - navigation planning
1900
+ - autopilot control
1901
+ - vessel control commands
1902
+ - remote Signal K administration
1903
+ - generic MQTT bridging
1904
+ - Signal K replacement
1905
+ - qualification calculations inside the plugin
1906
+ - country-specific regulatory logic
1907
+
1908
+ Those belong elsewhere.
1909
+
1910
+ ---
1911
+
1912
+ # 44. Product principle
1913
+
1914
+ The plugin should eventually feel almost invisible.
1915
+
1916
+ Ideal vessel-owner experience:
1917
+
1918
+ ```text
1919
+ Install Wake Logger
1920
+ ↓
1921
+ Enter pairing code
1922
+ ↓
1923
+ Connected
1924
+ ```
1925
+
1926
+ Everything else:
1927
+
1928
+ ```text
1929
+ MQTT
1930
+ TLS
1931
+ queue management
1932
+ retries
1933
+ sampling
1934
+ protocol versions
1935
+ outages
1936
+ backlog recovery
1937
+ ```
1938
+
1939
+ should happen automatically.
1940
+
1941
+ The success criterion is not merely that telemetry works on perfect Wi-Fi.
1942
+
1943
+ The success criterion is that the vessel can move between good cellular coverage, poor coverage and no coverage for extended periods, and Wake Logger still reconstructs an accurate, ordered tracking timeline once communication becomes available again.