colregs 0.1.0 → 0.1.1

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/PROVENANCE.md CHANGED
@@ -33,7 +33,7 @@ Two of the 38 (`NRHB_25_b.png`, `NRHB_27_ei.png`) are served by the USCG but
33
33
  not linked from the page; they were fetched by name. Two more
34
34
  (`NRHB_23_e.png`, `NRHB_24_j.png`) illustrate Great Lakes and Western Rivers
35
35
  paragraphs and are unmapped in this international-only release — they are kept
36
- because the inland ruleset will want them.
36
+ because the `us/inland` jurisdiction will want them.
37
37
 
38
38
  ### The `NR_*` / `NRHB_*` prefix question, resolved
39
39
 
package/README.md CHANGED
@@ -1,24 +1,60 @@
1
1
  # colregs
2
2
 
3
- The international collision regulations, and the national amalgamations derived
4
- from them, as language-neutral JSON with the provenance to check every line
5
- against its source and fixtures a second implementation can verify against.
3
+ The COLREGS 72 navigation *light* rules as language-neutral JSON, plus the
4
+ USCG's own diagrams and enough geometry to draw the lights yourself. Built as
5
+ the base other countries' national amalgamations hang off of, not scoped to
6
+ one country's rulebook.
6
7
 
7
8
  Data only. No runtime, no dependencies, no inference.
8
9
 
9
- > **Status: pre-release.** Nothing here is complete, and nothing here is fit for
10
- > navigation. See [`docs/requirements.md`](docs/requirements.md) for what it is
11
- > meant to become.
10
+ > **Status: pre-release.** Not complete, and not fit for navigation. Navigate
11
+ > by the published rules.
12
+
13
+ ```text
14
+ data/rules.json verbatim rule text, keyed by paragraph path and jurisdiction
15
+ data/lights.json the six Rule 21 lights: colour, arc, Rule 22 range
16
+ data/facts.json the fact record, and how to decode SignalK navigation.state
17
+ data/applicability.json predicate -> lights, each entry also carrying modality, citation, jurisdiction
18
+ data/geometry.json Annex I: heights, spacings, colour, intensity
19
+ data/images.json every image, its source, and what it illustrates
20
+ images/ 38 USCG diagrams + 5 arc GIFs
21
+ fixtures/ fact records and the entries that apply to them
22
+ ```
12
23
 
13
24
  ## Coverage
14
25
 
15
- | | |
16
- |---|---|
17
- | **Rules** | Part C, lights (Rules 20–31). Day shapes and Part D signals are not here. |
18
- | **Jurisdictions** | `intl` only. US Inland, Canada and the rest are modelled for but not present. |
19
- | **Conditions** | Night. |
26
+ Part C lights (Rules 20-31) only, `intl` jurisdiction only, night only. Day
27
+ shapes, Part D signals, and every other jurisdiction (US Inland, Canada,
28
+ CEVNI) are on the roadmap in [`docs/requirements.md`](docs/requirements.md)
29
+ but not present here.
30
+
31
+ ## The four layers
32
+
33
+ **Rule text.** Keyed by *paragraph path*, like `27(a)(i)` or `25(d)(ii)`,
34
+ because the paragraph is the unit you actually cite. The text is verbatim
35
+ International text; Inland-only inserts were stripped rather than paraphrased.
36
+
37
+ **Light definitions.** This layer is Rule 21. Each light carries its colour,
38
+ its arc as a bearing range, and its minimum visible range by length band from
39
+ Rule 22. Bearings run in degrees clockwise from right ahead, and an arc whose
40
+ `from_deg` exceeds its `to_deg` wraps through the bow. So the masthead light
41
+ is 247.5° to 112.5°, which is 225° of arc.
42
+
43
+ **Facts.** Three orthogonal axes (`propulsion`, `activity`, `position`), a
44
+ `making_way` modifier that refines `underway`, and scalars such as `length_m`
45
+ and `tow_length_m`. There is deliberately no vessel-class field. Under COLREGS
46
+ what a vessel *is* follows from what it is *doing*, so classification falls
47
+ out of the axes on its own.
48
+
49
+ SignalK's `navigation.state` flattens all of that into one enum. `facts.json`
50
+ therefore carries a decode table, the enum values it can't decode, and the
51
+ five places where the flattening loses information. Fishing at anchor and
52
+ making-way are the two of those that matter in practice.
20
53
 
