colregs 0.2.3 → 0.2.4
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 +4 -0
- package/README.md +109 -286
- package/data/applicability.json +13 -10
- package/data/images.json +570 -33
- package/data/rules.json +40 -20
- package/data/version.json +1 -1
- package/docs/adr/0001-name-and-jurisdiction-model.md +35 -2
- package/docs/adr/0003-language-as-a-dimension.md +1 -1
- package/docs/adr/0010-text-withheld-jurisdictions.md +123 -0
- package/docs/adr/0011-api-shape.md +173 -0
- package/docs/adr/0012-trace-and-rule2-departure-api.md +203 -0
- package/docs/budgets.json +6 -2
- package/docs/requirements.md +36 -6
- package/docs/verification/2026-09-09-text-slug-straw-man.md +264 -0
- package/fixtures/situation-fixtures.json +78 -0
- package/package.json +1 -1
- package/schema/images.schema.json +26 -1
- package/schema/rules.schema.json +75 -2
package/PROVENANCE.md
CHANGED
|
@@ -19,6 +19,10 @@ publications. Nothing here is authoritative: consult the published rules.
|
|
|
19
19
|
reconstruct it from memory, `rules.json` records it under `gaps` and the
|
|
20
20
|
paragraph is omitted. 24(g) covers inconspicuous, partly submerged tows and
|
|
21
21
|
is outside the applicability table in this release.
|
|
22
|
+
- **Withheld text is not a gap.** A `gaps` entry is a paragraph we could not
|
|
23
|
+
obtain. A paragraph with `text_status: withheld` is one we hold but may not
|
|
24
|
+
publish, under a licence bar recorded in `withheld_reason` — see ADR 0010.
|
|
25
|
+
None exist yet; `intl` is entirely verbatim.
|
|
22
26
|
- **Known quirks kept verbatim:** the source's own text of Rule 1(c) repeats
|
|
23
27
|
"special rules ... special rules made" and Rule 13(b) reads "coming up with
|
|
24
28
|
a another vessel" (sic), and Rule 10(c) reads "A vessel, shall so far as
|
package/README.md
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
# colregs
|
|
2
2
|
|
|
3
|
-
|
|
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.
|
|
3
|
+
Two vessels are closing. *What must they do? Who gives way? What must they display?*
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
The COLREGS, the International Regulations for Preventing Collisions at Sea, answer all three. This project
|
|
6
|
+
transforms the colregs so that a machine can evaluate and reason about them *deterministically*:
|
|
7
|
+
the whole of the rules as structured data, so the same situation always yields the same result,
|
|
8
|
+
and every result can be traced back to the rule that produced it. Going further, the engine
|
|
9
|
+
and the rules are then *checked with formal methods*, which means mathematically proving the rule set
|
|
10
|
+
is consistent and complete rather than just testing it a bunch and hoping it all works out.
|
|
11
|
+
|
|
12
|
+
This package is the data: the rules as language-neutral JSON, the USCG's own diagrams, and
|
|
13
|
+
enough geometry to draw the lights yourself. Jurisdictions are deltas on the international
|
|
14
|
+
base, so national amalgamations hang off it rather than forking it.
|
|
15
|
+
|
|
16
|
+
Related packages:
|
|
17
|
+
* [colregs](https://github.com/mark-brannan/colregs) - the data and JSON Schema
|
|
18
|
+
* [colregs-engine](https://github.com/mark-brannan/colregs-engine) - the engine that evaluates rules
|
|
19
|
+
* [colregs-mcp](https://github.com/mark-brannan/colregs-mcp) - an MCP server so AI can use the engine
|
|
20
|
+
* [nav-wright](https://github.com/mark-brannan/nav-wright) - draws vessels and displays (stub)
|
|
21
|
+
* [searoom](https://github.com/mark-brannan/searoom) - a study tool demo
|
|
22
|
+
|
|
23
|
+
See a [live demo](https://mark-brannan.github.io/searoom/) of searoom and the colregs data/engine.
|
|
9
24
|
|
|
10
25
|
> **Status: pre-release.** Not complete, and not fit for navigation. Navigate
|
|
11
26
|
> by the published rules.
|
|
12
27
|
|
|
13
28
|
```text
|
|
14
|
-
data/rules.json
|
|
29
|
+
data/rules.json rule text, keyed by paragraph path and jurisdiction
|
|
15
30
|
data/lights.json the six Rule 21 lights: colour, arc, Rule 22 range
|
|
16
31
|
data/facts.json the fact record, and how to decode SignalK navigation.state
|
|
17
32
|
data/applicability.json predicate -> lights, each entry also carrying modality, citation, jurisdiction
|
|
@@ -22,107 +37,82 @@ images/ 38 USCG diagrams + 5 arc GIFs
|
|
|
22
37
|
fixtures/ fact records and the entries that apply to them
|
|
23
38
|
```
|
|
24
39
|
|
|
25
|
-
##
|
|
40
|
+
## What this package does not do
|
|
26
41
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
present here.
|
|
42
|
+
It has no runtime and no dependencies. It does not infer anything: it is a
|
|
43
|
+
pure function of the fact record, and deciding *that* a vessel is fishing, or
|
|
44
|
+
aground, or making way is the caller's job. Nothing here reads a sensor.
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
It does not select a single display. Where the rules permit a choice, every
|
|
47
|
+
lawful option comes back and none is picked. Selection belongs to the consumer.
|
|
48
|
+
|
|
49
|
+
## Coverage
|
|
50
|
+
|
|
51
|
+
Every rule with a machine-checkable consequence: Part B conduct, Part C
|
|
52
|
+
lights and shapes, Part D sound and light signals, and Annex I geometry.
|
|
53
|
+
`intl` is the base; `us/inland`, `ca/inland` and `eu/cevni` are deltas on it.
|
|
54
|
+
[`docs/requirements.md`](docs/requirements.md) is the numbered contract for
|
|
55
|
+
all of it. One case the Convention cannot state, a vessel made fast to a
|
|
56
|
+
mooring buoy, lives only under `us/inland`
|
|
36
57
|
([ADR 0008](docs/adr/0008-mooring-buoy-modifier.md)).
|
|
37
58
|
|
|
38
|
-
## The
|
|
59
|
+
## The layers
|
|
39
60
|
|
|
40
|
-
**Rule text.**
|
|
41
|
-
|
|
42
|
-
|
|
61
|
+
**Rule text.** Verbatim, keyed by *paragraph path*, like `27(a)(i)`, because
|
|
62
|
+
the paragraph is the unit you actually cite. Where a licence bars republishing
|
|
63
|
+
a jurisdiction's words, the paragraph is still modelled and its text withheld
|
|
64
|
+
rather than paraphrased — evaluation never reads the text.
|
|
43
65
|
|
|
44
|
-
**Light definitions.**
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
`from_deg` exceeds its `to_deg` wraps through the bow. So the masthead light
|
|
48
|
-
is 247.5° to 112.5°, which is 225° of arc.
|
|
66
|
+
**Light definitions.** Rule 21's lights with colour, arc as a bearing range,
|
|
67
|
+
and Rule 22 range by length band. Bearings run clockwise from right ahead; an
|
|
68
|
+
arc whose `from_deg` exceeds its `to_deg` wraps through the bow.
|
|
49
69
|
|
|
50
70
|
**Facts.** Three orthogonal axes (`fact:propulsion`, `fact:activity`,
|
|
51
|
-
`fact:position`), a `fact:making_way` modifier
|
|
52
|
-
`
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
**Identifiers.** Two classes, with opposite requirements. Citation-derived ids
|
|
68
|
-
— paragraph paths and the entry ids built from them — carry no prefix, because
|
|
69
|
-
the path *is* the citation. Vocabulary ids do: `light:masthead`,
|
|
70
|
-
`fact:activity`, `activity:nuc`, `rel:in_lieu_of`. See
|
|
71
|
-
[`docs/identifiers.md`](docs/identifiers.md); coming from a 0.1.x release, see
|
|
72
|
-
[Migrating from 0.1.x](#migrating-from-01x).
|
|
71
|
+
`fact:position`), a `fact:making_way` modifier, and scalars such as
|
|
72
|
+
`fact:length_m`. There is deliberately no vessel-class field: under COLREGS
|
|
73
|
+
what a vessel *is* follows from what it is *doing*. A decode table maps
|
|
74
|
+
SignalK's `navigation.state` onto the axes and names what the flattening
|
|
75
|
+
loses.
|
|
76
|
+
|
|
77
|
+
**Applicability entries.** Each is a predicate over facts, a set of lights or
|
|
78
|
+
references to other entries, a modality, a citation, and a jurisdiction. Every
|
|
79
|
+
entry has an id (`25b`, `27a-mw`) a consumer can point at.
|
|
80
|
+
|
|
81
|
+
**Identifiers.** Citation-derived ids (paragraph paths, entry ids) carry no
|
|
82
|
+
prefix, because the path *is* the citation. Vocabulary ids do:
|
|
83
|
+
`light:masthead`, `fact:activity`, `activity:nuc`, `rel:in_lieu_of`. Every
|
|
84
|
+
identifier is immutable once published; retirements go through
|
|
85
|
+
[`data/deprecated-identifiers.json`](data/deprecated-identifiers.json). See
|
|
86
|
+
[`docs/identifiers.md`](docs/identifiers.md).
|
|
73
87
|
|
|
74
88
|
## Design
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
requirements and
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
- [`docs/requirements.md`](docs/requirements.md): the source of truth
|
|
81
|
-
- [`docs/adr/`](docs/adr/): decisions, with the reasoning that produced them
|
|
90
|
+
Requirements-first: sessions work against the numbered requirements in
|
|
91
|
+
[`docs/requirements.md`](docs/requirements.md) and decisions live in
|
|
92
|
+
[`docs/adr/`](docs/adr/) rather than being argued again. Four ideas carry
|
|
93
|
+
most of it.
|
|
82
94
|
|
|
83
|
-
|
|
95
|
+
**The paragraph is the unit.** Rule text, citations and composition all key
|
|
96
|
+
on the paragraph path. Citation unit and composition unit turn out to be the
|
|
97
|
+
same thing.
|
|
84
98
|
|
|
85
|
-
**
|
|
86
|
-
|
|
87
|
-
|
|
99
|
+
**Jurisdiction is a dimension, not a fork.** Every record carries a
|
|
100
|
+
`jurisdiction`: `intl`, or `<country-or-body>/<waters>` as a delta on it.
|
|
101
|
+
Entries a jurisdiction doesn't override are inherited, not restated.
|
|
88
102
|
|
|
89
|
-
**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
delta on `intl`; entries it doesn't override are inherited, not restated
|
|
93
|
-
(REQ-SCOPE-2/3). Geography that merely gates a rule inside one jurisdiction
|
|
94
|
-
(Great Lakes, Western Rivers) is an ordinary fact a predicate reads, not a
|
|
95
|
-
jurisdiction of its own (REQ-SCOPE-5).
|
|
103
|
+
**Predicates, not enumerations.** Gates are `fact:length_m < 7`, never a
|
|
104
|
+
pre-built list of configurations. Enumerated tables are where prior art
|
|
105
|
+
silently loses rules; a predicate cannot omit a case it was never asked about.
|
|
96
106
|
|
|
97
|
-
**
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
**Alternatives are first-class.** COLREGS routinely permits a choice: a
|
|
102
|
-
tricolor *in lieu of* separate sidelights, a torch *in lieu of* either. The data
|
|
103
|
-
carries every lawful option with its modality and gate, and picks none of them.
|
|
104
|
-
Selection belongs to the consumer.
|
|
107
|
+
**Alternatives are first-class.** A tricolor *in lieu of* separate sidelights,
|
|
108
|
+
a torch *in lieu of* either. The data carries every lawful option with its
|
|
109
|
+
modality and gate, and picks none of them.
|
|
105
110
|
|
|
106
111
|
## Predicate semantics
|
|
107
112
|
|
|
108
113
|
An entry applies when **every** constraint in its `when` is satisfied. An
|
|
109
|
-
absent fact never satisfies a constraint
|
|
110
|
-
|
|
111
|
-
`fact:activity: "activity:ram"` also matches `activity:ram_underwater`, which
|
|
112
|
-
is a refinement of it.
|
|
113
|
-
|
|
114
|
-
A `when` is a conjunction, and two constructs open it up. `{"not": C}` is a
|
|
115
|
-
constraint satisfied when the fact does *not* satisfy `C`; `any_of` is
|
|
116
|
-
disjunction, holding sub-predicates as a key of a `when` and constraints as the
|
|
117
|
-
value of a fact. **`not` over an absent fact is unsatisfied**, like every other
|
|
118
|
-
constraint over an absent fact — so `{"not": C}` and `C` are both false on a
|
|
119
|
-
record that never mentions the fact, and the two are not complements there. That
|
|
120
|
-
is deliberate: predicates stay conservative, and a duty is never laid on a vessel
|
|
121
|
-
because a consumer left a field out. It also means `not` is a constraint on one
|
|
122
|
-
fact and never a key of a `when` — a predicate-level negation would be satisfied
|
|
123
|
-
by silence, which is the one thing the absent-fact rule is there to forbid. Where
|
|
124
|
-
a paragraph really does mean "any vessel other than …", the negation goes on the
|
|
125
|
-
fact the paragraph names, and the fact has to be present for the entry to apply.
|
|
114
|
+
absent fact never satisfies a constraint, including `not`: a duty is never
|
|
115
|
+
laid on a vessel because a consumer left a field out.
|
|
126
116
|
|
|
127
117
|
| form | where | means |
|
|
128
118
|
|---|---|---|
|
|
@@ -133,94 +123,34 @@ fact the paragraph names, and the fact has to be present for the entry to apply.
|
|
|
133
123
|
| `{"any_of": [C, …]}` | a fact's constraint | the fact satisfies at least one `C` |
|
|
134
124
|
| `"any_of": [W, …]` | a key of a `when` | at least one sub-predicate `W` holds |
|
|
135
125
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
list quietly missed it; that is fixed, and a list and `{"any_of": […]}` are now
|
|
141
|
-
interchangeable wherever both are legal.
|
|
142
|
-
|
|
143
|
-
Some facts are **derived** rather than supplied. `facts.json`'s `derived`
|
|
144
|
-
section holds them, each with a decode table that is its definition — an ordered
|
|
145
|
-
list of predicate/value rows, first match wins — read the same way as the
|
|
146
|
-
SignalK `navigation.state` table. `fact:rule18_class` is the one that exists: a
|
|
147
|
-
vessel's rank under Rule 18, decoded from her propulsion, her activity and the
|
|
148
|
-
27(c) and WIG booleans, because Rule 18 ranks vessels by the Rule 3 terms of art
|
|
149
|
-
and `fact:activity` answers a different question — what she *shows*. A consumer
|
|
150
|
-
never supplies a derived fact.
|
|
151
|
-
|
|
152
|
-
Entries **compose**: several apply to one fact record, and Rule 28 or Rule 26
|
|
153
|
-
add to Rule 23 rather than replacing it. Relations between them:
|
|
126
|
+
Entries **compose**: several apply to one fact record, and Rule 26 adds to
|
|
127
|
+
Rule 23 rather than replacing it. A condition on whether a paragraph applies
|
|
128
|
+
at all goes in the predicate; a condition on which of two applicable
|
|
129
|
+
paragraphs prevails is a relation.
|
|
154
130
|
|
|
155
131
|
| relation | meaning |
|
|
156
132
|
|---|---|
|
|
157
133
|
| `rel:includes` | import the referenced entry's **lights only**, never its predicate |
|
|
158
134
|
| `rel:conditional_includes` | import lights when the stated `when` holds; `one_of` is a set of legal alternatives |
|
|
159
135
|
| `rel:in_lieu_of` | this entry's lights replace the referenced entries' lights |
|
|
160
|
-
| `rel:excludes` | must not be shown together: a pick-one between alternatives
|
|
136
|
+
| `rel:excludes` | must not be shown together: a pick-one between alternatives, never one obligation vetoing another |
|
|
161
137
|
| `rel:exempts` | the referenced requirement does not apply (30(e)) |
|
|
162
|
-
| `rel:overrides` |
|
|
163
|
-
|
|
164
|
-
A condition on whether a paragraph applies to the vessel at all goes in the
|
|
165
|
-
predicate; a condition on which of two applicable paragraphs prevails is a
|
|
166
|
-
relation. Delete the other paragraph: if this one is still true of the vessel,
|
|
167
|
-
it is a relation. Rule 28 at anchor is a predicate; Rule 18 displacing Rule 15's
|
|
168
|
-
role is `rel:overrides` (REQ-MODEL-13, ADR 0005 §4).
|
|
169
|
-
|
|
170
|
-
Where the rules permit a choice, the data keeps every lawful option instead of
|
|
171
|
-
picking one. A 12 m sloop under sail has three legal displays: 25(a), the
|
|
172
|
-
25(b) tricolor, or 25(a) plus the 25(c) red-over-green. Which one a given boat
|
|
173
|
-
shows depends on what's installed, and that decision belongs to the consumer.
|
|
138
|
+
| `rel:overrides` | this paragraph's requirement prevails over the referenced one's when both apply (Rule 18; Rule 26(a) over Rule 30's anchor lights) |
|
|
174
139
|
|
|
175
140
|
Modality is `shall`, `may`, `shall-if-practicable`, `shall-not`,
|
|
176
141
|
`shall-not-impede`, or `conditional` with a `modality_by` table when it turns
|
|
177
|
-
on a fact
|
|
178
|
-
|
|
179
|
-
Most entries read one vessel and produce lights.
|
|
180
|
-
situation
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
`pair:geo:in_sight`. A key with no subject means `own:`, so nothing above
|
|
190
|
-
changes. `docs/identifiers.md` has the namespace and the effect vocabulary;
|
|
191
|
-
`fixtures/situation-fixtures.json` is their contract.
|
|
192
|
-
|
|
193
|
-
The three encounter types **partition** relative bearing. 13(b)'s overtaking
|
|
194
|
-
sector is written once, as one constraint; Rule 15's crossing is `not` over
|
|
195
|
-
that same constraint and `not` over Rule 14's head-on cone, so no crossing
|
|
196
|
-
sector is enumerated anywhere and none can drift out of step. The suite sweeps
|
|
197
|
-
both vessels' bearings in half-degree steps and asserts that exactly one
|
|
198
|
-
encounter applies at every point, that 13(b)'s 22.5°-abaft-the-beam edge is
|
|
199
|
-
exclusive on both sides, and that Rule 13(d)'s latch holds the classification
|
|
200
|
-
at `overtaking` however far the bearing afterwards draws out. The numbers the
|
|
201
|
-
Rules do not state — what counts as an appreciable bearing change, how wide
|
|
202
|
-
"nearly reciprocal" is — are declared once in `facts.json` under
|
|
203
|
-
`situation.constants`, marked pencil, and read from there by every entry.
|
|
204
|
-
|
|
205
|
-
A situation can state geometry no two vessels can occupy, so the suite checks
|
|
206
|
-
every fixture that states its kinematics against them (REQ-VERIFY-8): the two
|
|
207
|
-
relative bearings must be two readings of one line of sight, positions must
|
|
208
|
-
reproduce range and bearing, and CPA, TCPA and bearing rate must be the ones
|
|
209
|
-
the headings and speeds give. The equations and tolerances are declared once in
|
|
210
|
-
`facts.json` under `situation.geometry.consistency`. The sweeps construct
|
|
211
|
-
situations that pass the same check, and the property that no two vessels are
|
|
212
|
-
both give-way is asserted over a sweep of steady-bearing geometries — where it
|
|
213
|
-
is a theorem — with the both-starboard geometry that breaks it pinned as one
|
|
214
|
-
the check rejects.
|
|
215
|
-
|
|
216
|
-
## What this package does not do
|
|
217
|
-
|
|
218
|
-
It does not infer anything. It is a pure function of the fact record. Deciding
|
|
219
|
-
*that* a vessel is making way, or fishing, or aground is somebody else's job.
|
|
220
|
-
Nothing here reads a sensor.
|
|
221
|
-
|
|
222
|
-
It does not select a single display. Where the rules offer alternatives, all of
|
|
223
|
-
them come back.
|
|
142
|
+
on a fact.
|
|
143
|
+
|
|
144
|
+
Most entries read one vessel and produce lights. The Part B entries read
|
|
145
|
+
**two**, a situation rather than a fact record, and produce an `effect`:
|
|
146
|
+
which section governs, which vessel gives way, whether the encounter is
|
|
147
|
+
`head-on`, `crossing` or `overtaking`. They address each vessel through a
|
|
148
|
+
subject segment (`own:fact:activity`, `other:fact:propulsion`,
|
|
149
|
+
`pair:geo:in_sight`); a key with no subject means `own:`. The encounter
|
|
150
|
+
sectors partition relative bearing, so no crossing sector is enumerated and
|
|
151
|
+
none can drift. [`docs/identifiers.md`](docs/identifiers.md) has the
|
|
152
|
+
vocabulary, [`docs/part-b-invariants.md`](docs/part-b-invariants.md) the
|
|
153
|
+
invariants, and `fixtures/situation-fixtures.json` is the contract.
|
|
224
154
|
|
|
225
155
|
## Verifying
|
|
226
156
|
|
|
@@ -230,124 +160,17 @@ npm test
|
|
|
230
160
|
|
|
231
161
|
Every fixture reproduces exactly; every citation, cross-reference, light and
|
|
232
162
|
geometry reference resolves; every image is on disk with its SHA-256 recorded;
|
|
233
|
-
every
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
at least one fixture and absent from at least one other (REQ-VERIFY-3). Three
|
|
245
|
-
gates that affect only *modality*, not which entries apply, are flagged as an
|
|
246
|
-
open question rather than fixtured against a schema that can't express the
|
|
247
|
-
distinction; see [Q-5](docs/requirements.md#9-open-questions).
|
|
248
|
-
|
|
249
|
-
`fixtures/applicability-fixtures.json` is the cross-implementation contract: an
|
|
250
|
-
implementation in any language should reproduce those entry sets exactly.
|
|
251
|
-
|
|
252
|
-
## Migrating from 0.1.x
|
|
253
|
-
|
|
254
|
-
0.2.0 is the first release whose vocabulary identifiers carry a type prefix.
|
|
255
|
-
`colregs@0.1.1`, the last version on npm, has the bare names; every 0.1.x
|
|
256
|
-
consumer holds strings that no longer resolve. Renaming an identifier is a
|
|
257
|
-
breaking change under REQ-PKG-4, and the rename is the one exception
|
|
258
|
-
REQ-MODEL-10 records: 0.1.1 predates the identifier audit, sits outside the
|
|
259
|
-
immutability baseline, and nothing after it may be renamed this way again.
|
|
260
|
-
|
|
261
|
-
**What did not change.** Paragraph paths (`27(a)(i)`) and entry ids (`25b`,
|
|
262
|
-
`27a-mw`) are citation-derived and stay bare. No entry id present in 0.1.1
|
|
263
|
-
is removed — the 40 entries of 0.1.1 are all in 0.2.0, with 30 more.
|
|
264
|
-
|
|
265
|
-
**What did.** Every light id, fact key, fact value and relation verb, in
|
|
266
|
-
every place it appears: `lights.json` keys, `facts.json` keys and `values`,
|
|
267
|
-
the `light` field of an entry's `lights[]`, the keys and values of an entry's
|
|
268
|
-
`when` and `modality_by[].when`, the relation keys on an entry
|
|
269
|
-
(`includes` → `rel:includes`, and so on), the `relations` map in
|
|
270
|
-
`applicability.json`, the `light` field in `geometry.json`, the
|
|
271
|
-
`signalk_navigation_state.decode` table, `actuable_subset.fields`, and the
|
|
272
|
-
`facts` record of every fixture. The rule is in
|
|
273
|
-
[`docs/identifiers.md`](docs/identifiers.md): a light is `light:<id>`, a
|
|
274
|
-
fact key is `fact:<key>`, a value of an enumerated fact is `<fact>:<value>`,
|
|
275
|
-
a relation is `rel:<name>`. The full table, generated from the two data
|
|
276
|
-
sets rather than from memory:
|
|
277
|
-
|
|
278
|
-
| kind | 0.1.1 | 0.2.0 |
|
|
279
|
-
|---|---|---|
|
|
280
|
-
| light id | `masthead` | `light:masthead` |
|
|
281
|
-
| light id | `sidelights` | `light:sidelights` |
|
|
282
|
-
| light id | `sidelight_starboard` | `light:sidelight_starboard` |
|
|
283
|
-
| light id | `sidelight_port` | `light:sidelight_port` |
|
|
284
|
-
| light id | `sternlight` | `light:sternlight` |
|
|
285
|
-
| light id | `towing` | `light:towing` |
|
|
286
|
-
| light id | `all_round` | `light:all_round` |
|
|
287
|
-
| light id | `flashing` | `light:flashing` |
|
|
288
|
-
| light id | `torch` | `light:torch` |
|
|
289
|
-
| light id | `deck_lights` | `light:deck_lights` |
|
|
290
|
-
| fact key | `propulsion` | `fact:propulsion` |
|
|
291
|
-
| value of propulsion | `power` | `propulsion:power` |
|
|
292
|
-
| value of propulsion | `sail` | `propulsion:sail` |
|
|
293
|
-
| value of propulsion | `oars` | `propulsion:oars` |
|
|
294
|
-
| fact key | `activity` | `fact:activity` |
|
|
295
|
-
| value of activity | `none` | `activity:none` |
|
|
296
|
-
| value of activity | `fishing` | `activity:fishing` |
|
|
297
|
-
| value of activity | `trawling` | `activity:trawling` |
|
|
298
|
-
| value of activity | `towing` | `activity:towing` |
|
|
299
|
-
| value of activity | `pushing` | `activity:pushing` |
|
|
300
|
-
| value of activity | `being_towed` | `activity:being_towed` |
|
|
301
|
-
| value of activity | `nuc` | `activity:nuc` |
|
|
302
|
-
| value of activity | `ram` | `activity:ram` |
|
|
303
|
-
| value of activity | `ram_underwater` | `activity:ram_underwater` |
|
|
304
|
-
| value of activity | `cbd` | `activity:cbd` |
|
|
305
|
-
| value of activity | `mine` | `activity:mine` |
|
|
306
|
-
| value of activity | `pilot` | `activity:pilot` |
|
|
307
|
-
| value of activity | `diving` | `activity:diving` |
|
|
308
|
-
| fact key | `position` | `fact:position` |
|
|
309
|
-
| value of position | `underway` | `position:underway` |
|
|
310
|
-
| value of position | `anchored` | `position:anchored` |
|
|
311
|
-
| value of position | `aground` | `position:aground` |
|
|
312
|
-
| value of position | `moored` | `position:moored` |
|
|
313
|
-
| fact key | `making_way` | `fact:making_way` |
|
|
314
|
-
| fact key | `length_m` | `fact:length_m` |
|
|
315
|
-
| fact key | `tow_length_m` | `fact:tow_length_m` |
|
|
316
|
-
| fact key | `max_speed_kn` | `fact:max_speed_kn` |
|
|
317
|
-
| fact key | `gear_extent_m` | `fact:gear_extent_m` |
|
|
318
|
-
| fact key | `beam_m` | `fact:beam_m` |
|
|
319
|
-
| fact key | `composite_unit` | `fact:composite_unit` |
|
|
320
|
-
| fact key | `non_displacement` | `fact:non_displacement` |
|
|
321
|
-
| fact key | `wig` | `fact:wig` |
|
|
322
|
-
| fact key | `wig_near_surface` | `fact:wig_near_surface` |
|
|
323
|
-
| fact key | `near_channel` | `fact:near_channel` |
|
|
324
|
-
| fact key | `inconspicuous_partly_submerged_tow` | `fact:inconspicuous_partly_submerged_tow` |
|
|
325
|
-
| fact key | `towed_alongside` | `fact:towed_alongside` |
|
|
326
|
-
| fact key | `obstruction_exists` | `fact:obstruction_exists` |
|
|
327
|
-
| fact key | `obstruction_side` | `fact:obstruction_side` |
|
|
328
|
-
| value of obstruction_side | `port` | `obstruction_side:port` |
|
|
329
|
-
| value of obstruction_side | `starboard` | `obstruction_side:starboard` |
|
|
330
|
-
| relation | `includes` | `rel:includes` |
|
|
331
|
-
| relation | `conditional_includes` | `rel:conditional_includes` |
|
|
332
|
-
| relation | `in_lieu_of` | `rel:in_lieu_of` |
|
|
333
|
-
| relation | `excludes` | `rel:excludes` |
|
|
334
|
-
| relation | `exempts` | `rel:exempts` |
|
|
335
|
-
|
|
336
|
-
The mapping is mechanical and total: strip nothing, prepend the namespace.
|
|
337
|
-
The one string that needed the prefix to disambiguate is `towing`, which in
|
|
338
|
-
0.1.1 was both a light id and an `activity` value; it is now `light:towing`
|
|
339
|
-
or `activity:towing` depending on which it was.
|
|
340
|
-
|
|
341
|
-
A consumer that builds a fact record from SignalK `navigation.state` gets
|
|
342
|
-
the new keys and values from the decode table for free. One that stored a
|
|
343
|
-
0.1.1 fact record, light id or relation name must rewrite it by the table
|
|
344
|
-
above; `fixtures/applicability-fixtures.json` is the check that the rewrite
|
|
345
|
-
came out right.
|
|
346
|
-
|
|
347
|
-
From 0.2.0 on, every identifier in the package is immutable once published
|
|
348
|
-
(REQ-MODEL-10). [`data/deprecated-identifiers.json`](data/deprecated-identifiers.json)
|
|
349
|
-
is the REQ-MODEL-11 registry a retired identifier goes into, and `npm test`
|
|
350
|
-
refuses a removal that is not recorded there. [`data/version.json`](data/version.json) mirrors `package.json`; release-please keeps it in sync (see [ADR 0009](docs/adr/0009-data-version-stamp.md)).
|
|
163
|
+
every fact a predicate reads is declared. A drift test cross-checks fact
|
|
164
|
+
record to lights and lights back to entries, and fails on any collision the
|
|
165
|
+
data doesn't declare through a relation. Every numeric gate has fixtures
|
|
166
|
+
either side of its threshold, and every entry is exercised by at least one
|
|
167
|
+
fixture and absent from another. The encounter sweeps assert that exactly one
|
|
168
|
+
encounter applies at every bearing, and that no steady-bearing geometry makes
|
|
169
|
+
both vessels give-way.
|
|
170
|
+
|
|
171
|
+
`fixtures/applicability-fixtures.json` and `fixtures/situation-fixtures.json`
|
|
172
|
+
are the cross-implementation contract: an implementation in any language
|
|
173
|
+
should reproduce those exactly.
|
|
351
174
|
|
|
352
175
|
## Provenance and licence
|
|
353
176
|
|
|
@@ -356,5 +179,5 @@ publications, public domain; see [PROVENANCE.md](PROVENANCE.md). The
|
|
|
356
179
|
compilation is Apache-2.0.
|
|
357
180
|
|
|
358
181
|
Not authoritative, not endorsed by the Coast Guard. Navigate by the published
|
|
359
|
-
rules.
|
|
360
|
-
|
|
182
|
+
rules. The `ca/inland` delta carries the same condition its licence does: it
|
|
183
|
+
must not be represented as an official version.
|
package/data/applicability.json
CHANGED
|
@@ -196,6 +196,7 @@
|
|
|
196
196
|
}
|
|
197
197
|
],
|
|
198
198
|
"images": [
|
|
199
|
+
"NRHB_23_a.png",
|
|
199
200
|
"NRHB_23_aii.png"
|
|
200
201
|
]
|
|
201
202
|
},
|
|
@@ -393,7 +394,7 @@
|
|
|
393
394
|
],
|
|
394
395
|
"modality": "shall",
|
|
395
396
|
"images": [
|
|
396
|
-
"
|
|
397
|
+
"NRHB_24_av.png"
|
|
397
398
|
]
|
|
398
399
|
},
|
|
399
400
|
{
|
|
@@ -952,7 +953,8 @@
|
|
|
952
953
|
],
|
|
953
954
|
"modality": "shall",
|
|
954
955
|
"images": [
|
|
955
|
-
"NRHB_27_d.png"
|
|
956
|
+
"NRHB_27_d.png",
|
|
957
|
+
"NRHB_27_diii.png"
|
|
956
958
|
],
|
|
957
959
|
"notes": "27(d)(iii): when at anchor these lights are shown instead of Rule 30's."
|
|
958
960
|
},
|
|
@@ -987,9 +989,6 @@
|
|
|
987
989
|
"27d"
|
|
988
990
|
],
|
|
989
991
|
"modality": "shall",
|
|
990
|
-
"images": [
|
|
991
|
-
"NRHB_27_ei.png"
|
|
992
|
-
],
|
|
993
992
|
"notes": "Only when the vessel's size makes the full 27(d) display impracticable."
|
|
994
993
|
},
|
|
995
994
|
{
|
|
@@ -1134,7 +1133,7 @@
|
|
|
1134
1133
|
],
|
|
1135
1134
|
"modality": "shall",
|
|
1136
1135
|
"images": [
|
|
1137
|
-
"
|
|
1136
|
+
"NRHB_30_d.png"
|
|
1138
1137
|
]
|
|
1139
1138
|
},
|
|
1140
1139
|
{
|
|
@@ -1158,7 +1157,10 @@
|
|
|
1158
1157
|
"rel:in_lieu_of": [
|
|
1159
1158
|
"30a"
|
|
1160
1159
|
],
|
|
1161
|
-
"modality": "may"
|
|
1160
|
+
"modality": "may",
|
|
1161
|
+
"images": [
|
|
1162
|
+
"NRHB_30_a.png"
|
|
1163
|
+
]
|
|
1162
1164
|
},
|
|
1163
1165
|
{
|
|
1164
1166
|
"id": "30c",
|
|
@@ -1232,7 +1234,7 @@
|
|
|
1232
1234
|
],
|
|
1233
1235
|
"modality": "shall-if-practicable",
|
|
1234
1236
|
"images": [
|
|
1235
|
-
"
|
|
1237
|
+
"NRHB_30_dii.png"
|
|
1236
1238
|
],
|
|
1237
1239
|
"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."
|
|
1238
1240
|
},
|
|
@@ -1654,7 +1656,8 @@
|
|
|
1654
1656
|
},
|
|
1655
1657
|
"pair:geo:tcpa_s": {
|
|
1656
1658
|
"gt": 0
|
|
1657
|
-
}
|
|
1659
|
+
},
|
|
1660
|
+
"other:hist:was_overtaking": false
|
|
1658
1661
|
},
|
|
1659
1662
|
{
|
|
1660
1663
|
"own:hist:was_overtaking": true
|
|
@@ -1683,7 +1686,7 @@
|
|
|
1683
1686
|
"12a2",
|
|
1684
1687
|
"12a3"
|
|
1685
1688
|
],
|
|
1686
|
-
"note": "Categorised `precedence`, not `classification` as ADR 0005 sec. 1 and the proposal's first-cut table have it. 13(a) is the one paragraph of Rule 13 that assigns a role, and a `classification` entry has no field to put a role in; 13(b)'s sector test is the classification and is what sets the latch. Q-14 settles membership paragraph by paragraph and this is one of them. The predicate now carries both halves of 'any vessel overtaking any other': the 13(b) sector, which 13b-overtaking classifies, and the 13(d) latch, which 13d classifies. They are a disjunction, which is what the entry could not write before the predicate language grew `any_of` (Q-33). Now also overrides the three Rule 12 entries: 'notwithstanding anything contained in' the Rules of Part B Sections I and II includes Rule 12, and two sailing vessels in an overtaking would otherwise hold 13(a)'s and 12(a)'s roles at once (Q-40).",
|
|
1689
|
+
"note": "Categorised `precedence`, not `classification` as ADR 0005 sec. 1 and the proposal's first-cut table have it. 13(a) is the one paragraph of Rule 13 that assigns a role, and a `classification` entry has no field to put a role in; 13(b)'s sector test is the classification and is what sets the latch. Q-14 settles membership paragraph by paragraph and this is one of them. The predicate now carries both halves of 'any vessel overtaking any other': the 13(b) sector, which 13b-overtaking classifies, and the 13(d) latch, which 13d classifies. They are a disjunction, which is what the entry could not write before the predicate language grew `any_of` (Q-33). Now also overrides the three Rule 12 entries: 'notwithstanding anything contained in' the Rules of Part B Sections I and II includes Rule 12, and two sailing vessels in an overtaking would otherwise hold 13(a)'s and 12(a)'s roles at once (Q-40). The sector branch now also reads `other:hist:was_overtaking: false`, so it cannot newly name a second give-way vessel while the other side already holds 13(d)'s latch -- once overtaking, always overtaking, on whichever vessel history says holds the role (Q-47).",
|
|
1687
1690
|
"gap": "Only own's side. 13(a) lays the duty on the overtaking vessel, so this entry is directional by design and the overtaken vessel's stand-on role comes from the same entry read on the swapped situation. What it still cannot say is 13(c) -- a vessel in any doubt as to whether she is overtaking shall assume that she is -- because doubt is a state of the observer and no fact carries it; and it inherits 13b-overtaking's speed-comparison gap. Q-41, Q-46."
|
|
1688
1691
|
},
|
|
1689
1692
|
{
|