colregs 0.1.1 → 0.2.2
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/LICENSE +194 -26
- package/PROVENANCE.md +45 -12
- package/README.md +222 -23
- package/data/applicability.json +1252 -190
- package/data/deprecated-identifiers.json +7 -0
- package/data/facts.json +556 -113
- package/data/geometry.json +33 -33
- package/data/images.json +51 -25
- package/data/lights.json +35 -35
- package/data/rules.json +787 -3
- package/docs/adr/0001-name-and-jurisdiction-model.md +119 -1
- package/docs/adr/0003-language-as-a-dimension.md +220 -0
- package/docs/adr/0004-licence-layering.md +78 -0
- package/docs/adr/0005-rule-categories-and-the-situation-record.md +323 -0
- package/docs/adr/0006-json-schema-and-identifier-diff.md +95 -0
- package/docs/adr/0007-rule26-overrides-and-aground.md +68 -0
- package/docs/adr/0008-mooring-buoy-modifier.md +87 -0
- package/docs/budgets.json +162 -0
- package/docs/conventions.md +27 -0
- package/docs/gates.json +84 -0
- package/docs/identifiers.md +435 -0
- package/docs/part-b-invariants.md +922 -0
- package/docs/requirements.md +1251 -23
- package/docs/verification/2026-08-30-q6-q8.md +278 -0
- package/docs/verification/2026-09-05-rule27f-rule28-anchor-scenarios.md +330 -0
- package/fixtures/applicability-fixtures.json +361 -227
- package/fixtures/situation-fixtures.json +3673 -0
- package/package.json +16 -4
- package/schema/applicability-fixtures.schema.json +49 -0
- package/schema/applicability.schema.json +401 -0
- package/schema/deprecated-identifiers.schema.json +29 -0
- package/schema/facts.schema.json +793 -0
- package/schema/geometry.schema.json +239 -0
- package/schema/images.schema.json +53 -0
- package/schema/lights.schema.json +131 -0
- package/schema/rules.schema.json +50 -0
- package/schema/situation-fixtures.schema.json +325 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# Identifiers
|
|
2
|
+
|
|
3
|
+
Every name the data is addressed by — paragraph path, entry id, light id,
|
|
4
|
+
fact key, fact value, relation name — is an identifier, and REQ-MODEL-10
|
|
5
|
+
makes identifiers immutable from the version stated there onward. This file
|
|
6
|
+
records what the identifiers are and why they are shaped the way they are,
|
|
7
|
+
so that the shape is a decision on file rather than an accident nobody can
|
|
8
|
+
now change.
|
|
9
|
+
|
|
10
|
+
Identifiers are schema keywords, not display strings. They are never
|
|
11
|
+
localized (REQ-LANG-2); translations attach to them.
|
|
12
|
+
|
|
13
|
+
## Two classes, opposite requirements
|
|
14
|
+
|
|
15
|
+
**Citation-derived identifiers carry no prefix.** A paragraph path *is* the
|
|
16
|
+
citation: `27(a)(i)` is what a mariner, a lawyer and a court all write, and
|
|
17
|
+
what a consumer stores when it records why a light was shown. Prefixing it
|
|
18
|
+
would put a package-local token in front of a reference that belongs to the
|
|
19
|
+
Convention rather than to this repository, and would make a stored citation
|
|
20
|
+
unreadable outside the tool that stored it. Entry ids are derived from
|
|
21
|
+
paragraph paths (below) and inherit the same transparency for the same
|
|
22
|
+
reason. Paragraph-keying is argued in ADR 0001 and required by
|
|
23
|
+
REQ-MODEL-4; nothing here reopens either.
|
|
24
|
+
|
|
25
|
+
**Vocabulary identifiers carry a type prefix.** These names are this
|
|
26
|
+
package's own — nothing in COLREGS calls anything `masthead` or `nuc`. They
|
|
27
|
+
share one flat string space across five files, and before the prefix they
|
|
28
|
+
collided in it: `towing` was simultaneously a light id (Rule 21(d)) and an
|
|
29
|
+
`activity` value (Rule 24(a)), so a consumer holding the string `towing`
|
|
30
|
+
could not say what it was a name *for* without knowing which field it came
|
|
31
|
+
out of. The prefix makes the namespace part of the identifier, which
|
|
32
|
+
resolves that collision by construction rather than by convention.
|
|
33
|
+
|
|
34
|
+
## The scheme
|
|
35
|
+
|
|
36
|
+
| form | class | examples |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `light:<id>` | light definitions (`data/lights.json`) | `light:masthead`, `light:sidelight_starboard`, `light:all_round` |
|
|
39
|
+
| `fact:<key>` | fact keys — the input vocabulary (`data/facts.json`) | `fact:activity`, `fact:length_m`, `fact:making_way`, `fact:on_mooring_buoy` |
|
|
40
|
+
| `<fact>:<value>` | values of an enumerated fact | `activity:nuc`, `position:anchored`, `propulsion:sail`, `obstruction_side:port` |
|
|
41
|
+
| `rel:<name>` | the five relation verbs (`data/applicability.json`) | `rel:includes`, `rel:in_lieu_of`, `rel:exempts` |
|
|
42
|
+
|
|
43
|
+
The prefix names the namespace the identifier lives in. For a fact *value*
|
|
44
|
+
that namespace is the fact itself, written bare: `activity:nuc`, not
|
|
45
|
+
`fact:activity:nuc`. A value is only ever meaningful against its own fact,
|
|
46
|
+
so naming the fact is what disambiguates it; naming the class as well would
|
|
47
|
+
add a segment that never varies.
|
|
48
|
+
|
|
49
|
+
**There is no version segment.** No `colregs.v1:activity:nuc`. A version in
|
|
50
|
+
the identifier churns every id at a major bump — including the ones that
|
|
51
|
+
did not change — which destroys exactly the stability REQ-MODEL-10 exists
|
|
52
|
+
to provide, and forces every consumer to rewrite stored references for
|
|
53
|
+
changes that did not affect them. Breaking changes are signalled by the
|
|
54
|
+
package version, which is where a consumer already looks.
|
|
55
|
+
|
|
56
|
+
Only enumerated facts have a value namespace. Numeric facts
|
|
57
|
+
(`fact:length_m`) take numbers and booleans (`fact:composite_unit`) take
|
|
58
|
+
`true`/`false`; there is nothing to prefix.
|
|
59
|
+
|
|
60
|
+
A two-subject predicate prefixes a **subject** segment onto the forms above
|
|
61
|
+
and adds three fact classes of its own (`kin:`, `geo:`, `hist:`). That is
|
|
62
|
+
pencil and is the next section.
|
|
63
|
+
|
|
64
|
+
## Two subjects `✎`
|
|
65
|
+
|
|
66
|
+
**Pencil** (`docs/conventions.md`): ADR 0005 puts the whole two-subject shape
|
|
67
|
+
in pencil and v0.x allows the break, so any session may change this section
|
|
68
|
+
for a better idea, logging the change. What would settle it: the first
|
|
69
|
+
two-subject entry — Rule 18 — actually being written against it. This
|
|
70
|
+
section answers `Q-28`.
|
|
71
|
+
|
|
72
|
+
A `display` entry reads one vessel. A `classification` or `precedence`
|
|
73
|
+
entry reads two, and needs to say *whose* `fact:activity` it means. The form
|
|
74
|
+
is three segments:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
<subject>:<class>:<key>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
| segment | values |
|
|
81
|
+
|---|---|
|
|
82
|
+
| subject | `own`, `other`, `pair` |
|
|
83
|
+
| class | `fact`, `kin`, `geo`, `hist` |
|
|
84
|
+
| key | the identifier as it already exists, or a new one in a new class |
|
|
85
|
+
|
|
86
|
+
`own:fact:activity`, `other:kin:heading_deg`, `pair:geo:in_sight`,
|
|
87
|
+
`own:hist:was_overtaking`.
|
|
88
|
+
|
|
89
|
+
**A key with no subject segment means `own:`.** This is the whole of the
|
|
90
|
+
backward-compatibility story and it is why the subject is a *prefix* rather
|
|
91
|
+
than a change to the fact keys. `fact:activity` still spells `fact:activity`
|
|
92
|
+
and still denotes what it always denoted, so every predicate in
|
|
93
|
+
`data/applicability.json`, every fixture in
|
|
94
|
+
`fixtures/applicability-fixtures.json` and every stored citation a consumer
|
|
95
|
+
holds stays correct unedited — `REQ-MODEL-10` is satisfied by construction
|
|
96
|
+
rather than by a migration. The alternative shapes were a suffix
|
|
97
|
+
(`fact:activity:own`), which buries the thing you are scanning for at the
|
|
98
|
+
end of a variable-length name, and per-subject fact keys
|
|
99
|
+
(`fact:own_activity`), which would double the fact vocabulary and repoint
|
|
100
|
+
nothing but would leave two names for one concept forever. Prefixing is the
|
|
101
|
+
only one of the three where the existing vocabulary is a strict subset of
|
|
102
|
+
the new one.
|
|
103
|
+
|
|
104
|
+
The cost, stated so nobody rediscovers it: `own`, `other` and `pair` are now
|
|
105
|
+
reserved at the head of the identifier space, and no fact, light or relation
|
|
106
|
+
may ever be named one of them. That is the price of a subject segment that
|
|
107
|
+
is not itself prefixed, and it is cheap — the three words are not candidate
|
|
108
|
+
names for anything this package models.
|
|
109
|
+
|
|
110
|
+
### The three subjects
|
|
111
|
+
|
|
112
|
+
`own` is the vessel the rule addresses; `other` is the vessel it is in an
|
|
113
|
+
encounter with. **`pair` is the encounter itself**, and it exists because
|
|
114
|
+
some facts belong to neither vessel: range is one number, not own's number
|
|
115
|
+
and the other's. Putting `geo:range_m` under both subjects would create two
|
|
116
|
+
identifiers for one quantity and a class of bug — the two disagreeing —
|
|
117
|
+
that has no meaning.
|
|
118
|
+
|
|
119
|
+
### Relative geometry, and why aspect is not an identifier
|
|
120
|
+
|
|
121
|
+
Geometry splits on whether the quantity is symmetric between the vessels:
|
|
122
|
+
|
|
123
|
+
| fact | subject | |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| `geo:rel_bearing_deg` | `own` / `other` | bearing of the *other* subject, clockwise from this subject's heading |
|
|
126
|
+
| `geo:range_m` | `pair` | |
|
|
127
|
+
| `geo:bearing_change_deg_min` | `pair` | Rule 7(d)(i)'s steady bearing |
|
|
128
|
+
| `geo:cpa_m`, `geo:tcpa_s` | `pair` | |
|
|
129
|
+
| `geo:in_sight` | `pair` | Rule 3(k), symmetric because the rule defines it that way |
|
|
130
|
+
|
|
131
|
+
The directional row is where the namespace earns its keep.
|
|
132
|
+
`own:geo:rel_bearing_deg` is relative bearing — where the other vessel is
|
|
133
|
+
off own's bow. `other:geo:rel_bearing_deg` is the same fact read from the
|
|
134
|
+
other side, which is **aspect**. So aspect gets no identifier of its own: it
|
|
135
|
+
is a subject swap, not a second fact. Rule 13(b)'s overtaking sector is then
|
|
136
|
+
`other:geo:rel_bearing_deg` in (112.5, 247.5) — own more than 22.5° abaft
|
|
137
|
+
the other vessel's beam — written once, in the units the rule itself uses.
|
|
138
|
+
Swapping `own` and `other` throughout a predicate reverses the encounter,
|
|
139
|
+
which is exactly the operation a `precedence` rule needs and the reason to
|
|
140
|
+
prefer a subject namespace over two parallel vocabularies.
|
|
141
|
+
|
|
142
|
+
The directional and the pair geometry are redundant with `kin:` wherever both
|
|
143
|
+
are stated, and a record can state a set no two vessels can occupy — two
|
|
144
|
+
bearings no pair of headings produces, a CPA the speeds do not give.
|
|
145
|
+
`facts.json` declares the equations that relate them under
|
|
146
|
+
`situation.geometry.consistency`, and the suite enforces them on every fixture
|
|
147
|
+
and on every situation it constructs (`REQ-VERIFY-8`, `Q-48`). That makes them
|
|
148
|
+
checked, not derived: a consumer with an ARPA solution still supplies them,
|
|
149
|
+
and a record that omits the kinematics is unchecked rather than wrong.
|
|
150
|
+
|
|
151
|
+
`kin:` is the kinematic class ADR 0005 introduces — `kin:position`,
|
|
152
|
+
`kin:heading_deg`, `kin:sog_kn`, `kin:rot_deg_min`, `kin:dynamics`. It takes
|
|
153
|
+
`own`/`other` only; there is no kinematic state of a pair. `kin:dynamics`
|
|
154
|
+
is an enumerated fact, so its values follow the bare-fact-name rule above:
|
|
155
|
+
`dynamics:tanker`, not `kin:dynamics:tanker`.
|
|
156
|
+
|
|
157
|
+
### History
|
|
158
|
+
|
|
159
|
+
Rule 13(d) is the reason history is a class and not a note. Once a vessel is
|
|
160
|
+
overtaking, a subsequent alteration of the bearing does not make her a
|
|
161
|
+
crossing vessel; the instantaneous geometry, read alone, says otherwise and
|
|
162
|
+
hands the duty to the wrong vessel. So the latch is a fact:
|
|
163
|
+
|
|
164
|
+
- `own:hist:was_overtaking` — this subject was, earlier in this encounter,
|
|
165
|
+
an overtaking vessel with respect to the other.
|
|
166
|
+
- `own:hist:latched_at_s` — how long ago that attached, for a `conduct`
|
|
167
|
+
monitor. A predicate at a point does not read it.
|
|
168
|
+
|
|
169
|
+
History is directional — it is *own* that was overtaking — so it takes a
|
|
170
|
+
subject segment like the fact record does, and never `pair`.
|
|
171
|
+
|
|
172
|
+
### What this does not do
|
|
173
|
+
|
|
174
|
+
It does not version an identifier, and it does not repoint one. Everything
|
|
175
|
+
above is additive: new segments, new classes, new keys. No existing
|
|
176
|
+
identifier changes its spelling or its meaning, which is the property
|
|
177
|
+
`REQ-MODEL-10` protects and the one an alternative that renamed the fact
|
|
178
|
+
keys would have broken.
|
|
179
|
+
|
|
180
|
+
## Effects `✎`
|
|
181
|
+
|
|
182
|
+
**Pencil** (`docs/conventions.md`): ADR 0005 puts the whole two-subject shape
|
|
183
|
+
there. What would settle it: a second family of `precedence` paragraphs —
|
|
184
|
+
Rules 12, 14 and 15 — written against it. **Written, and it held with one
|
|
185
|
+
addition**: Rules 7(d) and 13–15 are the first `classification` entries, and a
|
|
186
|
+
classification produces neither a role nor a section, so the table below grows
|
|
187
|
+
a third row. Rule 12 turned out to be `precedence` and not `classification`
|
|
188
|
+
(below). This section answers the data half of `Q-27` and is required by
|
|
189
|
+
`REQ-CAT-8`.
|
|
190
|
+
|
|
191
|
+
A `display` entry produces `lights`. A `scope` or `precedence` entry produces
|
|
192
|
+
an **effect**, and the shape of the effect is fixed by the category:
|
|
193
|
+
|
|
194
|
+
| category | effect |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `scope` | `{"part", "section", "applies_rules"}` — which section of which Part governs, and the rules it contains |
|
|
197
|
+
| `precedence` | `{"own": <role>, "other": <role>}` — one role per subject |
|
|
198
|
+
| `classification` | `{"encounter": <encounter>}` **or** `{"risk_of_collision": true}` — exactly one key |
|
|
199
|
+
|
|
200
|
+
Five roles, a closed set: `give-way`, `stand-on`, `shall-not-impede`,
|
|
201
|
+
`keep-clear`, `none`. They are declared in `data/applicability.json` under
|
|
202
|
+
`effects`, and they are **not identifiers** — like modality and jurisdiction
|
|
203
|
+
values they are a closed vocabulary of their own, outside what `REQ-MODEL-10`
|
|
204
|
+
binds.
|
|
205
|
+
|
|
206
|
+
### Encounters, and why a classification effect has two shapes
|
|
207
|
+
|
|
208
|
+
Four encounters, a closed set like the roles: `head-on` (Rule 14), `crossing`
|
|
209
|
+
(Rule 15), `overtaking` (Rule 13) and `none`. They are declared in
|
|
210
|
+
`data/applicability.json` under `effects.encounters` and, like the roles, they
|
|
211
|
+
are not identifiers.
|
|
212
|
+
|
|
213
|
+
A `classification` effect carries **exactly one key**, and which key it is
|
|
214
|
+
depends on which question the paragraph answers. Rule 7(d)(i) answers *does
|
|
215
|
+
risk of collision exist* and produces `{"risk_of_collision": true}`; Rules 13,
|
|
216
|
+
14 and 15 answer *what kind of encounter is this* and produce an `encounter`.
|
|
217
|
+
ADR 0005 gives both questions to `classification` — "relative geometry,
|
|
218
|
+
history → encounter type, risk of collision" — and the two do not merge. A
|
|
219
|
+
single shape would have made every encounter entry state a risk it does not
|
|
220
|
+
decide, and 15(a)'s crossing test reads `pair:geo:risk_of_collision` as an
|
|
221
|
+
input rather than producing it.
|
|
222
|
+
|
|
223
|
+
There is no `{"risk_of_collision": false}` and there never will be. 7(a) makes
|
|
224
|
+
risk a judgement on all available means and deems it to exist in any doubt, so
|
|
225
|
+
an entry can add a ground for risk and nothing in this package can deny one.
|
|
226
|
+
`none` is declared as an encounter for the completeness of the vocabulary and
|
|
227
|
+
no entry produces it: an encounter type is asserted by a paragraph, and the
|
|
228
|
+
absence of one is the absence of an entry rather than an entry with a null
|
|
229
|
+
value.
|
|
230
|
+
|
|
231
|
+
**The three encounter types partition relative bearing, and the data is
|
|
232
|
+
written so that they cannot stop.** 13(b)'s sector is one constraint object,
|
|
233
|
+
`{"gt": 112.5, "lt": 247.5}`; 15(a)'s residual is `not` over that same object,
|
|
234
|
+
and 14(b)'s cone is negated the same way inside an `any_of`. Nothing writes a
|
|
235
|
+
crossing sector. The consequence is that the only way to put a bearing in two
|
|
236
|
+
encounters or in none is to edit one of two constraints and not the other, and
|
|
237
|
+
there is exactly one of each to edit. `test/data.test.mjs` sweeps both
|
|
238
|
+
subjects' bearings in half-degree steps and asserts exactly one encounter at
|
|
239
|
+
each of the 518 400 points; the Alloy version of the same property lives in
|
|
240
|
+
`colregs-engine`.
|
|
241
|
+
|
|
242
|
+
### Rule 12 is `precedence`, not `classification`
|
|
243
|
+
|
|
244
|
+
ADR 0005 §1 and the proposal's first-cut table file Rule 12 under
|
|
245
|
+
`classification`. It is `precedence` here, for the reason `Q-37` gives for
|
|
246
|
+
13(a): **12(a) produces a role, and a classification effect has nowhere to put
|
|
247
|
+
one.** "One of them shall keep out of the way of the other" is give-way and
|
|
248
|
+
stand-on in the effect vocabulary that already exists, and it is not an
|
|
249
|
+
encounter type — two sailing vessels meeting are still in a head-on, a
|
|
250
|
+
crossing or an overtaking, and Rule 12 says which of them gives way rather
|
|
251
|
+
than which kind of meeting it is. Rule 12 has no deeming paragraph at all:
|
|
252
|
+
12(b) defines the windward side and is a `definition`, so it is the cite on the
|
|
253
|
+
`kin:wind_side` fact rather than an entry.
|
|
254
|
+
|
|
255
|
+
The category is `Q-14`'s to settle paragraph by paragraph and this is two more
|
|
256
|
+
of them; the departure from the table is recorded in ADR 0005's pencil log and
|
|
257
|
+
in `Q-40`.
|
|
258
|
+
|
|
259
|
+
**Who governs over Rule 12.** 12(a)'s subjects are "two sailing vessels",
|
|
260
|
+
which is 3(c), so `12a1`–`12a3` gate on `fact:propulsion` and not on the Rule
|
|
261
|
+
18 rank — a fishing vessel under sail is a sailing vessel. Where Rule 18 also
|
|
262
|
+
ranks the pair, its entry displaces Rule 12's: `18b1`–`18b3` and `18c1`–`18c2`
|
|
263
|
+
carry `rel:overrides` against all three, because Rule 18's opening words
|
|
264
|
+
except Rules 9, 10 and 13 and nothing else. `13a` overrides them for the same
|
|
265
|
+
reason it overrides Rule 18 — 13(a) is "notwithstanding" the rest of Sections
|
|
266
|
+
I and II. The test that pins the relation asserts both reasons from
|
|
267
|
+
`rules.json`, so the data cannot keep an override after losing the words.
|
|
268
|
+
|
|
269
|
+
**And over Rule 15, the same way.** 15(a)'s subjects are "two power-driven
|
|
270
|
+
vessels", which is 3(b), so `15a-give-way` gates on `fact:propulsion` and on
|
|
271
|
+
no Rule 18 rank either — a vessel engaged in fishing, or not under command,
|
|
272
|
+
whose machinery is in use is a power-driven vessel. It used to negate the four
|
|
273
|
+
ranks in its own predicate, which said the same thing in the one place a test
|
|
274
|
+
could not see the reason; `18a1`–`18a3`, `18c1`–`18c2` and `18f1` now carry
|
|
275
|
+
`rel:overrides` against it instead. The derived half of the test is what makes
|
|
276
|
+
that checkable: a Rule 18 entry meets Rule 15 when it assigns a helm role and
|
|
277
|
+
neither subject is gated to a sailing vessel, and every such entry must carry
|
|
278
|
+
the override, so a Rule 18 paragraph added later cannot join Rule 15 silently.
|
|
279
|
+
|
|
280
|
+
**The effect names both subjects, and that is the point.** A `precedence`
|
|
281
|
+
entry is evaluated from own's side, so 18(a)(i) says own gives way *and* the
|
|
282
|
+
other vessel stands on. Writing only own's half would lose Rule 17, which
|
|
283
|
+
attaches to the counterpart of a give-way duty and to nothing else. So
|
|
284
|
+
`stand-on` appears only opposite `give-way`, and the counterpart of
|
|
285
|
+
`shall-not-impede` is always `none` — that is 8(f)(iii) in the data: a vessel
|
|
286
|
+
whose passage is not to be impeded acquires no privilege by it. `none` is
|
|
287
|
+
written rather than omitted, because a norm that confers nothing on a subject
|
|
288
|
+
is a finding and not an absence: NUC against RAM is `none` on both sides, and
|
|
289
|
+
that is Rule 18's partial order rather than a gap in the table.
|
|
290
|
+
|
|
291
|
+
`keep-clear` is one role for the two duties 18(e) and 18(f)(i) impose together
|
|
292
|
+
— keep well clear, and avoid impeding navigation. The vocabulary cannot
|
|
293
|
+
separate them and does not pretend to.
|
|
294
|
+
|
|
295
|
+
### Two-subject entry ids
|
|
296
|
+
|
|
297
|
+
Entry ids stay citation-derived, exactly as below: `18a1` is 18(a)(i), `9c` is
|
|
298
|
+
9(c), `8f3` is 8(f)(iii). Where a paragraph's subject is disjunctive — 9(b) is
|
|
299
|
+
"a vessel of less than 20 metres in length **or** a sailing vessel", and a
|
|
300
|
+
`when` is a conjunction — the paragraph takes two entries and the suffix names
|
|
301
|
+
the half: `9b-small` and `9b-sail`, `10j-small` and `10j-sail`. That is the
|
|
302
|
+
same rule the `-m2`/`-mw`/`-anc` suffixes below follow: name what
|
|
303
|
+
distinguishes them, in terms a reader with the rule text in front of them can
|
|
304
|
+
find.
|
|
305
|
+
|
|
306
|
+
## Entry ids
|
|
307
|
+
|
|
308
|
+
An entry id is derived from the paragraph path its entry cites, lowercased
|
|
309
|
+
with the parentheses dropped and roman sub-paragraph numerals written as
|
|
310
|
+
arabic digits:
|
|
311
|
+
|
|
312
|
+
| paragraph path | entry id |
|
|
313
|
+
|---|---|
|
|
314
|
+
| Rule 28 (one paragraph) | `28` |
|
|
315
|
+
| `23(b)` | `23b` |
|
|
316
|
+
| `25(d)(ii)` | `25d2` |
|
|
317
|
+
| `23(a)(iii)`–`(iv)`, one entry | `23a34` |
|
|
318
|
+
|
|
319
|
+
Where one paragraph produces more than one entry, a hyphenated suffix names
|
|
320
|
+
what distinguishes them. The suffixes are **not** drawn from a single
|
|
321
|
+
scheme, because the paragraphs they split do not divide on a single axis:
|
|
322
|
+
|
|
323
|
+
| suffix | means | example |
|
|
324
|
+
|---|---|---|
|
|
325
|
+
| `-m2` / `-m3` | two or three masthead lights | `24a-m2`, `24a-m3` |
|
|
326
|
+
| `-rest` | the remainder of the rule's requirements once the split ones are taken out | `24a-rest` |
|
|
327
|
+
| `-id` | the identity lights: the all-round group that says *what the vessel is* | `26b-id`, `27a-id`, `27b-id` |
|
|
328
|
+
| `-mast` | the masthead light the paragraph adds on top of the identity lights | `26b-mast` |
|
|
329
|
+
| `-mw` | the making-way half of a rule that lights differently when moving through the water | `26b-mw`, `27a-mw`, `27b-mw` |
|
|
330
|
+
| `-gear` | the light indicating the direction of outlying gear | `26c-gear` |
|
|
331
|
+
| `-anc` | the at-anchor branch | `27b-anc` |
|
|
332
|
+
| `-anchor` / `-red` | 30(d)'s two halves: the anchor lights it requires, and the two red all-round lights of a vessel aground | `30d-anchor`, `30d-red` |
|
|
333
|
+
|
|
334
|
+
This was reviewed and kept as it stands. The alternative — a uniform
|
|
335
|
+
ordinal suffix, `27a-1` / `27a-2` — would be self-consistent and completely
|
|
336
|
+
opaque: it tells a reader with the rule text in front of them nothing, in
|
|
337
|
+
exchange for no gain to a machine, which only ever compares entry ids for
|
|
338
|
+
equality. `24a-m2` / `24a-m3` are worth calling out in particular, because
|
|
339
|
+
the two-or-three masthead split is stated in 24(a)(i) itself — the
|
|
340
|
+
cardinality is in the law, not a modelling convenience of this package, and
|
|
341
|
+
the suffix names something the reader can go and find.
|
|
342
|
+
|
|
343
|
+
## Derived facts
|
|
344
|
+
|
|
345
|
+
A derived fact is one this package computes from the fact record rather than
|
|
346
|
+
asking a consumer for. It is an identifier like any other and takes the same
|
|
347
|
+
two forms as everything above: `fact:<key>` for the key, `<key>:<value>` for
|
|
348
|
+
its values. `fact:rule18_class` therefore takes `rule18_class:nuc`,
|
|
349
|
+
`rule18_class:sail` and so on — **not** `class:nuc`. The bare-fact-name rule
|
|
350
|
+
is what makes a value readable on its own: `class:nuc` would say which
|
|
351
|
+
namespace a reader is in only if they already knew, and `class` is exactly the
|
|
352
|
+
kind of word that a second derived fact would want too. The verbosity is the
|
|
353
|
+
price of the value being self-identifying, which is the same trade the whole
|
|
354
|
+
scheme makes.
|
|
355
|
+
|
|
356
|
+
Being derived is a property of the fact, not of its name. There is no `derived:`
|
|
357
|
+
prefix and no naming convention that marks one, because whether a consumer
|
|
358
|
+
supplies a fact or an evaluator computes it is a question about the pipeline
|
|
359
|
+
rather than about what the name denotes — and a fact that becomes derivable
|
|
360
|
+
later must not have to be renamed for it, which is exactly what `REQ-MODEL-10`
|
|
361
|
+
forbids. `facts.json` says so in a field instead: `derived: true`, beside a
|
|
362
|
+
decode table that is the definition.
|
|
363
|
+
|
|
364
|
+
## Terms of art kept unspelled
|
|
365
|
+
|
|
366
|
+
Four `activity` values are abbreviations rather than words, and stay that
|
|
367
|
+
way:
|
|
368
|
+
|
|
369
|
+
| value | expansion | Rule |
|
|
370
|
+
|---|---|---|
|
|
371
|
+
| `activity:nuc` | not under command | 3(f) |
|
|
372
|
+
| `activity:ram` | restricted in her ability to manoeuvre | 3(g) |
|
|
373
|
+
| `activity:ram_underwater` | restricted in her ability to manoeuvre, dredging or engaged in underwater operations | 27(d) |
|
|
374
|
+
| `activity:cbd` | constrained by her draught | 3(h) |
|
|
375
|
+
|
|
376
|
+
These are the standard abbreviations in the field: they are what appears on
|
|
377
|
+
an AIS display, in a SignalK `navigation.state` value, and in a mariner's
|
|
378
|
+
own speech. Spelling them out would produce `activity:not_under_command`,
|
|
379
|
+
which is longer, no clearer to the audience that reads them, and further
|
|
380
|
+
from the vocabulary the consumers already use.
|
|
381
|
+
|
|
382
|
+
**`ram` is a trap and is named here so nobody has to discover it.** In this
|
|
383
|
+
dataset `ram` is *restricted in her ability to manoeuvre*. It is not the
|
|
384
|
+
English verb, and this is a dataset about vessels colliding. Anyone reading
|
|
385
|
+
`activity:ram` as a collision is reading a rule about a dredger as a rule
|
|
386
|
+
about an impact. The prefix helps — `activity:ram` reads as a status, where
|
|
387
|
+
bare `ram` read as an event — but the expansion is written down here
|
|
388
|
+
because a prefix cannot carry a definition.
|
|
389
|
+
|
|
390
|
+
`activity:ram_underwater` is a **refinement** of `activity:ram`, not a peer
|
|
391
|
+
of it: a predicate written for `activity:ram` also matches it. That is
|
|
392
|
+
implemented in the reference evaluator and asserted by the fixtures.
|
|
393
|
+
|
|
394
|
+
## What is not an identifier
|
|
395
|
+
|
|
396
|
+
- **Modality values** (`shall`, `may`, `shall-if-practicable`,
|
|
397
|
+
`conditional`, `exempt`) and **jurisdiction values** (`intl`,
|
|
398
|
+
`us/inland`) are their own closed vocabularies, defined in §2 of the
|
|
399
|
+
requirements and not part of the identifier space REQ-MODEL-10 binds. So are
|
|
400
|
+
the **role** and **encounter** values of an effect.
|
|
401
|
+
- **Constants** — `situation.constants` in `data/facts.json`: the numbers a
|
|
402
|
+
Part B predicate needs and the Rules do not always give
|
|
403
|
+
(`appreciable_bearing_change_deg_min`, `head_on_half_angle_deg`, the two
|
|
404
|
+
`overtaking_sector_*_deg`). They are values, like a modality, and they are
|
|
405
|
+
named rather than written into a predicate so that the number appears once
|
|
406
|
+
and a test can assert that every entry reads it. Each carries its status
|
|
407
|
+
under `docs/conventions.md`, and a pencilled one carries what would settle
|
|
408
|
+
it.
|
|
409
|
+
- **Shape keys** — `when`, `one_of`, `cite`, `lights`, the predicate
|
|
410
|
+
language's `not` and `any_of`, and the SignalK decode table's
|
|
411
|
+
`also_activity` and `annex_ii_signal` — are JSON structure, not names the
|
|
412
|
+
data is addressed by. Only the values inside them can be identifiers, and
|
|
413
|
+
where they are (`also_activity` holds an activity value) they are prefixed.
|
|
414
|
+
`not` and `any_of` are the second pair of words reserved at the head of an
|
|
415
|
+
identifier space, after `own`/`other`/`pair`: they appear where a fact key
|
|
416
|
+
appears, so no fact may ever be named either. The cost is the same and as
|
|
417
|
+
cheap — every fact key carries a class prefix (`fact:`, `geo:`, `kin:`,
|
|
418
|
+
`hist:`, `env:`) and neither word could be one.
|
|
419
|
+
- **Prose fields** — `geometry.json`'s `datum` ("hull", "gunwale",
|
|
420
|
+
"forward masthead light") describes where a measurement is taken from in
|
|
421
|
+
words. It is deliberately not a light reference and does not resolve to
|
|
422
|
+
one.
|
|
423
|
+
|
|
424
|
+
## This does not reverse GATE-5
|
|
425
|
+
|
|
426
|
+
GATE-5 declined a CI-enforced terminology glossary, permanently, for the
|
|
427
|
+
**legal corpora**: rule text is verbatim (REQ-MODEL-1), so a glossary that
|
|
428
|
+
disagreed with the source would be a defect in the glossary, and enforcing
|
|
429
|
+
consistent terminology across a transcription means corrupting it.
|
|
430
|
+
|
|
431
|
+
Nothing in this file is transcribed from a source. `light:masthead`,
|
|
432
|
+
`activity:nuc` and `rel:in_lieu_of` are names this package invented for its
|
|
433
|
+
own structures; COLREGS contains none of them. Documenting a vocabulary you
|
|
434
|
+
authored is not the same act as imposing one on a text you did not, and the
|
|
435
|
+
reasoning that closed GATE-5 does not reach it. GATE-5 stays declined.
|