21
- Coverage is stated because silence must not imply it (REQ-SCOPE-6).
54
+ **Applicability entries.** Each entry is a predicate over facts, a set of
55
+ lights or references to other entries, a modality, a citation, and a
56
+ jurisdiction. Every entry has an id (`25b`, `27a-mw`) that both consumers can
57
+ point at.
22
58
 
23
59
  ## Design
24
60
 
@@ -26,25 +62,100 @@ This repo is requirements-first. Coding sessions work against numbered
26
62
  requirements and cite them; decisions that shaped the design are recorded as
27
63
  ADRs rather than argued again.
28
64
 
29
- - [`docs/requirements.md`](docs/requirements.md) the source of truth
30
- - [`docs/adr/`](docs/adr/) decisions, with the reasoning that produced them
65
+ - [`docs/requirements.md`](docs/requirements.md): the source of truth
66
+ - [`docs/adr/`](docs/adr/): decisions, with the reasoning that produced them
31
67
 
32
68
  Three ideas carry most of the design:
33
69
 
34
70
  **The paragraph is the unit.** Rule text, citations and composition all key on
35
- the paragraph path `27(a)(i)`, not "Rule 27". Citation unit and composition
71
+ the paragraph path (`27(a)(i)`, not "Rule 27"). Citation unit and composition
36
72
  unit turn out to be the same thing.
37
73
 
74
+ **Jurisdiction is a dimension, not a fork.** Every rule-text record and every
75
+ applicability entry carries a `jurisdiction`: `intl` (the reserved base value)
76
+ or `<country-or-body>/<waters>` (`us/inland`, `eu/cevni`). A jurisdiction is a
77
+ delta on `intl`; entries it doesn't override are inherited, not restated
78
+ (REQ-SCOPE-2/3). Geography that merely gates a rule inside one jurisdiction
79
+ (Great Lakes, Western Rivers) is an ordinary fact a predicate reads, not a
80
+ jurisdiction of its own (REQ-SCOPE-5).
81
+
38
82
  **Predicates, not enumerations.** Gates are `length_m < 7`, never a pre-built
39
83
  list of configurations. Enumerated tables are where prior art silently loses
40
84
  rules; a predicate cannot omit a case it was never asked about.
41
85
 
42
- **Alternatives are first-class.** COLREGS routinely permits a choice a
86
+ **Alternatives are first-class.** COLREGS routinely permits a choice: a
43
87
  tricolor *in lieu of* separate sidelights, a torch *in lieu of* either. The data
44
88
  carries every lawful option with its modality and gate, and picks none of them.
45
89
  Selection belongs to the consumer.
46
90
 
