Skip to main content

domain

Sailing instrument tribal knowledge that is NOT directly grep-recoverable from the code — common-mistake guards, B&G/instrument-vendor quirks, J/105 polar reference targets, and calibration miscalibration symptoms. Auto-triggers when working on sk_reader.py, can_reader.py, nmea2000.py, polar.py, boat_settings.py, synthesize.py, maneuver_detector.py, export.py, or calibration-related code. Skill content is intentionally narrow — for paths, PGN byte layouts, conversion constants, and table schemas already encoded in the source, read sk_reader.py / nmea2000.py / storage.py directly.

Jump to install

Source facts

Repository
weaties/helmlog
Last source activity
April 26, 2026 at 21:17
Detected SKILL.md language
English
Stars
2
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
domain
description
Sailing instrument tribal knowledge that is NOT directly grep-recoverable from the code — common-mistake guards, B&G/instrument-vendor quirks, J/105 polar reference targets, and calibration miscalibration symptoms. Auto-triggers when working on sk_reader.py, can_reader.py, nmea2000.py, polar.py, boat_settings.py, synthesize.py, maneuver_detector.py, export.py, or calibration-related code. Skill content is intentionally narrow — for paths, PGN byte layouts, conversion constants, and table schemas already encoded in the source, read sk_reader.py / nmea2000.py / storage.py directly.
# Sailing Instrument Domain — Tribal Knowledge This skill encodes only what the codebase does NOT make obvious on its own: common mistakes the model has made before, vendor-specific quirks, polar target speeds for our hull, and miscalibration symptoms. For Signal K paths, PGN byte layouts, conversion constants, table schemas, and unit conversions, read `sk_reader.py`, `nmea2000.py`, and `storage.py` directly — those files are the source of truth and are always more current than this skill. --- ## 1. Common mistakes (priming guards) These are errors the model has historically made. Read these before writing instrument-handling code. - **Polar calculations always use BSP (`navigation.speedThroughWater`), never SOG (`navigation.speedOverGround`).** SOG includes current — a 1-knot favorable current makes the boat look 1 knot faster at every TWA/TWS bin and contaminates the polar. - **TWA is derived FROM apparent wind, not the reverse.** AWA + AWS + BSP → TWA + TWS. The masthead wand measures AWA directly; TWA is computed by the instrument processor (B&G Zeus). Code that "derives AWA from TWA" is upside-down. - **TWA is 0–180 in HelmLog**, not 0–360. Port/starboard symmetry is assumed for polars. If you find yourself wrapping a TWA value through 360, you are probably handling TWD (true wind direction), not TWA. - **Wind reference field matters.** PGN 130306's reference field decides what `wind_angle_deg` actually means. Mishandling this is a recurring bug. Codes (also in `nmea2000.py`): - `0` — true, boat-referenced — value IS TWA - `2` — apparent — filter out for polars - `4` — true, north-referenced — value is TWD; **TWA = `(TWD - HDG + 360) % 360`** then fold to 0–180 - **B&G systems typically emit reference 4 (TWD), not reference 0 (TWA).** So `_compute_twa()` in `polar.py` is on the hot path; do not bypass it. - **Reference=4 needs a contemporaneous heading.** If `HeadingRecord` is missing or stale, drop the wind sample — do not guess. - **AIS PGNs (129038–129810) are never ingested.** Data licensing requirement (#208), not a technical limitation. If you find yourself adding an AIS decoder, stop and check `docs/data-licensing.md`. --- ## 2. J/105 reference polars (used for synthetic test data) These are the optimal upwind/downwind targets for our hull, used by `synthesize.py` to generate fixture data. They are not in the SQL schema; if you need numeric ground truth for a test, this is it: | TWS (kts) | Upwind TWA | Upwind BSP | Downwind TWA | Downwind BSP | |---|---|---|---|---| | 6 | 44° | 5.2 kts | 150° | 4.8 kts | | 8 | 43° | 6.0 kts | 145° | 5.8 kts | | 10 | 42° | 6.5 kts | 140° | 6.5 kts | | 12 | 41° | 6.8 kts | 135° | 7.0 kts | | 16 | 39° | 7.3 kts | 130° | 7.6 kts | If observed BSP is consistently >10% above or below these for the same (TWS, TWA), suspect BSP calibration drift before assuming the model is fast or slow. --- ## 3. Polar binning conventions Not obvious from code at a glance: - **TWS bins:** floor of TWS in knots (0, 1, 2, … 30+). - **TWA bins:** floor to nearest 5° (0, 5, 10, … 175, 180). - **Per bin:** mean BSP, P90 BSP, session count, sample count. - **Minimum sessions:** 3 races before the baseline is published. VMG bands (for VMG-per-sail analysis): 0–6, 6–10, 10–15, 15–20, 20+ kts. --- ## 4. Calibration miscalibration symptoms Crew-entered tuning parameters live in `boat_settings.py`. They are stored for debrief correlation; most do not yet feed calculations. The non-obvious part is what miscalibration *looks like* in the data: | Parameter | What it controls | Miscalibration symptom | |---|---|---| | **BSP calibration** | Paddlewheel scale factor | Polars consistently above/below J/105 targets; VMG unreliable | | **AWA offset** | Wind vane zero point | Upwind performance differs port vs. starboard tack | | **Compass deviation** | Heading correction table | TWA wrong when derived from TWD (ref=4); tack/gybe misclassified | | **Depth offset** | Transducer-to-keel distance | `offset_m` in `DepthRecord`; shallow-water alarms fire at wrong depth | | **GPS antenna position** | SOG/COG | Usually accurate; offset matters only for match-racing precision | If a debrief shows asymmetric upwind speed across tacks, the first hypothesis should be AWA offset, not crew technique. --- ## 5. Maneuver classification rule Heading change alone does NOT classify a tack vs. gybe — TWA before and after determines it. Source of truth is `maneuver_detector.py`, but the rule in plain English: | TWA before | TWA after | Heading change | Classification | |---|---|---|---| | <90° (upwind) | <90° (upwind) | ≥60° | **Tack** | | >90° (downwind) | >90° (downwind) | ≥60° | **Gybe** | | crosses 90° boundary | — | ≥60° | **Mark rounding** | Without true wind data the detector falls back to a generic `"maneuver"` type — heading change with no TWA context is unclassified, not assumed.
View on GitHub