47
- ## Licence
91
+ ## Predicate semantics
92
+
93
+ An entry applies when **every** constraint in its `when` is satisfied. An
94
+ absent fact never satisfies a constraint. Numeric constraints are
95
+ `{gte, gt, lte, lt}`; a list means membership; anything else is equality.
96
+ `activity: "ram"` also matches `ram_underwater`, which is a refinement of it.
97
+
98
+ Entries **compose**: several apply to one fact record, and Rule 28 or Rule 26
99
+ add to Rule 23 rather than replacing it. Relations between them:
100
+
101
+ | relation | meaning |
102
+ |---|---|
103
+ | `includes` | import the referenced entry's **lights only**, never its predicate |
104
+ | `conditional_includes` | import lights when the stated `when` holds; `one_of` is a set of legal alternatives |
105
+ | `in_lieu_of` | this entry's lights replace the referenced entries' lights |
106
+ | `excludes` | must not be shown together (25(c) and the tricolor) |
107
+ | `exempts` | the referenced requirement does not apply (30(e)) |
108
+
109
+ Where the rules permit a choice, the data keeps every lawful option instead of
110
+ picking one. A 12 m sloop under sail has three legal displays: 25(a), the
111
+ 25(b) tricolor, or 25(a) plus the 25(c) red-over-green. Which one a given boat
112
+ shows depends on what's installed, and that decision belongs to the consumer.
113
+
114
+ Modality is `shall`, `may`, `shall-if-practicable`, or `conditional` with a
115
+ `modality_by` table when it turns on a fact (23(a)(ii) is `shall` at 50 m and
116
+ above, `may` below).
117
+
118
+ ## What this package does not do
119
+
120
+ It does not infer anything. It is a pure function of the fact record. Deciding
121
+ *that* a vessel is making way, or fishing, or aground is somebody else's job.
122
+ Nothing here reads a sensor.
123
+
124
+ It does not select a single display. Where the rules offer alternatives, all of
125
+ them come back.
126
+
127
+ ## Verifying
128
+
129
+ ```bash
130
+ npm test
131
+ ```
132
+
133
+ Every fixture reproduces exactly; every citation, cross-reference, light and
134
+ geometry reference resolves; every image is on disk with its SHA-256 recorded;
135
+ every decoded `navigation.state` value and every fact a predicate reads is
136
+ declared.
137
+
138
+ A **drift test** (REQ-VERIFY-2) cross-checks two directions: forward, fact
139
+ record to lights, and reverse, lights already shown to which other entries
140
+ could explain them. It fails on any collision the data doesn't already
141
+ declare through `includes`/`in_lieu_of`/`excludes`/`exempts`/
142
+ `conditional_includes`.
143
+
144
+ Every numeric gate that affects *which entries apply* has fixtures immediately
145
+ either side of its threshold (REQ-VERIFY-5), and every entry is exercised by
146
+ at least one fixture and absent from at least one other (REQ-VERIFY-3). Three
147
+ gates that affect only *modality*, not which entries apply, are flagged as an
148
+ open question rather than fixtured against a schema that can't express the
149
+ distinction; see [Q-5](docs/requirements.md#9-open-questions).
150
+
151
+ `fixtures/applicability-fixtures.json` is the cross-implementation contract: an
152
+ implementation in any language should reproduce those entry sets exactly.
153
+
154
+ ## Provenance and licence
155
+
156
+ Rule text and `NRHB_*` diagrams are USCG publications, public domain. The five
157
+ `*arc.gif` files came from an older repo and their provenance is unresolved;
158
+ see [PROVENANCE.md](PROVENANCE.md). The compilation is MIT.
48
159
 
49
- Code and fixtures: see `LICENSE`. Rule text and diagrams carry their own terms,
50
- recorded per asset — see `PROVENANCE.md` once data lands.
160
+ Not authoritative, not endorsed by the Coast Guard. Navigate by the published
161
+ rules.
@@ -1,5 +1,4 @@
1
1
  {
2
- "ruleset": "international",
3
2
  "conditions": "night (Rule 20(b): sunset to sunrise), and by 20(c) in restricted visibility by day. Day shapes are not in this release.",
4
3
  "relations": {
5
4
  "includes": "import another entry's lights only, never its predicate",
@@ -45,7 +44,7 @@
45
44
  "entries": [
46
45
  {
47
46
  "id": "23a1",
48
- "ruleset": "international",
47
+ "jurisdiction": "intl",
49
48
  "cite": "23(a)(i)",
50
49
  "when": {
51
50
  "propulsion": "power",
@@ -66,7 +65,7 @@
66
65
  },
67
66
  {
68
67
  "id": "23a2",
69
- "ruleset": "international",
68
+ "jurisdiction": "intl",
70
69
  "cite": "23(a)(ii)",
71
70
  "when": {
72
71
  "propulsion": "power",
@@ -105,7 +104,7 @@
105
104
  },
106
105
  {
107
106
  "id": "23a34",
108
- "ruleset": "international",
107
+ "jurisdiction": "intl",
109
108
  "cite": "23(a)(iii)-(iv)",
110
109
  "when": {
111
110
  "propulsion": "power",
@@ -124,7 +123,7 @@
124
123
  },
125
124
  {
126
125
  "id": "23b",
127
- "ruleset": "international",
126
+ "jurisdiction": "intl",
128
127
  "cite": "23(b)",
129
128
  "when": {
130
129
  "propulsion": "power",
@@ -153,13 +152,14 @@
153
152
  },
154
153
  {
155
154
  "id": "23c",
156
- "ruleset": "international",
155
+ "jurisdiction": "intl",
157
156
  "cite": "23(c)",
158
157
  "when": {
159
158
  "propulsion": "power",
160
159
  "activity": "none",
161
160
  "position": "underway",
162
- "wig": true
161
+ "wig": true,
162
+ "wig_near_surface": true
163
163
  },
164
164
  "lights": [
165
165
  {
@@ -180,7 +180,7 @@
180
180
  },
181
181
  {
182
182
  "id": "23d1",
183
- "ruleset": "international",
183
+ "jurisdiction": "intl",
184
184
  "cite": "23(d)(i)",
185
185
  "when": {
186
186
  "propulsion": "power",
@@ -212,7 +212,7 @@
212
212
  },
213
213
  {
214
214
  "id": "23d2",
215
- "ruleset": "international",
215
+ "jurisdiction": "intl",
216
216
  "cite": "23(d)(ii)",
217
217
  "when": {
218
218
  "propulsion": "power",
@@ -249,7 +249,7 @@
249
249
  },
250
250
  {
251
251
  "id": "24a-m2",
252
- "ruleset": "international",
252
+ "jurisdiction": "intl",
253
253
  "cite": "24(a)(i)",
254
254
  "when": {
255
255
  "activity": "towing",
@@ -275,7 +275,7 @@
275
275
  },
276
276
  {
277
277
  "id": "24a-m3",
278
- "ruleset": "international",
278
+ "jurisdiction": "intl",
279
279
  "cite": "24(a)(i)",
280
280
  "when": {
281
281
  "activity": "towing",
@@ -301,7 +301,7 @@
301
301
  },
302
302
  {
303
303
  "id": "24a-rest",
304
- "ruleset": "international",
304
+ "jurisdiction": "intl",
305
305
  "cite": "24(a)(ii)-(iv)",
306
306
  "when": {
307
307
  "activity": "towing"
@@ -323,7 +323,7 @@
323
323
  },
324
324
  {
325
325
  "id": "24b",
326
- "ruleset": "international",
326
+ "jurisdiction": "intl",
327
327
  "cite": "24(b)",
328
328
  "when": {
329
329
  "activity": "pushing",
@@ -343,7 +343,7 @@
343
343
  },
344
344
  {
345
345
  "id": "24c",
346
- "ruleset": "international",
346
+ "jurisdiction": "intl",
347
347
  "cite": "24(c)",
348
348
  "when": {
349
349
  "activity": "pushing",
@@ -368,7 +368,7 @@
368
368
  },
369
369
  {
370
370
  "id": "24e",
371
- "ruleset": "international",
371
+ "jurisdiction": "intl",
372
372
  "cite": "24(e)",
373
373
  "when": {
374
374
  "activity": "being_towed"
@@ -389,7 +389,7 @@
389
389
  },
390
390
  {
391
391
  "id": "25a",
392
- "ruleset": "international",
392
+ "jurisdiction": "intl",
393
393
  "cite": "25(a)",
394
394
  "when": {
395
395
  "propulsion": "sail",
@@ -411,7 +411,7 @@
411
411
  },
412
412
  {
413
413
  "id": "25b",
414
- "ruleset": "international",
414
+ "jurisdiction": "intl",
415
415
  "cite": "25(b)",
416
416
  "when": {
417
417
  "propulsion": "sail",
@@ -447,7 +447,7 @@
447
447
  },
448
448
  {
449
449
  "id": "25c",
450
- "ruleset": "international",
450
+ "jurisdiction": "intl",
451
451
  "cite": "25(c)",
452
452
  "when": {
453
453
  "propulsion": "sail",
@@ -481,7 +481,7 @@
481
481
  },
482
482
  {
483
483
  "id": "25d1",
484
- "ruleset": "international",
484
+ "jurisdiction": "intl",
485
485
  "cite": "25(d)(i)",
486
486
  "when": {
487
487
  "propulsion": "sail",
@@ -511,7 +511,7 @@
511
511
  },
512
512
  {
513
513
  "id": "25d2",
514
- "ruleset": "international",
514
+ "jurisdiction": "intl",
515
515
  "cite": "25(d)(ii)",
516
516
  "when": {
517
517
  "propulsion": "oars"
@@ -540,7 +540,7 @@
540
540
  },
541
541
  {
542
542
  "id": "26b-id",
543
- "ruleset": "international",
543
+ "jurisdiction": "intl",
544
544
  "cite": "26(b)(i)",
545
545
  "when": {
546
546
  "activity": "trawling"
@@ -571,7 +571,7 @@
571
571
  },
572
572
  {
573
573
  "id": "26b-mast",
574
- "ruleset": "international",
574
+ "jurisdiction": "intl",
575
575
  "cite": "26(b)(ii)",
576
576
  "when": {
577
577
  "activity": "trawling"
@@ -605,7 +605,7 @@
605
605
  },
606
606
  {
607
607
  "id": "26b-mw",
608
- "ruleset": "international",
608
+ "jurisdiction": "intl",
609
609
  "cite": "26(b)(iii)",
610
610
  "when": {
611
611
  "activity": "trawling",
@@ -622,7 +622,7 @@
622
622
  },
623
623
  {
624
624
  "id": "26c-id",
625
- "ruleset": "international",
625
+ "jurisdiction": "intl",
626
626
  "cite": "26(c)(i)",
627
627
  "when": {
628
628
  "activity": "fishing"
@@ -649,7 +649,7 @@
649
649
  },
650
650
  {
651
651
  "id": "26c-gear",
652
- "ruleset": "international",
652
+ "jurisdiction": "intl",
653
653
  "cite": "26(c)(ii)",
654
654
  "when": {
655
655
  "activity": "fishing",
@@ -669,7 +669,7 @@
669
669
  },
670
670
  {
671
671
  "id": "26c-mw",
672
- "ruleset": "international",
672
+ "jurisdiction": "intl",
673
673
  "cite": "26(c)(iii)",
674
674
  "when": {
675
675
  "activity": "fishing",
@@ -686,7 +686,7 @@
686
686
  },
687
687
  {
688
688
  "id": "27a-id",
689
- "ruleset": "international",
689
+ "jurisdiction": "intl",
690
690
  "cite": "27(a)(i)",
691
691
  "when": {
692
692
  "activity": "nuc",
@@ -707,7 +707,7 @@
707
707
  },
708
708
  {
709
709
  "id": "27a-mw",
710
- "ruleset": "international",
710
+ "jurisdiction": "intl",
711
711
  "cite": "27(a)(iii)",
712
712
  "when": {
713
713
  "activity": "nuc",
@@ -724,7 +724,7 @@
724
724
  },
725
725
  {
726
726
  "id": "27b-id",
727
- "ruleset": "international",
727
+ "jurisdiction": "intl",
728
728
  "cite": "27(b)(i)",
729
729
  "when": {
730
730
  "activity": "ram"
@@ -754,7 +754,7 @@
754
754
  },
755
755
  {
756
756
  "id": "27b-mw",
757
- "ruleset": "international",
757
+ "jurisdiction": "intl",
758
758
  "cite": "27(b)(iii)",
759
759
  "when": {
760
760
  "activity": "ram",
@@ -773,7 +773,7 @@
773
773
  },
774
774
  {
775
775
  "id": "27b-anc",
776
- "ruleset": "international",
776
+ "jurisdiction": "intl",
777
777
  "cite": "27(b)(iv)",
778
778
  "when": {
779
779
  "activity": "ram",
@@ -795,7 +795,7 @@
795
795
  },
796
796
  {
797
797
  "id": "27d",
798
- "ruleset": "international",
798
+ "jurisdiction": "intl",
799
799
  "cite": "27(d)",
800
800
  "when": {
801
801
  "activity": "ram_underwater",
@@ -828,7 +828,7 @@
828
828
  },
829
829
  {
830
830
  "id": "27e",
831
- "ruleset": "international",
831
+ "jurisdiction": "intl",
832
832
  "cite": "27(e)(i)",
833
833
  "when": {
834
834
  "activity": "diving"
@@ -864,7 +864,7 @@
864
864
  },
865
865
  {
866
866
  "id": "27f",
867
- "ruleset": "international",
867
+ "jurisdiction": "intl",
868
868
  "cite": "27(f)",
869
869
  "when": {
870
870
  "activity": "mine"
@@ -900,7 +900,7 @@
900
900
  },
901
901
  {
902
902
  "id": "28",
903
- "ruleset": "international",
903
+ "jurisdiction": "intl",
904
904
  "cite": "28",
905
905
  "when": {
906
906
  "activity": "cbd"
@@ -926,7 +926,7 @@
926
926
  },
927
927
  {
928
928
  "id": "29a",
929
- "ruleset": "international",
929
+ "jurisdiction": "intl",
930
930
  "cite": "29(a)",
931
931
  "when": {
932
932
  "activity": "pilot"
@@ -974,7 +974,7 @@
974
974
  },
975
975
  {
976
976
  "id": "30a",
977
- "ruleset": "international",
977
+ "jurisdiction": "intl",
978
978
  "cite": "30(a)",
979
979
  "when": {
980
980
  "position": "anchored"
@@ -1000,7 +1000,7 @@
1000
1000
  },
1001
1001
  {
1002
1002
  "id": "30b",
1003
- "ruleset": "international",
1003
+ "jurisdiction": "intl",
1004
1004
  "cite": "30(b)",
1005
1005
  "when": {
1006
1006
  "position": "anchored",
@@ -1023,7 +1023,7 @@
1023
1023
  },
1024
1024
  {
1025
1025
  "id": "30c",
1026
- "ruleset": "international",
1026
+ "jurisdiction": "intl",
1027
1027
  "cite": "30(c)",
1028
1028
  "when": {
1029
1029
  "position": "anchored"
@@ -1055,8 +1055,27 @@
1055
1055
  ]
1056
1056
  },
1057
1057
  {
1058
- "id": "30d",
1059
- "ruleset": "international",
1058
+ "id": "30d-anchor",
1059
+ "jurisdiction": "intl",
1060
+ "cite": "30(d)",
1061
+ "when": {
1062
+ "position": "aground"
1063
+ },
1064
+ "lights": [],
1065
+ "conditional_includes": [
1066
+ {
1067
+ "one_of": [
1068
+ "30a",
1069
+ "30b"
1070
+ ]
1071
+ }
1072
+ ],
1073
+ "modality": "shall",
1074
+ "notes": "30(d)'s lead-in requires the 30(a)/(b) anchor lights unconditionally, with no length gate; only the two red lights below (30(d)(i)-(ii)) are subject to the 30(f) exemption."
1075
+ },
1076
+ {
1077
+ "id": "30d-red",
1078
+ "jurisdiction": "intl",
1060
1079
  "cite": "30(d)",
1061
1080
  "when": {
1062
1081
  "position": "aground",
@@ -1072,23 +1091,15 @@
1072
1091
  "arrangement": "vertical"
1073
1092
  }
1074
1093
  ],
1075
- "conditional_includes": [
1076
- {
1077
- "one_of": [
1078
- "30a",
1079
- "30b"
1080
- ]
1081
- }
1082
- ],
1083
1094
  "modality": "shall-if-practicable",
1084
1095
  "images": [
1085
1096
  "NRHB_30_d.png"
1086
1097
  ],
1087
- "notes": "The Rule 30(a)/(b) anchor lights are 'shall'; the two red lights are 'shall, if practicable'. 30(f) exempts vessels under 12 m from the red lights."
1098
+ "notes": "The two red lights are 'shall, if practicable'. 30(f) exempts vessels under 12 m from them; it does not exempt the 30(a)/(b) anchor lights, see 30d-anchor."
1088
1099
  },
1089
1100
  {
1090
1101
  "id": "30e",
1091
- "ruleset": "international",
1102
+ "jurisdiction": "intl",
1092
1103
  "cite": "30(e)",
1093
1104
  "when": {
1094
1105
  "position": "anchored",
package/data/facts.json CHANGED
@@ -119,7 +119,13 @@
119
119
  },
120
120
  "wig": {
121
121
  "cite": "23(c)",
122
- "actuable": false
122
+ "actuable": false,
123
+ "note": "The vessel is a wing-in-ground craft. Doesn't by itself mean 23(c) applies -- see wig_near_surface."
124
+ },
125
+ "wig_near_surface": {
126
+ "cite": "23(c)",
127
+ "actuable": false,
128
+ "note": "Taking off, landing, or in flight near the surface. 23(c) is scoped to this phase, not to being a WIG craft generally."
123
129
  },
124
130
  "near_channel": {
125
131
  "cite": "30(e)",
@@ -1,5 +1,5 @@
1
1
  {
2
- "ruleset": "international",
2
+ "jurisdiction": "intl",
3
3
  "source": "Annex I - Positioning and Technical Details of Lights and Shapes (33 CFR 84), International text",
4
4
  "note": "The structured half of the image payload: where each light sits and what it looks like, so a renderer can draw a configuration instead of picking a scan. Bearing arcs live in lights.json; this file carries heights, spacings, colour and intensity.",
5
5
  "vertical_positioning": [
package/data/images.json CHANGED
@@ -780,7 +780,7 @@
780
780
  "30(d)"
781
781
  ],
782
782
  "entries": [
783
- "30d"
783
+ "30d-red"
784
784
  ]
785
785
  },
786
786
  "NRHB_30_dii.png": {
package/data/lights.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "ruleset": "international",
2
+ "jurisdiction": "intl",
3
3
  "bearing_convention": {
4
4
  "zero": "right ahead",
5
5
  "direction": "clockwise (0 bow, 90 starboard beam, 180 right aft)",