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.
Files changed (37) hide show
  1. package/LICENSE +194 -26
  2. package/PROVENANCE.md +45 -12
  3. package/README.md +222 -23
  4. package/data/applicability.json +1252 -190
  5. package/data/deprecated-identifiers.json +7 -0
  6. package/data/facts.json +556 -113
  7. package/data/geometry.json +33 -33
  8. package/data/images.json +51 -25
  9. package/data/lights.json +35 -35
  10. package/data/rules.json +787 -3
  11. package/docs/adr/0001-name-and-jurisdiction-model.md +119 -1
  12. package/docs/adr/0003-language-as-a-dimension.md +220 -0
  13. package/docs/adr/0004-licence-layering.md +78 -0
  14. package/docs/adr/0005-rule-categories-and-the-situation-record.md +323 -0
  15. package/docs/adr/0006-json-schema-and-identifier-diff.md +95 -0
  16. package/docs/adr/0007-rule26-overrides-and-aground.md +68 -0
  17. package/docs/adr/0008-mooring-buoy-modifier.md +87 -0
  18. package/docs/budgets.json +162 -0
  19. package/docs/conventions.md +27 -0
  20. package/docs/gates.json +84 -0
  21. package/docs/identifiers.md +435 -0
  22. package/docs/part-b-invariants.md +922 -0
  23. package/docs/requirements.md +1251 -23
  24. package/docs/verification/2026-08-30-q6-q8.md +278 -0
  25. package/docs/verification/2026-09-05-rule27f-rule28-anchor-scenarios.md +330 -0
  26. package/fixtures/applicability-fixtures.json +361 -227
  27. package/fixtures/situation-fixtures.json +3673 -0
  28. package/package.json +16 -4
  29. package/schema/applicability-fixtures.schema.json +49 -0
  30. package/schema/applicability.schema.json +401 -0
  31. package/schema/deprecated-identifiers.schema.json +29 -0
  32. package/schema/facts.schema.json +793 -0
  33. package/schema/geometry.schema.json +239 -0
  34. package/schema/images.schema.json +53 -0
  35. package/schema/lights.schema.json +131 -0
  36. package/schema/rules.schema.json +50 -0
  37. package/schema/situation-fixtures.schema.json +325 -0
@@ -7,6 +7,15 @@ Requirement IDs are stable and never reused. If a requirement is dropped it is
7
7
  struck through and kept, not deleted — a spec whose IDs shift silently cannot
8
8
  be cited by a test.
9
9
 
10
+ A requirement marked **(unimplemented)** is specified but not yet built, and
11
+ nothing in the repository satisfies it today; **(unimplemented in part)**
12
+ names the clause that is outstanding. Either way it is still binding; the
13
+ marker exists so the document cannot be read as a description of what ships.
14
+ Requirements that are pure prohibitions, or constraints on a future addition
15
+ that has not happened, carry no marker — there is nothing to
16
+ implement until something tries to violate them. Gate status is not marked in
17
+ prose at all: it is data, in `docs/gates.json`.
18
+
10
19
  Language: **MUST** / **SHOULD** / **MAY** in the RFC 2119 sense.
11
20
 
12
21
  ---
@@ -47,6 +56,7 @@ Neither consumer lives in this repo.
47
56
  | **modality** | `shall` / `may` / `shall-if-practicable`. |
48
57
  | **jurisdiction** | A body of rules: `intl`, `us/inland`, `ca/inland`, … |
49
58
  | **delta** | A jurisdiction's departures from the international text. |
59
+ | **identifier** | Any name the data is addressed by: entry id, paragraph path, light id, fact key, fact value, relation name. |
50
60
 
51
61
  ---
52
62
 
@@ -61,7 +71,14 @@ Neither consumer lives in this repo.
61
71
  `ca/inland`, `de/binnen`, `eu/cevni`.
62
72
  - **REQ-SCOPE-3** — A jurisdiction MUST be expressible as a *delta*: entries
63
73
  absent from a jurisdiction's data inherit from `intl`. A jurisdiction MUST
64
- NOT require restating the whole body of rules.
74
+ NOT require restating the whole body of rules. Inheritance is "unless
75
+ suppressed", not unconditional — see Q-11: verified Inland structure
76
+ (Rule 28 "[Reserved]") means silence-means-inherit would apply
77
+ international law where the national body deliberately has none, so no
78
+ non-`intl` jurisdiction lands before an explicit suppression mechanism
79
+ exists. A delta that only *adds* entries is exempt: it suppresses nothing,
80
+ so the Q-11 hazard cannot arise from it (ADR 0008, `30a-buoy`/`30b-buoy`).
81
+ A delta that suppresses or replaces an `intl` entry still waits.
65
82
  - **REQ-SCOPE-4** — Adding a jurisdiction MUST be additive. It MUST NOT require
66
83
  a schema change or edits to existing `intl` entries.
67
84
  - **REQ-SCOPE-5** — Geography that gates a rule (Great Lakes, Western Rivers,
@@ -78,16 +95,25 @@ Part C (Rules 20–31, lights and shapes) is v1. The structure MUST accommodate
78
95
  the rest without redesign.
79
96
 
80
97
  - **REQ-PART-1** — Part C lights MUST be complete for `intl` before any other
81
- part or jurisdiction is added.
98
+ part or jurisdiction is added, except a purely additive jurisdiction delta
99
+ recorded in an ADR — one that adds entries and edits or suppresses none
100
+ (ADR 0008). Such a delta is not a claim to model that jurisdiction, and
101
+ REQ-SCOPE-6's coverage statement MUST say what it does and does not cover.
82
102
  - **REQ-PART-2** — Day shapes MUST use the same entry model as lights, differing
83
103
  only in the fixture vocabulary they emit.
84
104
  - **REQ-PART-3** — Sound and light signals (Part D, Rules 32–37) SHOULD be
85
105
  representable by the same entry model. Where they are not — signals are
86
106
  event-triggered rather than state-derived — the divergence MUST be recorded
87
107
  as an ADR before any Part D data is written.
88
- - **REQ-PART-4** — Steering and sailing rules (Part B) are OUT of v1 scope and
108
+ - **REQ-PART-4** — ~~Steering and sailing rules (Part B) are OUT of v1 scope and
89
109
  MAY never be modelled; they govern conduct between two vessels, not the
90
- appearance of one, and the fact record is single-vessel by construction.
110
+ appearance of one, and the fact record is single-vessel by construction.~~
111
+ **Superseded by ADR 0005** (2026-09-04), and kept here rather than deleted
112
+ per the preamble's ID-stability rule. Part B remains out of v1 scope —
113
+ REQ-PART-1 still orders Part C first, and no Part B data lands with the
114
+ ADR — but "MAY never be modelled" does not survive: the obstacle it named,
115
+ a single-vessel fact record, is met by the situation record of REQ-CAT-4
116
+ without changing that record. Replaced by REQ-CAT-1..5 (§4.1).
91
117
 
92
118
  ---
93
119
 
@@ -103,36 +129,383 @@ Four layers, each independently addressable.
103
129
  add definitions (e.g. the US special flashing light, Inland 21(g)).
104
130
  - **REQ-MODEL-3** — **Facts**: the input vocabulary. Three orthogonal axes MUST
105
131
  be used, never a single flattened status enum:
106
- - `propulsion` ∈ power / sail / oars
107
- - `activity` ∈ none / fishing / trawling / towing / pushing / being-towed /
108
- nuc / ram / cbd / mine / pilot / diving
109
- - `position` ∈ underway / anchored / aground / moored
110
- plus `making_way` as a boolean refining `position=underway`, and numeric and
111
- boolean facts (`length_m`, `tow_length_m`, `max_speed_kn`, `composite_unit`,
112
- and the education-only facts).
132
+ - `fact:propulsion` ∈ `propulsion:power` / `propulsion:sail` /
133
+ `propulsion:oars`
134
+ - `fact:activity` `activity:none` / `activity:fishing` /
135
+ `activity:trawling` / `activity:towing` / `activity:pushing` /
136
+ `activity:being_towed` / `activity:nuc` / `activity:ram` /
137
+ `activity:ram_underwater` / `activity:cbd` / `activity:mine` /
138
+ `activity:pilot` / `activity:diving`
139
+ - `fact:position` ∈ `position:underway` / `position:anchored` /
140
+ `position:aground` / `position:moored`
141
+ plus `fact:making_way` as a boolean refining `fact:position=position:underway`
142
+ and `fact:on_mooring_buoy` as a boolean refining
143
+ `fact:position=position:moored` — made fast to a buoy, not to the shore;
144
+ the Convention prescribes lights for neither, and only a jurisdiction that
145
+ deems her at anchor reads it (ADR 0008) — and numeric and boolean facts (`fact:length_m`, `fact:tow_length_m`,
146
+ `fact:max_speed_kn`, `fact:composite_unit`, and the education-only facts).
147
+ Fact keys, and the values of the enumerated facts, carry a type prefix;
148
+ `docs/identifiers.md` states the scheme and why citation-derived
149
+ identifiers do not.
113
150
  - **REQ-MODEL-4** — **Applicability entries**: `when` (predicate over facts) →
114
151
  lights or refs → modality → citation → jurisdiction. Every entry MUST have a
115
152
  stable id derived from its paragraph path (`25b`, `25d1`).
116
153
  - **REQ-MODEL-5** — Gates MUST be expressed as predicates over facts
117
- (`length_m < 7`), never as pre-enumerated tuples or configuration counts. Any
154
+ (`fact:length_m < 7`), never as pre-enumerated tuples or configuration counts. Any
118
155
  count of "configurations" is an output of evaluation, never an input to the
119
156
  data.
120
157
  - **REQ-MODEL-6** — Entries MUST compose. Multiple entries applying to one fact
121
158
  record is the normal case, not an error (Rule 28 is "in addition to" Rule 23).
122
- - **REQ-MODEL-7** — Three relations MUST be supported:
123
- - `includes` — import another entry's **lights only**, never its predicate;
124
- - `in_lieu_of` — legal alternatives for the same fact record;
125
- - `excludes` — mutual exclusion, including across rules.
159
+ - **REQ-MODEL-7** — Five relations MUST be supported:
160
+ - `rel:includes` — import another entry's **lights only**, never its predicate;
161
+ - `rel:in_lieu_of` — legal alternatives for the same fact record;
162
+ - `rel:excludes` — mutual exclusion, including across rules; symmetric
163
+ (A excludes B implies B excludes A), and no participating entry MAY be
164
+ forceful (`shall`/`shall-if-practicable`) — a directed "this one
165
+ prevails" is `rel:overrides` (ADR 0007), not `rel:excludes`;
166
+ - `rel:exempts` — one entry lifting another's obligation;
167
+ - `rel:conditional_includes` — import or alternatives, gated on a predicate.
168
+ The five are not interchangeable; README.md holds the working semantics.
169
+ - **REQ-MODEL-13** — Where a condition goes is not a style choice. A
170
+ condition on whether a paragraph *applies to this vessel at all* MUST be in
171
+ the entry's predicate; a condition on *which of two applicable paragraphs
172
+ prevails* MUST be a relation between them, never a negation of the other
173
+ entry's class folded into the predicate. The test: delete the other
174
+ paragraph, and if this one is still true of the vessel, it is a relation.
175
+ Rule 28 does not speak to a vessel constrained by her draught at anchor, so
176
+ `underway` is a predicate; Rule 15 does speak to a fishing vessel under
177
+ power, and Rule 18 only displaces the role it assigns, so that is
178
+ `rel:overrides`. A gate doing a relation's job silently drops every pair the
179
+ displacing paragraph is silent about (fishing against fishing under Rule 18).
180
+ ADR 0005 §4.
181
+ - **REQ-MODEL-12** — `rel:conditional_includes` currently carries three
182
+ distinct shapes under one relation name: a bare `one_of` alternative set
183
+ (`25d2`), a gated alternative set (`when` + `one_of`, `27f`), and a gated
184
+ import with its own citation (`when` + `rel:includes` + `cite`, `29a`). Which
185
+ behaviour applies is inferred from which keys are present. This is a
186
+ **soft** requirement — the data is correct today and the tests cover it,
187
+ so nothing is broken. It is recorded because a third jurisdiction adding
188
+ a fourth shape is how the inference stops being obvious, and because a
189
+ relation whose semantics depend on key presence cannot be validated by
190
+ schema. Before a non-`intl` jurisdiction lands, either split the relation
191
+ or add an explicit discriminant. Recorded as accepted risk until then
192
+ (Q-10).
126
193
  - **REQ-MODEL-8** — Alternatives MUST be first-class. Where the rules permit a
127
194
  choice, the data MUST express all lawful options with their differing
128
195
  modalities and gates, and MUST NOT pick one.
129
196
  - **REQ-MODEL-9** — A decode table from SignalK `navigation.state` to the three
130
197
  axes MUST ship with the package. Its lossy cases MUST be enumerated in data,
131
198
  not prose — at minimum, the flat enum cannot express fishing-at-anchor.
199
+ - **REQ-MODEL-10** — **Identifiers are immutable once published.** An
200
+ identifier (§2) that has shipped in a released version MUST NOT be
201
+ renamed, reused, or repointed. Specifically:
202
+ - **Adding** an identifier is always permitted, at any version.
203
+ - **Deprecating** one is permitted: it MUST keep denoting what it always
204
+ denoted, MUST be marked deprecated in data with the version that
205
+ deprecated it, and MUST NOT be removed in the same major version.
206
+ - **Mutating** one is forbidden. This covers the obvious case (renaming
207
+ `25b`) and the dangerous quiet one: an identifier keeping its spelling
208
+ while changing what it denotes — a paragraph path repointed at
209
+ different text, a fact value narrowed, a light id reassigned. A
210
+ consumer cannot detect this, and every stored citation becomes silently
211
+ wrong.
212
+ - **Reuse after removal** is forbidden outright. A retired identifier is
213
+ retired permanently; its spelling MUST NOT be reissued with a new
214
+ meaning in any later version.
215
+
216
+ Where a renumbering upstream forces a genuine collision, the resolution
217
+ is a **new identifier plus a deprecation**, never a repoint. Renaming or
218
+ removing an identifier is a major version (REQ-PKG-4); repointing one is
219
+ not a version event at all, because it is not permitted.
220
+
221
+ **Immutability baseline: `0.1.1`.** The prohibitions above bind every
222
+ identifier present in the first version released *after* `colregs@0.1.1`,
223
+ and every identifier introduced from then on. Identifiers as they stood
224
+ in `0.1.1` and earlier are outside the baseline. The reason, recorded so
225
+ it is not mistaken for convenience later: `0.1.1` was published
226
+ 2026-08-29, the day the package was seeded, before the identifier review
227
+ this requirement itself calls for had been done and before any consumer
228
+ existed. Read without a baseline, the requirement froze the vocabulary at
229
+ the moment of its first accidental publication and forbade the one review
230
+ it was written to make possible — including the vocabulary type-prefixing
231
+ that resolved a live namespace collision (`docs/identifiers.md`). That is
232
+ a defect in the requirement, not a licence to skip the review.
233
+
234
+ The baseline is **set exactly once**. It MUST NOT be moved, raised,
235
+ re-stated in a later version, or joined by a second baseline clause. This
236
+ clause is the whole of the exception; there is no mechanism for granting
237
+ another. Without that, "move the baseline" is a silent escape hatch from
238
+ REQ-MODEL-10 and the exception becomes the pattern — a specification that
239
+ can suspend its own prohibition by editing one number is advisory, not
240
+ normative. One recorded exception is a correction; a second is a policy.
241
+
242
+ `test/data.test.mjs` pins the baseline literal and asserts it is stated
243
+ exactly once. A build has no access to git history, so it cannot see the
244
+ number being *edited* in place; a test that reconstructed history to
245
+ check would cost more than it is worth and would still pass on a rewritten
246
+ history. What it can refuse is a **second** baseline clause, which is the
247
+ form the escape hatch actually takes — nobody deletes the recorded reason
248
+ for the first exception in order to grant themselves a second. Editing
249
+ the pinned literal is possible, but it is no longer silent: it fails the
250
+ suite and must be done deliberately, in a reviewable diff.
251
+
252
+ **Recorded review — identifier audit, 2026-08-30.** REQ-MODEL-10 binds a
253
+ vocabulary that had never been reviewed as a vocabulary. The audit that
254
+ the baseline authorises is that review; `docs/identifiers.md` states what
255
+ it changed. What it examined and deliberately did **not** change is
256
+ recorded here so it is not re-opened as an oversight:
257
+ - **The entry-id suffix taxonomy** — `23a1`, `24a-m2`, `24a-rest`,
258
+ `26b-mw`, `30d-red`. The suffixes are not drawn from one scheme
259
+ (ordinal, masthead count, fact abbreviation, colour) because the
260
+ paragraphs they disambiguate do not divide on one axis. A uniform
261
+ scheme would have to be ordinal, which would make every id opaque to
262
+ the reader who has the rule text in front of them, for no gain to a
263
+ machine that only ever compares them for equality. Kept as they are.
264
+ - **`24a-m2` / `24a-m3`** — the two-or-three masthead split. The
265
+ cardinality is stated in 24(a)(i) itself ("two masthead lights … three
266
+ such lights" by tow length), so the suffix names something the law
267
+ names, not a modelling convenience of this package.
268
+ - **`nuc`, `cbd`, `ram`, `ram_underwater`** — kept unspelled as terms of
269
+ art; see `docs/identifiers.md` for the reasoning and the trap in `ram`.
270
+ - **REQ-MODEL-11** — Deprecated identifiers MUST be recorded as data — a
271
+ registry naming each retired identifier, what it denoted, the version that
272
+ deprecated it, and its replacement where one exists. Prose in a changelog
273
+ MUST NOT stand in for it: a consumer pinned to an old version needs to
274
+ resolve a stale identifier mechanically. The registry is
275
+ `data/deprecated-identifiers.json`, schema-validated
276
+ (`schema/deprecated-identifiers.schema.json`, ADR 0006); it ships empty
277
+ until the first identifier is retired.
278
+
279
+ ### 4.1 Rule categories and the situation record
280
+
281
+ ADR 0005. Everything in this subsection is **pencil** (`docs/conventions.md`):
282
+ any session may change it for a better idea, logging the change. It is
283
+ recorded as a requirement because it is what the package has decided to build
284
+ towards, not because the shape is settled.
285
+
286
+ - **REQ-CAT-1** **(unimplemented in part — `category` is carried by the
287
+ two-subject entries and defaulted for the rest; no record in `rules.json`
288
+ carries one, so a paragraph with no entry is uncategorised)** —
289
+ Every rule paragraph record MUST carry exactly one `category` from the
290
+ closed set `scope`, `definition`, `standard`, `display`,
291
+ `classification`, `precedence`, `conduct`, `care`, `meta`. The field
292
+ defaults to `display`, so existing entries are correct unedited. CI MUST
293
+ fail on a value outside the set. Where a paragraph plays a second role,
294
+ that role MUST be expressed as a relation (REQ-CAT-3), never as a second
295
+ category.
296
+ - **REQ-CAT-2** — `care` and `meta` paragraphs (Rules 2(a) and 2(b)) MUST NOT
297
+ be applicability entries. They MUST be recorded in a registry sibling to
298
+ `known_omissions`, stating that the package represents them and evaluates
299
+ neither. CI MUST fail on a `care` or `meta` paragraph that appears as an
300
+ entry.
301
+ - **REQ-CAT-3** **(unimplemented in part — `shall-not` has no entry yet)** —
302
+ The modality vocabulary MUST admit `shall-not` and `shall-not-impede`
303
+ alongside `shall`, `may`, `shall-if-practicable`, `conditional` and
304
+ `exempt`, and the relation vocabulary MUST admit `rel:overrides` as a
305
+ sixth verb beside REQ-MODEL-7's five. Both remain closed sets; CI MUST
306
+ fail on a value outside them, and on a cycle in `rel:overrides`.
307
+ - **REQ-CAT-4** — A two-subject rule MUST read a **situation record**:
308
+ two per-vessel fact records, a kinematic state per vessel, relative
309
+ geometry, and history. The per-vessel fact record MUST NOT change to accommodate it, and kinematic
310
+ state MUST be a distinct fact class — a consumer that reads only `display`
311
+ entries MUST NOT be required to supply one. Adding the situation record
312
+ MUST leave every existing fixture valid unedited.
313
+ - **REQ-CAT-5** — A situation MUST NOT be expressible in the current
314
+ single-vessel fixture format. Before any two-subject entry lands, the fixture schema MUST be
315
+ extended to carry a situation and to name each subject unambiguously, and
316
+ the extension MUST be backward-compatible with the fixtures published
317
+ today (REQ-VERIFY-1).
318
+ - **REQ-CAT-6** — The situation record MUST be declared in
319
+ `data/facts.json` under `situation`, and MUST address each vessel's facts
320
+ through the subject namespace of `docs/identifiers.md`:
321
+ `<subject>:<class>:<key>`, subject from `own`/`other`/`pair`, class from
322
+ `fact`/`kin`/`geo`/`hist`/`env`. A key with no subject segment MUST mean `own:`,
323
+ so that every predicate and fixture published today is a valid situation
324
+ predicate unedited. `own:fact:*` and `other:fact:*` MUST resolve to the
325
+ per-vessel fact record key for key, with no key renamed or copied.
326
+ `pair` MUST carry only classes whose facts are symmetric between the two
327
+ vessels; `env` — where the encounter is happening — is `pair`-only for that
328
+ reason and MUST NOT appear under a vessel. Every fact in the `kin`, `geo` and `hist` classes MUST carry
329
+ `type`, `cite`, `actuable` and `signalk` like the existing scalars, and a
330
+ `null` `cite` MUST carry `cite_pending` naming the paragraph it awaits, or
331
+ an explicit `null` where no paragraph will ever justify it. CI MUST fail
332
+ on a subject or class outside the declared sets, on a `pair` class that is
333
+ not symmetric, and on a fact record key that does not survive the subject
334
+ prefix.
335
+ - **REQ-CAT-7** — Situation fixtures MUST live in a file separate from
336
+ `fixtures/applicability-fixtures.json`, which MUST remain byte-identical
337
+ (REQ-VERIFY-1). Each case MUST carry a `situation` whose every key
338
+ resolves in the namespace of REQ-CAT-6 to a fact declared in
339
+ `data/facts.json`, and a `status` from a closed set. An element of
340
+ `expect` MUST be either a bare entry id — the published one-subject form,
341
+ asserting nothing about modality — or `{entry, modality}` naming the
342
+ modality that entry is expected to carry, which is what Q-5 needs. A case
343
+ whose `status` is `illustrative` MUST assert no entries and MUST NOT join
344
+ the fixture replay; it fixes the shape and the namespace before the
345
+ entries exist. CI MUST fail on an undeclared fact, an unresolvable key, an
346
+ unknown entry id, an unknown modality, and on an `illustrative` case that
347
+ names an entry.
348
+
349
+ - **REQ-CAT-8** — A two-subject entry MUST state an `effect` and MUST NOT
350
+ state `lights`. For a `precedence` entry the effect MUST be a role per
351
+ subject, `{own, other}`, from the closed set `give-way`, `stand-on`,
352
+ `shall-not-impede`, `keep-clear`, `none`; for a `scope` entry it MUST name
353
+ the part, the section and the rules that section governs; for a
354
+ `classification` entry it MUST carry exactly one key, either `encounter`
355
+ from the closed set `head-on`, `crossing`, `overtaking`, `none`, or
356
+ `risk_of_collision`, whose only value is `true`. `stand-on` MUST
357
+ appear only as the counterpart of `give-way`, and the counterpart of
358
+ `shall-not-impede` MUST be `none` — Rule 8(f)(iii) is why. CI MUST fail on a
359
+ role or an encounter outside its set, on an effect whose shape does not match
360
+ its category, and on a `rel:overrides` that resolves to no entry, points at an
361
+ entry of a different category, or closes a cycle. `✎` pencil, with the rest of
362
+ §4.1.
363
+ - **REQ-CAT-9** — The `classification` entries for Rules 13, 14 and 15 MUST
364
+ **partition** the pair's relative geometry: for any situation those entries
365
+ all reach, exactly one encounter type MUST apply — never two, never none.
366
+ The crossing sector MUST NOT be enumerated; it MUST be derived, as the
367
+ negation of the other two, so that a single constraint object states each
368
+ sector and its complement. Any numeric threshold a Part B predicate needs
369
+ which the Rules do not state MUST be declared once in `data/facts.json`
370
+ under `situation.constants`, with its status under `docs/conventions.md`
371
+ and, where pencilled, what would settle it; an entry MUST read the declared
372
+ constant rather than repeat the literal. CI MUST sweep both subjects'
373
+ relative bearings and fail on any bearing in two encounter types or in none,
374
+ on either edge of 13(b)'s sector falling on the wrong side, and on any entry
375
+ whose threshold does not match the declared constant. `✎` pencil, with the
376
+ rest of §4.1.
377
+
378
+ ### 4.2 Part B invariants
379
+
380
+ `docs/part-b-invariants.md` states what COLREGS requires of a *trace* of
381
+ situations, where an entry says which norms one state selects; it is a separate
382
+ document because its propositions are about COLREGS, not requirements on this
383
+ package, and would be misread under a `REQ-` id and an RFC 2119 MUST. Everything
384
+ here is **pencil** (`docs/conventions.md`) with §4.1.
385
+
386
+ - **REQ-INV-1** — Part B's steering and sailing rules MUST be recorded as prose
387
+ invariants in `docs/part-b-invariants.md`, each with a stable identifier,
388
+ each citing the paragraph path it comes from, and each precise enough that a
389
+ formalisation can be written from it without returning to the rule text.
390
+ - **REQ-INV-2** — An invariant identifier MUST be `INV-` followed by the
391
+ entry-id derivation of its paragraph path (`docs/identifiers.md`, "Entry
392
+ ids"), with a descriptive hyphenated suffix where one paragraph yields more
393
+ than one invariant. A suffix MUST name what distinguishes the invariant, and
394
+ MUST NOT be an ordinal. Identifiers MUST be stable and MUST NOT be reused; a
395
+ withdrawn invariant is struck through and kept, as a requirement is. Once a
396
+ formal specification cites an invariant identifier, its **Invariant.**
397
+ statement MUST NOT change in place; a changed statement is a new identifier
398
+ and the old one is struck through and kept.
399
+ - **REQ-INV-3** — Every paragraph path in `data/rules.json` within the range
400
+ the document covers MUST appear exactly once in its coverage table, mapped
401
+ either to an invariant identifier or to an explicit exclusion with a reason.
402
+ CI MUST fail on a paragraph in range that appears in neither, on one that
403
+ appears twice, and on an invariant whose citation does not resolve in
404
+ `data/rules.json`. Enforced by `test/data.test.mjs`.
405
+ - **REQ-INV-4** — An invariant that is temporal MUST state what state must be
406
+ remembered and over what window. "Temporal" means it relates two or more
407
+ states of a trace; a property of a single state MUST say so.
408
+ - **REQ-INV-5** — Where the rule text admits two readings, the document MUST
409
+ record both and MUST NOT choose. The choice is an open question in §11 and is
410
+ the maintainer's; a session MAY argue for a reading, and MUST NOT resolve one
411
+ by writing only its preferred half down. A proposition that is neither the
412
+ rule text, arithmetic over the rule text, nor a decision recorded as such
413
+ MUST NOT appear as an invariant.
414
+ - **REQ-INV-6** — An invariant that covers its paragraph while leaving a term
415
+ the Rules do not define MUST name that term in the document's list of
416
+ undetermined terms, so that "covered" is never read as "checkable". A numeric
417
+ stand-in for such a term MUST be a declared constant under
418
+ `situation.constants` (`REQ-CAT-9`), never a literal inside an invariant.
419
+ - **REQ-INV-7** — An invariant's **Invariant.** paragraph MUST be at most 120
420
+ words. This is a readability bound on the normative statement itself, not a
421
+ document-length budget (`docs/budgets.json` governs those); it keeps a single
422
+ invariant from growing into a paragraph a formalisation can't be checked
423
+ against sentence-by-sentence. Enforced by `test/data.test.mjs`.
424
+
425
+ ## 5. Languages and localization
426
+
427
+ COLREGS 72 is multi-lingual at the source: English and French are equally
428
+ authentic treaty texts, Spanish and Russian official translations were
429
+ deposited with the original, Arabic and Chinese texts exist through IMO's
430
+ official languages, and many states gazette their own legally binding
431
+ translation. (Recalled, not yet verified against the primary sources — Q-6.)
432
+ See ADR 0003.
433
+
434
+ - **REQ-LANG-1** **(unimplemented — no language dimension exists in the
435
+ data)** — Language MUST be a dimension orthogonal to jurisdiction,
436
+ identified by BCP 47 tags. Which body of rules applies and which text of
437
+ them is displayed are independent questions; neither MUST ever be inferred
438
+ from the other, and no property beyond the language of the text — not
439
+ source, audience, nor legal applicability — MUST be inferred from a tag.
440
+ - **REQ-LANG-2** — Identifiers — entry ids, fact values, light ids,
441
+ paragraph paths, relation names — MUST be language-neutral and MUST NOT
442
+ be localized. Translations attach to identifiers; they never replace them.
443
+ Identifiers are schema keywords, not display strings: each vocabulary
444
+ distinguishes machine identifier, display label (catalog), and definition,
445
+ and renaming an identifier is a breaking change (REQ-PKG-4). Immutability
446
+ itself is REQ-MODEL-10; this requirement adds only that identifiers are
447
+ never localized.
448
+ - **REQ-LANG-3** **(unimplemented — rule text is one untagged ruleset, not a
449
+ corpus per jurisdiction × language × source)** — Rule text MUST be storable
450
+ as a **corpus** per (jurisdiction × language × source), keyed by paragraph
451
+ path, holding at most one text per path, with corpus-level provenance and
452
+ one declared status tier:
453
+ - `authentic` — identified by the governing instrument itself as an
454
+ equally authentic text (a claim of the instrument, never this repo's
455
+ assessment);
456
+ - `official` — an official translation published or deposited through the
457
+ instrument's depositary organization;
458
+ - `national` — a state's legally binding published text;
459
+ - `community` — informational, no legal standing.
460
+ Tier is a property of the source, not the language. REQ-MODEL-1's verbatim
461
+ rule applies per corpus, against that corpus's own source.
462
+ - **REQ-LANG-4** — Adding a language MUST be additive: no schema change, no
463
+ edits to existing corpora or catalogs (the language mirror of REQ-SCOPE-4).
464
+ - **REQ-LANG-5** **(unimplemented — no coverage declaration, and the CI checks
465
+ are unwritten)** — Corpora MAY be partial. Coverage MUST be declared in
466
+ machine-readable form, and CI MUST fail on a corpus key that does not
467
+ resolve to a known paragraph path, and on a corpus filename that disagrees
468
+ with the file's internal metadata. Silence MUST NOT imply coverage (the
469
+ language mirror of REQ-SCOPE-6).
470
+ - **REQ-LANG-6** **(unimplemented — no display catalogs exist)** — Display
471
+ strings for the identifier vocabularies (light names, fact-value labels,
472
+ modality labels, image captions) MUST be addressable via stable string keys
473
+ with per-language catalogs, separate from legal corpora. Catalog entries are
474
+ static strings: no interpolation, plural or gender grammar — message
475
+ composition belongs to the consumer's i18n system, and this package MUST NOT
476
+ grow one. Each catalog MUST carry lightweight provenance: contributors,
477
+ reviewers, review date, licence. Maintainer notes inside structural files
478
+ are working documentation, not display strings, not part of the localization
479
+ surface, and stay untranslated.
480
+ - **REQ-LANG-7** **(unimplemented in part — no fallback policy is encoded, but
481
+ the mixed-corpus statement is missing from the package documentation)** — The
482
+ package MUST NOT encode a language fallback policy, and MUST NOT silently
483
+ substitute one corpus for another. Text is only addressable inside a corpus,
484
+ so every textual unit a consumer retrieves is attributable to its corpus;
485
+ package documentation MUST state that a mixed-corpus rendering is never a
486
+ single authoritative edition. Choice and fallback beyond that are the
487
+ consumer's (the language mirror of REQ-CONS-3).
488
+ - **REQ-LANG-8** — A `community`-tier corpus MUST record who produced and
489
+ who reviewed it. Machine translation without named human review MUST NOT
490
+ be accepted.
491
+ - **REQ-LANG-9** **(unimplemented — the shipped text declares no normalization
492
+ form)** — Verbatim (REQ-MODEL-1) is defined at the Unicode level: each
493
+ corpus MUST declare the normalization form applied to its text (NFC unless
494
+ declared otherwise) and MUST NOT insert or strip bidi control characters,
495
+ localize numerals, punctuation, units or quotation marks, or otherwise "fix"
496
+ the source text. Rendering direction is a consumer concern and MUST stay out
497
+ of the data.
498
+ - **REQ-LANG-10** **(unimplemented — neither the skeleton nor the ruleset
499
+ declares an amendment state)** — The structural skeleton MUST declare, as
500
+ data, the amendment state it consolidates (e.g. "COLREGS 72 as amended
501
+ through …"). Every corpus MUST declare the amendment state its source
502
+ reflects. The two MAY differ — a corpus transcribed from an older
503
+ consolidation is legitimate — but the difference MUST be machine-visible,
504
+ never silent.
132
505
 
133
506
  ---
134
507
 
135
- ## 5. Provenance and licensing
508
+ ## 6. Provenance and licensing
136
509
 
137
510
  - **REQ-PROV-1** — Every text and image asset MUST record its source, the date
138
511
  retrieved, and its licence or public-domain basis.
@@ -146,10 +519,27 @@ Four layers, each independently addressable.
146
519
  - **REQ-PROV-5** — Images MUST be addressable as data: an image record per file,
147
520
  naming what it illustrates by entry id or paragraph path. Unexplained filename
148
521
  prefixes are a provenance defect.
522
+ - **REQ-PROV-6** **(unimplemented — source identity is a prose string and
523
+ rights are one flat field)** — Source identity MUST be structured data —
524
+ publisher, title, edition, publication and effective dates, URL, retrieval
525
+ date — not a prose string. Rights MUST be recorded separately for the source
526
+ text, for the basis on which this package redistributes it, and for the
527
+ licence the package distributes under; one flat `licence` field MUST NOT
528
+ stand in for all three. A translation MAY carry translator rights even where
529
+ the underlying instrument is public domain, and that check is part of
530
+ REQ-PROV-2.
531
+ - **REQ-PROV-7** — An external contribution MUST NOT be merged from a
532
+ contributor who has not agreed to the contribution terms in
533
+ `CONTRIBUTING.md`, which state that opening a pull request constitutes
534
+ agreement. Those terms MUST include both (a) a DCO-style certification
535
+ that the contributor has the right to submit the work, and (b) a licence
536
+ grant to the maintainer sufficient to relicense the compilation. (b) is
537
+ what holds GATE-6 open; a bare DCO certifies origin and grants nothing,
538
+ so it does not.
149
539
 
150
540
  ---
151
541
 
152
- ## 6. Verification
542
+ ## 7. Verification
153
543
 
154
544
  - **REQ-VERIFY-1** — Fixtures MUST pair fact records with the entries that apply,
155
545
  and MUST be consumable by an implementation in any language.
@@ -158,16 +548,36 @@ Four layers, each independently addressable.
158
548
  candidate fact records), so the two cannot silently disagree.
159
549
  - **REQ-VERIFY-3** — Every applicability entry MUST be covered by at least one
160
550
  fixture that exercises it, and at least one that excludes it.
161
- - **REQ-VERIFY-4** — Every `in_lieu_of` and `excludes` relation MUST have a
551
+ - **REQ-VERIFY-4** — Every `rel:in_lieu_of` and `rel:excludes` relation MUST have a
162
552
  fixture demonstrating it.
163
553
  - **REQ-VERIFY-5** — Predicates MUST be tested at their boundaries. Every numeric
164
554
  gate MUST have fixtures immediately either side of the threshold.
165
555
  - **REQ-VERIFY-6** — CI MUST fail on a fixture that references an entry id, a
166
556
  light definition or a paragraph path that does not exist.
557
+ - **REQ-VERIFY-7** **(unimplemented — the check is unwritten; it depends on
558
+ REQ-MODEL-11)** — CI MUST fail on an identifier present in the deprecation
559
+ registry (REQ-MODEL-11) that has reappeared in the live data with a
560
+ different denotation, and on a registry entry whose replacement does not
561
+ resolve. Immutability (REQ-MODEL-10) is otherwise a cross-version property
562
+ no single build can check; the registry is what makes the checkable part
563
+ checkable.
564
+ - **REQ-VERIFY-8** — A situation record's relative geometry MUST be checkable
565
+ against its kinematic state. `data/facts.json` MUST declare, under
566
+ `situation.geometry.consistency`, the equations relating the two relative
567
+ bearings, the range, the CPA, the TCPA and the bearing rate to the two
568
+ positions, headings and speeds, with the tolerances a comparison uses. CI
569
+ MUST fail on a situation fixture that states quantities on both sides of one
570
+ of those equations and violates it, and every situation the suite constructs
571
+ for a sweep MUST satisfy the declaration. A property asserted over
572
+ constructed situations — REQ-CAT-9's partition, the precedence properties —
573
+ MUST be asserted over consistent situations only; where a property holds on
574
+ consistent situations and fails on an inconsistent one, the suite MUST pin
575
+ that situation as one the check rejects, so the exclusion is visible rather
576
+ than assumed. `✎` pencil, with `Q-48`.
167
577
 
168
578
  ---
169
579
 
170
- ## 7. Packaging
580
+ ## 8. Packaging
171
581
 
172
582
  - **REQ-PKG-1** — Zero runtime dependencies.
173
583
  - **REQ-PKG-2** — Data MUST be consumable without a JavaScript runtime: plain
@@ -182,7 +592,7 @@ Four layers, each independently addressable.
182
592
 
183
593
  ---
184
594
 
185
- ## 8. Consumer contracts
595
+ ## 9. Consumer contracts
186
596
 
187
597
  - **REQ-CONS-1** — The switching subset MUST be derivable from the data by
188
598
  filtering, not by a separate hand-maintained list. A consumer MUST be able to
@@ -197,7 +607,175 @@ Four layers, each independently addressable.
197
607
 
198
608
  ---
199
609
 
200
- ## 9. Open questions
610
+ ## 10. Reversibility gates
611
+
612
+ A pre-1.0 data package can decline a design and still adopt it later. That
613
+ stops being true at a specific, nameable event — a version tag, a second
614
+ corpus, a first consumer. A declined design whose cost rises over time is
615
+ therefore not "closed"; it is **timed**, and the timing is part of the
616
+ specification until 1.0.
617
+
618
+ - **REQ-GATE-1** — Every design declined on the grounds that it can be
619
+ adopted later MUST be recorded as a gate below, naming the **closing
620
+ event** after which adoption stops being cheap, and the **reopening
621
+ trigger** — the observable fact that forces reconsideration. A decline
622
+ recorded without both is incomplete.
623
+ - **REQ-GATE-2** — A gate MUST NOT be closed by the passage of time or by
624
+ a maintainer's judgement alone. It closes when its named event occurs, or
625
+ when its trigger fires and the decision is re-taken in a new ADR.
626
+ - **REQ-GATE-3** — Tagging 1.0 MUST be blocked until every gate whose
627
+ closing event is *the 1.0 tag* has been re-taken deliberately: confirmed
628
+ in a new ADR, or adopted. Inheriting one by default is the failure this
629
+ section exists to prevent.
630
+ - **REQ-GATE-4** — A gate that is adopted or confirmed MUST be struck
631
+ through here, not deleted, and MUST cite the ADR that settled it
632
+ (the gate mirror of the ID-stability rule in this document's preamble).
633
+
634
+ ### Open gates
635
+
636
+ Each gate names the declined design, the closing event, and the trigger.
637
+
638
+ - **GATE-1 — `paragraph_id` split from `citation_path`**
639
+ (ADR 0003, declined; REQ-LANG-3, REQ-PKG-4).
640
+ *Closing event*: the 1.0 tag. Before it, splitting the two is a
641
+ mechanical rewrite of cross-references in a package with no stable-API
642
+ promise. After it, every consumer's lookup path breaks.
643
+ *Trigger*: any paragraph path that keeps its spelling while changing what
644
+ text it denotes — the mutation REQ-MODEL-10 forbids outright, which is
645
+ why the collision has to be resolved in the schema rather than absorbed.
646
+ Two ways that happens, both now checked against primary sources
647
+ ([verification](verification/2026-08-30-q6-q8.md)):
648
+ - **Amendment renumbering — verified real, not hypothetical.** The
649
+ original "believed never since 1972" premise is refuted: A.910(22)
650
+ (2001) displaced the old `23(c)` to `23(d)` when WIG lighting took its
651
+ path, and A.464(XII) (1981) relettered `24(g)`→`24(h)` and
652
+ `27(d)(iv)`→`(iii)`. Two of seven amendments renumbered Part C.
653
+ - **Cross-jurisdiction divergence — verified present, and NOT this
654
+ gate's trigger.** The 15 same-path-different-text rows in the 33 CFR 83
655
+ diff are the *jurisdiction dimension working as designed* (REQ-MODEL-1
656
+ stores both texts, keyed by jurisdiction) — the effective identifier is
657
+ (jurisdiction, path), so they are not REQ-MODEL-10 mutations. This
658
+ route is retired, not merely dormant: divergence between two
659
+ jurisdictions at one point in time can never fire the trigger. The
660
+ residue that is genuinely structural — `23(d)(i)` having no Inland
661
+ counterpart path, Rule 28 "[Reserved]" — is a delta-model problem
662
+ (Q-11), not a repoint.
663
+ - **National renumbering across releases — live, and the second real
664
+ route.** A national body renumbering its own amalgamation is the same
665
+ within-jurisdiction repoint as an IMO amendment: if `us/inland 24(c)`
666
+ denotes different text in vN+1 than it did in vN, that is a mutation
667
+ REQ-MODEL-10 forbids, jurisdiction dimension or not. The trigger is
668
+ *within one jurisdiction across releases*, on either route — not
669
+ between jurisdictions at one moment.
670
+ *Ruling, 2026-08-30*: the gate does not flip on today's data — no
671
+ published path has changed denotation. But with the "rare, believed
672
+ never" premise gone (real base rate: twice in seven amendments), the
673
+ pre-1.0 re-take **leans adopt**, decided in the second-jurisdiction
674
+ bundle alongside GATE-2 and Q-10. Final call is the maintainer's at that
675
+ point.
676
+ *This gate is open on timing, not on outcome.* A real-world respelling —
677
+ a citation keeping its spelling while denoting different text —
678
+ **forces** the split: REQ-MODEL-10 forbids repointing and forbids reuse,
679
+ so no third option exists. The re-take, if the trigger fires, is
680
+ therefore predetermined:
681
+ - The split lands and it is a **major version**.
682
+ - Identifiers in the new major are **defined incompatible** with
683
+ identifiers of the prior major. A consumer MUST NOT assume a
684
+ same-spelled path denotes the same text across the boundary.
685
+ - An optional **prior → new identifier mapping** MAY ship alongside.
686
+ REQ-MODEL-11's deprecation registry, with its replacement pointers, is
687
+ the seed of that mapping and exists for this reason.
688
+ What remains open is only whether the trigger ever fires, and whether
689
+ the split lands pre-emptively or on demand.
690
+ *Re-take required before 1.0* (REQ-GATE-3), and re-checked in the
691
+ second-jurisdiction bundle — justified by Q-11 and GATE-2, no longer by
692
+ a cross-jurisdiction trigger route.
693
+
694
+ - **GATE-2 — instrument → edition → corpus as first-class layers**
695
+ (ADR 0003, declined; the adopted 80% is REQ-LANG-10).
696
+ *Closing event*: the second corpus of any one jurisdiction — which,
697
+ read against ADR 0003's sequencing, means **the first non-English
698
+ corpus**, not a distant milestone. A French or Finnish text of `intl`
699
+ is a second corpus of `intl`. With one corpus, re-homing it under an
700
+ edition parent is a single file move; the cost scales with
701
+ corpora × languages immediately thereafter.
702
+ *Trigger*: a jurisdiction publishing two editions in force
703
+ concurrently — an old and a new text running in parallel through a
704
+ transition period. REQ-LANG-10's declared amendment state makes such a
705
+ pair machine-visible, which is what gives this trigger a foothold.
706
+ *Re-take required before translation #1 lands* — the edition-layer
707
+ decision is due at the first added translation, not at 1.0.
708
+
709
+ - **GATE-3 — legal-status × translation-status as two enums**
710
+ (ADR 0003, half-adopted: one tier for legal authority in REQ-LANG-3,
711
+ translation provenance as structured metadata in REQ-LANG-8/REQ-PROV-6).
712
+ *Closing event*: the first `community`-tier translation of a `national`
713
+ corpus. Until one exists, the four-way combination the split exists to
714
+ express is hypothetical.
715
+ *Trigger*: a real corpus whose legal tier and translation tier disagree
716
+ in a way a consumer must filter on, and cannot from the metadata as
717
+ structured.
718
+
719
+ - **GATE-4 — a package-encoded language fallback chain**
720
+ (ADR 0003, declined; replaced by REQ-LANG-7's no-silent-substitution).
721
+ *Closing event*: none — this door opens outward. Loosening a strict rule
722
+ is additive; tightening one later breaks consumers. Recorded so the
723
+ asymmetry is not re-discovered as an argument for adopting it early.
724
+ *Trigger*: none anticipated. Consumer demand for a *documented,
725
+ non-normative* recommended chain, shipped outside the data, would not
726
+ reopen it.
727
+
728
+ - **GATE-5 — a CI-enforced terminology glossary**
729
+ (ADR 0003, declined for legal corpora; REQ-MODEL-1).
730
+ *Closing event*: none for legal corpora — the decline follows from
731
+ verbatimness and does not get cheaper or dearer with time. For display
732
+ catalogs it is contributor guidance, gated on the contribution docs
733
+ existing at all.
734
+ *Trigger*: none. A glossary contradicting a verbatim source is a defect
735
+ in the glossary.
736
+
737
+ - **GATE-6 — the compilation's outbound licence**
738
+ (ADR 0004; changed MIT → Apache-2.0 in `2669e2a` on `main`. REQ-PROV-4.)
739
+ *Closing event*: the **first merged external contribution**. Until then
740
+ the copyright holder is one person and the licence can be changed at
741
+ will. After it, relicensing needs every contributor's consent — and
742
+ soliciting translations is the express purpose of the language work, so
743
+ this door closes early and hard.
744
+ *Trigger*: deciding the data side wants CC0 or CC BY 4.0 separately from
745
+ the code (REQ-PROV-4). Tracked as Q-9; ADR 0004 settles the code licence
746
+ and deliberately leaves this open.
747
+ Two refinements the gate carries:
748
+ - Already-published npm versions are irreversibly under the licence they
749
+ shipped with. The gate governs future releases only.
750
+ - The gate is **held open deliberately**, by the mechanism adopted in
751
+ REQ-PROV-7: `CONTRIBUTING.md` terms, agreed by opening a pull request,
752
+ carrying a DCO-style certification *and* a licence grant sufficient to
753
+ relicense. The grant is the part that holds the gate open. Implied
754
+ assent is weaker than recorded assent; a CLA-assistant bot is the
755
+ upgrade path if contributors arrive (ADR 0004).
756
+ *Expected to stay open indefinitely* — external contributors are
757
+ unlikely short of major success. Recorded regardless: "unlikely" is not
758
+ a closing event (REQ-GATE-1).
759
+
760
+ Gates whose closing event is "none" are recorded because a future reader
761
+ will otherwise re-ask whether they were merely deferred. They were not.
762
+
763
+ ### Gate status is data
764
+
765
+ The gates above are mirrored in **`docs/gates.json`** — id, closing event,
766
+ trigger, status (`open` / `re-taken` / `adopted` / `declined-permanently`),
767
+ and the ADR that settled it where one exists. That file, not this prose, is
768
+ what REQ-GATE-3 is enforced against: `test/data.test.mjs` fails the build if
769
+ `package.json`'s major version is 1 or higher while any gate whose closing
770
+ event is the 1.0 tag is still `open` or cites no ADR. There is no environment
771
+ variable, skip flag, or warning-only path — undoing the block means editing
772
+ the registry in a pull request, which is the deliberate re-take REQ-GATE-3
773
+ asks for. The test also fails on a gate that appears in one place and not the
774
+ other, so the prose and the registry cannot drift apart.
775
+
776
+ ---
777
+
778
+ ## 11. Open questions
201
779
 
202
780
  Tracked here until resolved; each becomes an ADR.
203
781
 
@@ -209,13 +787,663 @@ Tracked here until resolved; each becomes an ADR.
209
787
  UK OGL v3.0, AU CC BY 4.0, DE §5 UrhG *amtliche Werke*, CA Reproduction of
210
788
  Federal Law Order, EU/UNECE CEVNI unclear. REQ-PROV-2 blocks each until
211
789
  checked against the primary source. CEVNI is the one most likely to fail.
790
+ **Verified 2026-09-05** against the primary sources for every jurisdiction
791
+ except CEVNI — see ADR 0001 Amendments (2026-09-05). CEVNI remains open:
792
+ unece.org was unreachable from the checking host, and the UN's default
793
+ terms (personal, non-commercial use only) block it until written
794
+ permission or a national transposition is chosen instead.
212
795
  - **Q-4** — Two upstream SignalK spec asks are outstanding and independent of
213
796
  this package: a making-way indicator, and `design.maxSpeed`.
214
797
  - **Q-5** — REQ-VERIFY-5 asks for boundary fixtures on every numeric gate.
215
- Three gates (`23a2`, `26b-mast`, `30c`'s `length_m` thresholds) live only in
798
+ Three gates (`23a2`, `26b-mast`, `30c`'s `fact:length_m` thresholds) live only in
216
799
  `modality_by`, not in the entry's `when` — they flip `shall` to `may`, not
217
800
  which entries apply. The fixture format only asserts applying entry ids, not
218
801
  expected modality, so there is no way to fixture these three without
219
802
  extending the schema to carry expected modality per entry. Not done
220
803
  speculatively; blocks a clean REQ-VERIFY-5 pass on these three gates until
221
804
  decided.
805
+ **Decided in pencil 2026-09-04** (PR #22), as part of the situation
806
+ fixture schema: an element of `expect` is either a bare entry id, exactly as
807
+ today, or `{entry, modality}`. The two forms are interchangeable and a bare
808
+ id asserts nothing, so `applicability-fixtures.json` stays byte-identical
809
+ and needs no migration; REQ-CAT-7 states the rule and
810
+ `fixtures/situation-fixtures.json` carries the worked example. What is left
811
+ is not a decision but the work: writing the boundary fixtures for `23a2`,
812
+ `26b-mast` and `30c` in the new form. Pencil, so a session that finds a
813
+ better shape may change it, logging the change; settled for good by those
814
+ three fixtures actually landing.
815
+ - **Q-6** — The treaty-language facts behind §5 (en/fr authentic, es/ru
816
+ deposited translations, ar/zh via IMO official languages) are recalled, not
817
+ verified. Verify against the Convention's final clauses and IMO's current
818
+ practice before the first non-English corpus lands.
819
+ **Verified 2026-08-30** against the UNTS deposit (Vol. 1050, I-15824,
820
+ Article IX) — en/fr authentic and es/ru deposited translations both
821
+ confirmed verbatim; ar/zh confirmed as a mechanism (IMO's six official
822
+ languages) with a catalogued Chinese edition, Arabic edition indicated but
823
+ not independently re-fetched. See
824
+ [docs/verification/2026-08-30-q6-q8.md](verification/2026-08-30-q6-q8.md#claim-3-q-6--verified-arabic-component-partially).
825
+ - **Q-7** — Reproduction terms per language corpus are unverified, and this —
826
+ not translation effort — sequences the work. IMO's consolidated
827
+ six-language editions are sold publications and probably NOT reproducible;
828
+ the UNTS deposit (en/fr authentic texts) and national gazettes (Finlex,
829
+ BOE, …) are the likely lawful sources. REQ-PROV-2 blocks each corpus until
830
+ its source's terms are checked and recorded. Answerable **per language**,
831
+ not only as a whole: clearing one candidate source unblocks that corpus
832
+ alone, which is the cheap path when a demo needs a specific language
833
+ early.
834
+ - **Q-8** — Does the paragraph path survive the first national amalgamation?
835
+ GATE-1's accepted risk rests on paragraph paths being immutable
836
+ (REQ-MODEL-10) — adding and deprecating are fine, but a path that keeps its
837
+ spelling while changing what text it points at breaks every citation and
838
+ every `cite` in `applicability.json`. The threat is not primarily a future
839
+ amendment. It is the **second jurisdiction**: while `intl` is the only
840
+ populated one, path and citation are trivially identical, and the question
841
+ cannot fail. The US Inland rules deliberately parallel COLREGS rule
842
+ numbering but are known to diverge below rule level (Rules 9, 15, 24 and
843
+ 34 are the usual examples). Check 33 CFR 83 against `rules.json` paragraph
844
+ by paragraph **before `us/inland` lands**, not at 1.0.
845
+ - If paths survive, GATE-1's accepted risk is earned rather than
846
+ assumed, and the 1.0 re-take is a confirmation.
847
+ - If they do not, GATE-1 flips to *adopt*, and the split must land
848
+ before the second jurisdiction rather than after.
849
+ - Secondary, and much weaker: whether any COLREGS amendment has ever
850
+ renumbered a Part C paragraph. Recalled as never — the WIG amendment
851
+ *inserted* 23(c) rather than renumbering around it — but 50 quiet
852
+ years is not a guarantee about the next amendment. Worth a check
853
+ against the IMO amendment resolutions, not worth blocking on.
854
+
855
+ **Verified 2026-08-30**, both parts, against primary sources — see
856
+ [docs/verification/2026-08-30-q6-q8.md](verification/2026-08-30-q6-q8.md).
857
+ Primary claim (33 CFR 83 vs `data/rules.json`): of 90 Part C paths, 15
858
+ are same-spelling-different-text mutations (`22(a)/(b)/(c)`, `24(c)`,
859
+ `24(d)`, `24(f)`, `24(g)`, `24(i)`, `25(d)(i)`, `25(d)(ii)`, `25(e)`,
860
+ `26(d)`, `30(e)`), plus one structural path-mismatch (`23(d)(i)` — the
861
+ Inland equivalent sits at bare `23(d)`, not `23(d)(i)`), one whole-rule
862
+ clean absence (`28`, "[Reserved]" in Inland), and two clean intl-only
863
+ absences. Secondary claim (amendment history): also refuted — the WIG
864
+ amendment (A.910(22), 2001) explicitly renumbers, displacing the
865
+ pre-existing `23(c)` (small-vessel alternative lights) to `23(d)`; a 1981
866
+ amendment (A.464(XII)) separately relettered `24(g)`→`24(h)` and
867
+ `27(d)(iv)`→`27(d)(iii)`. Both findings feed the GATE-1 re-take, not
868
+ decided here.
869
+ - **Q-12** — REQ-MODEL-10 has a **baseline off-by-one**, recorded here
870
+ because the requirement as written forbids work already approved. It
871
+ binds any identifier that "has shipped in a released version";
872
+ `colregs@0.1.1` was published 2026-08-29, so every identifier in it is
873
+ already bound — including the ones the identifier audit reviewed and
874
+ cleared for change (type-prefixing the vocabulary class:
875
+ `light:masthead`, `activity:nuc`). Fix by naming the baseline:
876
+ immutability binds from a stated version forward, with 0.1.1 explicitly
877
+ outside it and the reason recorded. The baseline itself MUST be
878
+ immutable: stated exactly once, never moved. A movable baseline is the
879
+ quiet escape hatch from REQ-MODEL-10 — one recorded exception is a
880
+ correction; a second is a pattern. This is a defect in the requirement,
881
+ not a reason to skip the rename; it must land in the same pre-1.0 PR as
882
+ the rename it authorises, and before that PR renames anything. The audit
883
+ itself — six findings, all verified against `data/*.json`, three kept
884
+ with rationale (`nuc`/`cbd`/`ram` as terms of art, the entry-id suffix
885
+ taxonomy, `24a-m2`/`24a-m3` whose cardinality is stated in 24(a)(i)
886
+ itself) — is REQ-MODEL-10's recorded review of the identifiers it binds,
887
+ and is on PR #4.
888
+
889
+ **Resolved 2026-08-30.** REQ-MODEL-10 now states the baseline (`0.1.1`,
890
+ outside it, with the reason) and the hardening that makes the exception
891
+ safe: the baseline is set exactly once and MUST NOT be moved, raised,
892
+ re-stated, or joined by a second clause. `test/data.test.mjs` pins the
893
+ literal and asserts a single statement; the requirement records why the
894
+ cross-version half is not asserted. The three accepted findings are
895
+ written up as REQ-MODEL-10's recorded review rather than left on a pull
896
+ request, and the changed one is `docs/identifiers.md`.
897
+ - **Q-10** — Split `rel:conditional_includes`, or add a discriminant?
898
+ REQ-MODEL-12 records the overload; this is the unresolved half. Splitting
899
+ it names each behaviour and lets a schema validate the shape, at the cost
900
+ of a sixth and seventh relation verb in a vocabulary CLAUDE.md already
901
+ warns is easy to confuse. A discriminant key is cheaper and keeps the
902
+ verb count down. Neither is urgent: the trigger is the second
903
+ jurisdiction, the same as GATE-2 and Q-8, so the three should be decided
904
+ together rather than one at a time.
905
+ - **Q-9** — Is Apache-2.0 the right outbound licence for a *data*
906
+ compilation, or should the data carry CC0 / CC BY 4.0 separately from
907
+ the code (REQ-PROV-4)? ADR 0004 settles the code licence and leaves this
908
+ open deliberately — the data question was never put. GATE-6's trigger;
909
+ must be settled before the contribution path opens. The CLA/DCO half of
910
+ that question is now answered by REQ-PROV-7.
911
+ - **Q-11** — What is the delta suppression mechanism? REQ-SCOPE-3's
912
+ inheritance-by-absence is verified unsafe as stated: 33 CFR 83 leaves
913
+ Rule 28 "[Reserved]" and has no counterpart for `23(d)(ii)`/`(iii)`
914
+ ([verification](verification/2026-08-30-q6-q8.md), Claim 1), so a
915
+ `us/inland` delta that is merely silent there would inherit the `intl`
916
+ entries and assert international obligations on inland waters. A delta
917
+ needs explicit suppression records (tombstones) alongside overrides —
918
+ "this path/entry deliberately does not exist here", distinguishable from
919
+ "not yet transcribed". Decide the mechanism in the second-jurisdiction
920
+ bundle (GATE-1 re-take, GATE-2, Q-10); until then no non-`intl`
921
+ jurisdiction lands.
922
+ Also from the same verification pass, tracked on the global board rather
923
+ than here: four transcription defects in `data/rules.json` itself
924
+ (`21(a)`, `21(b)`, `23(b)`, `29(b)`) — a data fix, not a design
925
+ question.
926
+
927
+ ### From ADR 0005 (pencilled items)
928
+
929
+ Every item ADR 0005 records is pencil (`docs/conventions.md`), and each
930
+ pencilled item in the proposal behind it names what would settle it. They are
931
+ listed here, one line each, because the ADR is what makes them live. Most are
932
+ `colregs-engine`'s to settle rather than this package's; they are marked
933
+ *(engine)* where so, and this package's own are the ones that gate data.
934
+
935
+ - **Q-13** — Is `category` the right word for the field (against kind, type,
936
+ flavour, charge)? Settled by Mark, before REQ-CAT-1's field name ships.
937
+ - **Q-14** — Which category does each paragraph take? The proposal's table is
938
+ a first cut; settled paragraph by paragraph as Rules 1–19 are transcribed.
939
+ PR #24 settles the first sixteen and departs from the table once: 13(a) is
940
+ `precedence`, not `classification` (`Q-37`).
941
+ - **Q-15** — Which verification tool discharges each category (Alloy, Z3, TLA+,
942
+ STL, Rocq)? Settled by building one proof per category, not by argument.
943
+ *(engine)*
944
+ - **Q-16** — Are the invariant levels right as hard / safe / rule-level, and
945
+ are procedural and physical levels needed? Settled by the first level-3
946
+ invariant that does not fit. *(engine)*
947
+ - **Q-17** — What separation distance *d* defines the "safe" level? Fixed to
948
+ one value to start; settled by the sensitivity matrix of Q-22. *(engine)*
949
+ - **Q-18** — What is the dynamics model, and what is the list of dynamics
950
+ classes (tanker, ferry, yacht, …)? Settled by the first two-vessel
951
+ computation; the class list is a data question once it stabilises.
952
+ A first-cut class list now exists in data as `kin:dynamics`
953
+ (PR #22) so the situation record has something to carry; it is
954
+ pencil and the question is unchanged. `dynamics:unknown` stays in the set
955
+ whatever the list becomes.
956
+ - **Q-19** — What are the game's parameters — horizon *T*, terminal condition,
957
+ action cadence Δt, the admissible set *A*, the information assumption?
958
+ Settled by the sensitivity matrix, which is owed before the ontology moves
959
+ out of pencil. *(engine)*
960
+ - **Q-20** — Is the adversary rule-compliant, arbitrary within physics, or
961
+ both, and does the horizon hide the region behind it? Settled by computing
962
+ both and comparing. *(engine)*
963
+ - **Q-21** — Can the hybrid, partial-information game be encoded soundly in
964
+ UPPAAL TIGA/STRATEGO or KeYmaera X at all? Settled by a benchmark with
965
+ certified bounds, not by reading the tools' documentation. *(engine)*
966
+ - **Q-22** — Is the region computed offline per dynamics-class pair, or does
967
+ it have to be computed at runtime? Settled by the first two-vessel
968
+ computation's cost. *(engine)*
969
+ - **Q-23** — Is Rule 2(b) a duty where departure is necessary, and does the
970
+ departing vessel bear the burden? Settled by reading the cases (*The Bywell
971
+ Castle*, *Boy Andrew v St Rognvald*, both unverified), not by advocacy.
972
+ - **Q-24** — Are the four worked illustrations (R0, R1, R2,
973
+ `inconclusive-in-model`) actually in the regions they are said to be in?
974
+ They fix meanings, not numbers; settled by computing them. *(engine)*
975
+ - **Q-25** — Is the tractability tiering (findable under duress / with time /
976
+ likely missed) a real axis, and do its proxies measure it? Settled by
977
+ bridge-simulator or human-reliability evidence, not by the model. *(engine)*
978
+ - **Q-26** — How large is the relative-frame state space? The 10⁴–10⁶ figure
979
+ is a back-of-envelope guess; settled by a worksheet. *(engine)*
980
+ - **Q-27** — What are the field names for `category`, `subjects`, `when`,
981
+ `effect` and the widened `modality`? Settled when the first non-`display`
982
+ entry lands, and cheap to change until then.
983
+ Unchanged by PR #22, which names none of those five. The names it
984
+ does fix — `situation`, the four classes, the three subjects — are
985
+ REQ-CAT-6's and are equally pencil.
986
+ - **Q-28** — What namespace distinguishes the two subjects of a two-subject
987
+ entry (`own:` / `other:` is the working proposal)? No such segment exists in
988
+ `docs/identifiers.md`; settled before Rule 18 lands, and it is an
989
+ identifier decision under REQ-MODEL-10.
990
+ **Decided in pencil 2026-09-04** (PR #22): `<subject>:<class>:<key>`
991
+ with subject `own`/`other`/`pair` and class `fact`/`kin`/`geo`/`hist`, and a
992
+ bare key meaning `own:`. Written up in `docs/identifiers.md` §"Two
993
+ subjects", required by REQ-CAT-6, and exercised by
994
+ `fixtures/situation-fixtures.json`. Three things the working proposal did
995
+ not have: a third subject, because range and in-sight belong to the
996
+ encounter and not to either vessel; a class segment, so kinematics and
997
+ history are new classes rather than new fact keys; and the bare-key default,
998
+ which is what makes the whole thing additive under REQ-MODEL-10 — no
999
+ existing identifier is renamed or repointed, and `own`/`other`/`pair` become
1000
+ reserved at the head of the identifier space, which is the only cost.
1001
+ Settled for good by Rule 18 being written against it.
1002
+ - **Q-29** — What are the file names and schemas for the invariants file and
1003
+ the region grid, and how does a level-3 invariant carry `jurisdiction`?
1004
+ Settled when the first invariant is written down.
1005
+ - **Q-30** — What does the `care`/`meta` registry look like as a file — its
1006
+ name, its schema, and its relationship to `known_omissions`? Settled by
1007
+ REQ-CAT-2's implementation, which is the next data change after this ADR.
1008
+
1009
+ **Decided in pencil, PR #23.** The registry is `represented_paragraphs`,
1010
+ a sibling array to `known_omissions` in `data/applicability.json`. Each
1011
+ record: `id` (paragraph-derived, e.g. `2a`), `jurisdiction`, `cite`,
1012
+ `category` (`care` or `meta`), and a one-sentence `note`; no `when`, no
1013
+ `lights` — a registry record states that the paragraph is represented
1014
+ and evaluated by nothing here, never a predicate. Holds the `2(a)` and
1015
+ `2(b)` records this PR adds. `✎` under `docs/conventions.md`: the file
1016
+ name and schema stay open to a better idea, logged when changed.
1017
+
1018
+ ### From the first two-subject data (PR #24)
1019
+
1020
+ Rules 4, 11, 19(a) and 18(a)–(f) are the first entries written against ADR
1021
+ 0005's model. What the model expressed, and what it could not, is recorded
1022
+ here rather than in a commit message. All pencil.
1023
+
1024
+ **Decided in pencil 2026-09-04 (PR #24)**, answering the data half of `Q-27`:
1025
+ the field names are `category`, `subjects` and `effect`, and `effect` is
1026
+ `{own, other}` roles for a `precedence` entry and `{part, section,
1027
+ applies_rules}` for a `scope` one. Written up in `docs/identifiers.md`
1028
+ §"Effects", required by `REQ-CAT-8`, and exercised by
1029
+ `fixtures/situation-fixtures.json`. `Q-28`'s namespace is settled for good by
1030
+ the same PR — Rule 18 is written against it and it held, with one addition:
1031
+ a fifth class `env`, `pair`-only, because a narrow channel and a traffic
1032
+ separation scheme are properties of the water and belong to neither vessel
1033
+ nor to the pair's geometry. `fixtures/situation-fixtures.json` had already
1034
+ named that gap before the class existed.
1035
+
1036
+ - **Q-31** — `modality` is a single closed value, and 18(c), 18(d)(i) and 9(a)
1037
+ each carry two deontic qualifications at once: a practicability caveat
1038
+ ("so far as possible", "if the circumstances of the case admit") *and* the
1039
+ duty itself. 18(c) is expressible because `shall-if-practicable` already
1040
+ exists; 18(d)(i) is not, and its caveat is dropped with a `gap` note on the
1041
+ entry. Settled by deciding whether practicability is a second field beside
1042
+ `modality` rather than a value inside it — which is the same question
1043
+ `modality_by` answers for the light rules, and should probably be answered
1044
+ the same way. **Narrowed, not settled, 2026-09-04 (PR #25):** 18(d)(i) is now
1045
+ `shall-if-practicable` with `effect.own: shall-not-impede`, so the two
1046
+ qualifications sit in two fields and neither is dropped. That works only
1047
+ because this duty happens to be a *role*, which `effect` already carries;
1048
+ 9(a)'s "if the circumstances of the case admit" has no second field to move
1049
+ into, and the general question is untouched.
1050
+ - **Q-32** — **decided in pencil 2026-09-04 (PR #25): a derived fact.**
1051
+ `fact:activity` is a *display* axis: it says what lights a vessel shows, not
1052
+ what her rank is under Rule 18, and the two disagree. `fact:rule18_class` is
1053
+ the rank, declared in a new `derived` section of `data/facts.json` with a
1054
+ decode table that is its definition, in the same style as the SignalK
1055
+ `navigation.state` table. Seven values — `rule18_class:nuc`, `:ram`,
1056
+ `:fishing`, `:wig`, `:cbd`, `:sail`, `:power` — each cited to the Rule 3
1057
+ paragraph that defines it. The three cases this question named are decoded
1058
+ rather than hand-listed: `activity:mine` (27(f)) and `activity:diving`
1059
+ (27(e)) to `rule18_class:ram` by 3(g), `activity:trawling` to
1060
+ `rule18_class:fishing` by 3(d), and the 27(c) tow that severely restricts the
1061
+ pair — the one the old predicates could not catch at all — to
1062
+ `rule18_class:ram`, via a new boolean `fact:tow_restricts_deviation`. Every
1063
+ Rule 18, 9 and 10 entry reads the class; no `precedence` entry reads
1064
+ `fact:activity` any more, and a test enforces that. `fact:activity` itself is
1065
+ unchanged and no entry that reads it was touched. What is *not* settled: the
1066
+ eighth rank Rule 18 distinguishes is the seaplane of 3(e), and it has no
1067
+ value here because there is no fact for being a seaplane — 18(e) stays in
1068
+ `known_omissions`. A vessel under oars decodes to nothing, deliberately: Rule
1069
+ 18 does not rank her, and 25(d)(ii) is a lights permission rather than a
1070
+ rank. Both are recorded in the fact's own `undecodable` list. The
1071
+ alternatives — a second refinement table, or a per-value attribute on the
1072
+ activity axis — were declined because both would have put the rank back
1073
+ inside the display axis, which is the thing this question says is the
1074
+ mistake.
1075
+ - **Q-33** — **decided in pencil 2026-09-04 (PR #25): the predicate language
1076
+ grows `not` and `any_of`.** A `when` was a conjunction with no negation and
1077
+ no disjunction, and Rule 18 needed both. `{"not": C}` is a constraint on one
1078
+ fact; `any_of` is disjunction, holding sub-predicates as a key of a `when`
1079
+ and constraints as the value of a fact. Both are implemented in `satisfies`
1080
+ and one shared walker, so the one-subject and two-subject evaluators get them
1081
+ without a second copy. **`not` over an absent fact is unsatisfied**, like
1082
+ every constraint over an absent fact, so `{"not": C}` and `C` are both false
1083
+ where the fact is missing and the language is not classical there — the point
1084
+ being that a duty is never laid on a vessel because a consumer left a field
1085
+ out. That is also why `not` is a constraint and never a key of a `when`: a
1086
+ predicate-level negation would be satisfied by silence. 18(d)(i) and the
1087
+ 18(a) family are now written as the negations their paragraphs state, over
1088
+ `fact:rule18_class` rather than over the activity axis; 9(b) and 10(j) each
1089
+ collapse from two entries to one with `any_of`. The generated-complement
1090
+ alternative was declined: it would have produced a predicate no reader could
1091
+ check against the rule text, to avoid a language feature the rules themselves
1092
+ use in plain words.
1093
+ - **Q-34** — A `shall-not-impede` entry names a duty toward `other`, but the
1094
+ paragraphs identify the protected vessel by a property this package does not
1095
+ carry: "a vessel which can safely navigate only within a narrow channel"
1096
+ (9(b), 9(d)), "any vessel following a traffic lane" (10(i), 10(j)), and a
1097
+ CBD vessel "exhibiting the signals in Rule 28" (18(d)(i)). `pair:env:*` says
1098
+ where the encounter is, not which vessel is confined to it, so those entries
1099
+ are wider than their paragraphs and could assert a duty owed to a third
1100
+ vessel. Settled by deciding whether the protected-vessel property is a
1101
+ per-vessel fact, and whether it is a fact at all or a consumer's judgement.
1102
+
1103
+ **Decided in pencil 2026-09-05, for the 9(b)/9(d) and 10(i)/10(j) half: the
1104
+ protected-vessel property is a per-vessel fact, consumer-supplied like
1105
+ `pair:env:narrow_channel` and `pair:env:traffic_lane` are.** `fact:confined_to_channel`
1106
+ and `fact:following_traffic_lane` name it, in the same shape as the existing
1107
+ `fact:near_channel` and `fact:obstruction_exists`; entries `9b`, `10i` and
1108
+ `10j` now read `other:fact:confined_to_channel`/`other:fact:following_traffic_lane`
1109
+ and their `gap` fields are closed. `9(d)` has no entry yet, so it inherits
1110
+ the same fact when one is written. **18(d)(i) is deliberately left open**:
1111
+ "exhibiting the signals in Rule 28" is a display-compliance fact rather than
1112
+ a vessel-identity one, and this package models night lights only (see
1113
+ CLAUDE.md "Coverage") — settling it is a narrower, separate decision.
1114
+ - **Q-35** — 8(f)(iii)'s antecedent is "a vessel, the passage of which is not to
1115
+ be impeded" — the *output* of another norm, not a fact. A precedence
1116
+ predicate reads only facts, so entry `8f3` reads the risk-of-collision half
1117
+ alone and applies to every pair with risk of collision. Settled by deciding
1118
+ whether a norm may read another norm's effect, which is the same question a
1119
+ `conduct` monitor will ask about role and phase.
1120
+ - **Q-36** — Rule 18(a)(iv) and 18(d)(i) are both in force between a sailing
1121
+ vessel and a vessel constrained by her draught: the CBD vessel gives way, and
1122
+ the sailing vessel must not impede her. Neither overrides the other and the
1123
+ model records both, so one subject holds `stand-on` and `shall-not-impede`
1124
+ at once. The test suite pins it as a finding rather than asserting it away.
1125
+ Settled by reading 8(f)(ii) against the cases, not by picking a role.
1126
+ - **Q-37** — 13(a) is `classification` in ADR 0005 §1 and in the proposal's
1127
+ first-cut table, but it is the one paragraph of Rule 13 that assigns a role
1128
+ and a `classification` entry has nowhere to put one. Entry `13a` is
1129
+ `precedence` here, with 13(b)'s sector test left for the `classification`
1130
+ entry that would set the `hist:was_overtaking` latch. Settled with the rest
1131
+ of `Q-14`, paragraph by paragraph.
1132
+
1133
+ **Closed in pencil 2026-09-04 (PR #26).** 13(b) is now written, as *two*
1134
+ `classification` entries rather than one — `13b-overtaking` and
1135
+ `13b-overtaken` — because the encounter type belongs to the pair and reading
1136
+ aspect alone classified the overtaken vessel's side of the same encounter as
1137
+ a crossing. 13(a) stays `precedence`, and its predicate now carries both
1138
+ halves of "any vessel overtaking any other": the 13(b) sector and the 13(d)
1139
+ latch, as an `any_of`, which closes the gap the entry recorded. 13(d) is a
1140
+ third `classification` entry, reading history and no geometry at all. The
1141
+ split confirms the thing ADR 0005 §1 was really defending — one category per
1142
+ paragraph — and costs one paragraph two entries, which the entry-id suffix
1143
+ scheme was already built for.
1144
+ - **Q-38** — 9(d), 18(d)(ii), 18(e), 18(f)(ii), 1(a)–(e) and 20(b)–(c) are
1145
+ recorded in `known_omissions` rather than modelled: 9(d) needs the channel's
1146
+ axis, 18(e) needs a fact for being a seaplane, 20(b)–(c) need time of day,
1147
+ and 1(a)–(e) are addressed to an authority rather than to a vessel. Settled
1148
+ one at a time as the facts they need land; none blocks the rest of Part B.
1149
+ - **Q-39** — Rule 4's `scope` entry has an empty `when`, because "any condition
1150
+ of visibility" is the absence of a condition. That makes it unfalsifiable —
1151
+ `REQ-VERIFY-3`'s "excluded by at least one fixture" half cannot be satisfied
1152
+ and the test exempts it explicitly. Settled by deciding whether an ungated
1153
+ norm should be a registry record like `represented_paragraphs` rather than an
1154
+ entry with a vacuous predicate.
1155
+
1156
+ ### From the classification norms (PR #26)
1157
+
1158
+ Rules 7(d), 12, 13(b)–(d), 14 and 15 are the first `classification` entries and
1159
+ the second family of `precedence` ones. All pencil. What the model expressed is
1160
+ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1161
+
1162
+ - **Q-40** — **Rule 12 is `precedence`, not `classification`.** ADR 0005 §1 and
1163
+ the proposal's table both file it under `classification`; it produces a role
1164
+ — "one of them shall keep out of the way of the other" — and a
1165
+ classification effect has nowhere to put one, which is `Q-37`'s argument
1166
+ applied a second time. Two sailing vessels are still in a head-on, a crossing
1167
+ or an overtaking; Rule 12 says which of them gives way, not what kind of
1168
+ meeting it is. 12(b) is a `definition` and is the cite on `kin:wind_side`
1169
+ rather than an entry. The second half of the question is narrower and worse:
1170
+ 12(a) says "two sailing vessels", which is 3(c), but entries `12a1`–`12a3`
1171
+ read `rule18_class:sail` instead, so a vessel engaged in fishing under sail
1172
+ falls out of Rule 12 — because letting her in would have given her a give-way
1173
+ duty under 12(a) and a stand-on role under 18(b)(iii) with no override
1174
+ between them. Narrowed deliberately and recorded on each entry. Settled with
1175
+ the rest of `Q-14`, and by deciding whether Rule 18 overrides Rules 12–15 the
1176
+ way Rules 9, 10 and 13 override Rule 18 — a `rel:overrides` nobody has yet
1177
+ written down. *Which mechanism* is settled: REQ-MODEL-13 makes it a
1178
+ relation, not a gate, because Rule 12 and Rule 15 do apply to the vessel and
1179
+ Rule 18 only displaces the role.
1180
+
1181
+ **Decided in pencil 2026-09-05 (PR #35): Rule 12 reads 3(c), and Rules 13
1182
+ and 18 override it.** The three Rule 12 entries gate both subjects on
1183
+ `fact:propulsion: propulsion:sail`, which is 3(c)'s sailing vessel, and no
1184
+ longer on `rule18_class:sail`; a vessel engaged in fishing under sail, or
1185
+ not under command under sail, is inside Rule 12 as the paragraph says. The
1186
+ conflict the narrowing was avoiding is resolved the way the Rules resolve
1187
+ it: Rule 18's chapeau excepts Rules 9, 10 and 13 and no others, so every
1188
+ Rule 18 norm that can be in force between two sailing vessels — 18(b)(i)–(iii)
1189
+ from the ordinary sailing vessel's side, 18(c)(i)–(ii) from the fishing
1190
+ vessel's — carries `rel:overrides` against `12a1`–`12a3`. 13(a), being
1191
+ "notwithstanding" the whole of Sections I and II, overrides them too, which
1192
+ it had to: two sailing vessels in an overtaking held 13(a)'s and 12(a)(ii)'s
1193
+ roles at once and nothing had noticed. Two fixtures and a sweep over sailing
1194
+ fleets — every tack and windward combination, plain and with one vessel
1195
+ ranked by Rule 18 — assert never both give-way, never both stand-on, and no
1196
+ two helm roles after resolution. What it leaves: between two sailing vessels
1197
+ Rule 18 does not order — one not under command, one restricted in her
1198
+ ability to manoeuvre — Rule 12 is now the only norm in force, and it lays a
1199
+ helm duty on a vessel that may be unable to discharge it; that is Rule 2's
1200
+ region (ADR 0005 §5) and is recorded, not gated.
1201
+
1202
+ **Decided in pencil 2026-09-05 (PR #46): Rule 15 reads 3(b), and Rule 18
1203
+ overrides it too.** The same question answered the other way for Rule 15.
1204
+ `15a-give-way` kept the four Rule 18 ranks — NUC, RAM, fishing and WIG —
1205
+ out of Rule 15 by negating them on both subjects in its own predicate; the
1206
+ negation is gone, both subjects gate on `fact:propulsion: propulsion:power`
1207
+ which is 3(b), and `18a1`–`18a3`, `18c1`–`18c2` and `18f1` carry
1208
+ `rel:overrides` against it. The gate was not merely the relation said in
1209
+ the wrong place. It produced the right roles wherever Rule 18 speaks and
1210
+ *no* role at all where Rule 18 is silent: two vessels engaged in fishing
1211
+ under power, and a vessel not under command crossing one restricted in her
1212
+ ability to manoeuvre under power, are pairs Rule 18 does not order, and
1213
+ neither vessel took a helm role from any entry. Both are fixtures now, and
1214
+ both failed on the data before the change — `15a-crossing` classified the
1215
+ encounter and nothing assigned a role. What it leaves is Rule 12's residue
1216
+ again: on those unordered pairs Rule 15 lays a give-way duty on a vessel
1217
+ that may be unable to discharge it, which is Rule 2's region and is
1218
+ recorded, not gated. `13a` needs no override against `15a-give-way` — the
1219
+ entry excludes every overtaking by the `hist:was_overtaking` latch and by
1220
+ 13(b)'s sector — and a test pins that absence so it stays a reason rather
1221
+ than an oversight. The hand-list of six is asserted complete by a derived
1222
+ check: every Rule 18 entry that assigns a helm role and does not gate a
1223
+ subject to a sailing vessel must carry the override, so a Rule 18 paragraph
1224
+ written later cannot join Rule 15 silently. The steady-bearing sweep gained
1225
+ power fleets — each rank on one side, on both sides, and against each other
1226
+ rank — and every one of the six overrides fails the sweep when removed. The
1227
+ fixtures file's `override_note` stays as it is: it says `expect` names every
1228
+ entry a situation selects, including one a `rel:overrides` then displaces,
1229
+ which is still how the fixtures are written and is what makes these six
1230
+ overrides observable rather than invisible.
1231
+
1232
+ The category half — Rule 12 as `precedence` — is unchanged and stays with
1233
+ `Q-14`.
1234
+ - **Q-41** — **13(c) and 14(c) invert the absent-fact rule.** "When a vessel is
1235
+ in any doubt as to whether she is overtaking, she shall assume that this is
1236
+ the case" is a duty that fires on the *absence* of knowledge, and the
1237
+ predicate language's one firm commitment is that an absent fact satisfies
1238
+ nothing (`Q-33`). Modelling either paragraph means a `doubt` boolean, which
1239
+ asks a consumer to report a mental state, or reading absence as assertion,
1240
+ which reverses the rule the language is built on. Both are in
1241
+ `known_omissions`. 12(a)(iii) is the same shape and *is* modelled, only
1242
+ because 12(b) makes the uncertainty a declared value of a fact that is
1243
+ present — `wind_side:unknown`. Settled by deciding whether "in doubt" is a
1244
+ fact of the situation at all; if it is, it is one fact and it closes three
1245
+ paragraphs.
1246
+ - **Q-42** — **7(d)(ii) is recorded, not modelled.** "Risk may sometimes exist
1247
+ even when an appreciable bearing change is evident, particularly when
1248
+ approaching a very large vessel or a tow or when approaching a vessel at
1249
+ close range." Two of the three limbs have no fact behind them — the Rules
1250
+ give no length for "very large" and no distance for "close range", so both
1251
+ would be numbers this package invented rather than thresholds on a quantity a
1252
+ paragraph names, which is what saves 7(d)(i)'s constant. The third limb, a
1253
+ tow, is expressible. It is not written alone because the modality is the real
1254
+ obstacle: "may sometimes exist" is neither a deeming rule nor a permission,
1255
+ and the vocabulary has no value for an instruction to the mariner's
1256
+ judgement. Settled by deciding whether the vocabulary gains one — `Q-31`'s
1257
+ neighbour, not its duplicate.
1258
+ - **Q-43** — **The partition needs history to be present, and says nothing when
1259
+ it is absent.** `14b` and `15a-crossing` are gated on `hist:was_overtaking`
1260
+ being `false` on both subjects, which is 13(d)'s requirement and the only way
1261
+ the three encounter types stay disjoint once the latch is set. Because absent
1262
+ is absent, a situation that omits the fact is classified as *no encounter at
1263
+ all* rather than as a head-on or a crossing. That is conservative in the
1264
+ right direction and completely silent, which is the wrong way to be
1265
+ conservative: a consumer who forgets one boolean gets an empty answer that
1266
+ looks like a lawful one. The neighbouring finding: two sailing vessels get no
1267
+ encounter type either, because Rules 14 and 15 are gated on two power-driven
1268
+ vessels and Rule 12 has no deeming paragraph — that one is a property of the
1269
+ Rules rather than of the model. Settled by deciding whether an engine may
1270
+ distinguish "no encounter" from "cannot say", which is the status alphabet of
1271
+ ADR 0005 §5 and belongs to `colregs-engine`.
1272
+ - **Q-44** — **`kin:wind_side` is not kinematics.** Rule 12 needs to know which
1273
+ side each vessel has the wind on. It is a per-vessel Part B fact, so it
1274
+ cannot go in the fact record (`REQ-CAT-4`: the record does not change, and a
1275
+ display consumer must never be asked for it) and it cannot go in `pair` (it
1276
+ is not symmetric), which leaves `kin` — a class whose declared meaning is
1277
+ where a vessel is, where she is pointing, how fast she is going and turning,
1278
+ and what she handles like. A sailing vessel's tack is none of those. Filed
1279
+ there rather than fixed by widening the class note, because widening it would
1280
+ make `kin` mean "per-vessel and not in the fact record", which is a
1281
+ description of the leftovers and not of a class. Settled by the second
1282
+ per-vessel Part B fact that is not kinematics: one is an awkwardness, two is
1283
+ a missing class.
1284
+ - **Q-45** — **One entry, two paragraphs.** `14a` cites 14(a), which states the
1285
+ situation, and reads 14(b), which fixes the geometry that deems it to exist.
1286
+ The paragraph is supposed to be the unit (ADR 0001), and Rule 13 splits the
1287
+ same way into two entries only because 13(a) also produces a role. Here there
1288
+ is nothing for a second entry to produce. Settled by deciding whether a
1289
+ deeming paragraph that produces no effect of its own gets an entry anyway —
1290
+ the same question `Q-39` asks about an ungated norm, from the other end.
1291
+
1292
+ **Decided in pencil 2026-09-05 (PR #36): the head-on classification cites
1293
+ 14(b), and 14(a) is `conduct`.** The question assumed 14(b) produced no
1294
+ effect of its own. It produces the only effect the entry has: "such a
1295
+ situation shall be deemed to exist when…" is the deeming test, and
1296
+ `{"encounter": "head-on"}` is what a deeming test yields — exactly as
1297
+ `13b-overtaking` and `13b-overtaken` cite 13(b), the deeming paragraph,
1298
+ and not 13(a). 14(a) states the situation in words ("reciprocal or nearly
1299
+ reciprocal courses") and imposes the duty ("each shall alter her course to
1300
+ starboard"); the duty is `conduct`, and the words are what 14(b) makes
1301
+ checkable. So the entry is `14b`, cites 14(b), and reads nothing 14(b) does
1302
+ not fix; 14(a) joins `known_omissions` as conduct beside 18(d)(ii), and
1303
+ `14a` is retired in `retired_entry_ids` and, because v0.1.3 shipped it,
1304
+ recorded in `data/deprecated-identifiers.json` with `14b` as its
1305
+ replacement — the registry's first record (REQ-MODEL-11). The
1306
+ general question — whether a paragraph with no effect of its own gets an
1307
+ entry — is `Q-39`'s and is untouched; this paragraph turned out not to be an
1308
+ instance of it.
1309
+ - **Q-46** — **"Coming up with" is a comparison of two facts.** 13(b) deems a
1310
+ vessel to be overtaking when *coming up with* another from more than 22.5°
1311
+ abaft her beam. That is `own:kin:sog_kn` against `other:kin:sog_kn`, and the
1312
+ predicate language compares a fact to a constant and never one fact to
1313
+ another — the same wall `12a2` hits on "both have the wind on the same side",
1314
+ which it gets over only because that comparison has two values to enumerate
1315
+ and this one has infinitely many. `pair:geo:tcpa_s > 0` stands in: the pair
1316
+ is closing, and closing from abaft the beam is coming up. It excludes the
1317
+ vessel drawing away astern, which is the case that mattered, and admits a
1318
+ pair closing because the vessel ahead has stopped, which is not an overtaking
1319
+ in seamanship and is one here. Settled by deciding whether the language gains
1320
+ fact-to-fact comparison — a bigger change than `not` and `any_of` were, and
1321
+ not one to make for a single paragraph.
1322
+ - **Q-47** — **13(d)'s latch never clears.** The paragraph runs "until she is
1323
+ finally past and clear", nothing in the fact vocabulary carries that, and so
1324
+ in this model `hist:was_overtaking` is set by a consumer and cleared by a
1325
+ consumer while entry `13d` classifies an overtaking for as long as it stands.
1326
+ Not approximated with a range or a bearing: past and clear is a seamanship
1327
+ judgement of the same kind as risk of collision, and a threshold for it would
1328
+ be a number invented rather than declared. Settled by whatever settles the
1329
+ `conduct` monitors, which are the things that watch a duty end rather than
1330
+ begin.
1331
+ - **Q-48** — **Nothing checks that a situation is geometrically possible.**
1332
+ `own:geo:rel_bearing_deg`, `other:geo:rel_bearing_deg`, the two
1333
+ `kin:heading_deg` and the two `kin:sog_kn` are six facts related by two
1334
+ equations, and the situation record enforces neither. A consumer — or a
1335
+ fixture — can state a pair of bearings that no two headings produce, and the
1336
+ entries will classify it without complaint. It bites in one visible place:
1337
+ where both vessels have the other on the starboard side, which cannot happen
1338
+ on a collision course, `15a-give-way` applies to both of them and the "never
1339
+ both give-way" property fails. The fixtures added here are built from a
1340
+ heading and a bearing so that they are consistent by construction, and the
1341
+ file says so; the model is not. Settled by deciding whether the record gains
1342
+ a consistency check, whether the relative quantities become derived facts
1343
+ like `fact:rule18_class` — computed from the two kinematic states rather than
1344
+ supplied beside them — or whether it is the consumer's problem and says so.
1345
+
1346
+ **Decided in pencil 2026-09-05: the record gains a consistency check,
1347
+ declared in data and enforced in the suite.** `data/facts.json` declares the
1348
+ equations under `situation.geometry.consistency` — the two relative bearings
1349
+ are two readings of one line of sight (`own + own heading + 180 ≡ aspect +
1350
+ other heading`), positions reproduce range and both bearings, and the two
1351
+ headings and speeds reproduce CPA, TCPA and bearing rate — with tolerances,
1352
+ and `REQ-VERIFY-8` requires the suite to apply them. A quantity a record does
1353
+ not state constrains nothing, so the check says "not inconsistent" rather
1354
+ than "possible" where a record is sparse. What it found: all sixteen fixtures
1355
+ that state kinematics satisfied the heading and position equations, and every
1356
+ one of them failed the motion equations, because their CPA, TCPA and
1357
+ bearing-rate values were placeholders. They were re-derived from the headings
1358
+ and speeds. Two cases could not keep their story: the R1 head-on had both
1359
+ vessels with the other to starboard, which no speeds make a steady bearing,
1360
+ and is recast as one; the 13(d) latch case is 400 m abeam with the CPA
1361
+ already past, and lost `7d1`. The partition sweep now constructs positions
1362
+ and headings for every bearing pair and is consistent at every point. The
1363
+ "never both give-way" property is asserted over a sweep of steady-bearing
1364
+ geometries — every relative bearing, several speed pairs, both intercept
1365
+ solutions — where it is a theorem rather than an observation:
1366
+ `u·sin(own bearing) = −v·sin(aspect)`, so the two bearings lie on opposite
1367
+ sides and 15(a) can name only one vessel. The both-starboard counterexample
1368
+ is pinned as a record the check rejects. What is *not* settled, and is
1369
+ pinned too: the theorem is exact only at a bearing rate of zero, and
1370
+ 7(d)(i)'s pencilled 1°/min admits a slow, close, starboard-to-starboard
1371
+ passing just outside the head-on cone on which risk is deemed and both
1372
+ vessels are give-way. That is 14(c)'s doubt case and belongs with `Q-41`,
1373
+ not here. Of the three options this question named, "the consumer's problem"
1374
+ is closed — the definition a consumer would need is now in the data — and
1375
+ the relative quantities as derived facts stays open in the block's
1376
+ `settled_by`.
1377
+
1378
+ - **Q-49** — **Must `13d`'s effect cross the Section II/III boundary for Rule 19(d)(i) to be expressible?**
1379
+ - *broad* — drop `13d`'s `pair:geo:in_sight` gate so `encounter: overtaking` is visible in Section III; breaks the scope invariant.
1380
+ - *narrow* — `13d` stays gated; a 19(d)(i) entry reads `own:hist:was_overtaking`/`other:hist:was_overtaking` directly, as `14b` and `15a-crossing` already do.
1381
+ - Default: narrow (nothing changes).
1382
+ - Recommendation: narrow — the test named below shows the fact resolves out of sight
1383
+ (`Q-49: hist:was_overtaking resolves out of sight; 13d does not fire`, `test/data.test.mjs`).
1384
+
1385
+ ### From the Part B invariants (P4.1)
1386
+
1387
+ Eight places where the rule text admits two readings, recorded here under
1388
+ `REQ-INV-5`. Each is the maintainer's, and each names the data's default so
1389
+ nothing is blocked while open.
1390
+
1391
+ - **Q-50** — **Does risk of collision gate Rules 13 and 18?** 14(a) and 15(a)
1392
+ say "so as to involve risk of collision"; Rule 13 and Rule 18 do not.
1393
+ *Wide:* they attach whenever in sight and the geometry holds — Rule 11 is the
1394
+ only gate Section II states — so a vessel overtaking a mile clear abeam is
1395
+ give-way and Rule 16 binds her. *Narrow:* Section II's duties attach only with
1396
+ risk of collision; 14 and 15 are emphasis. Default **wide**: `13a`, `13b-*`,
1397
+ `13d` and every Rule 18 entry read `in_sight` only. No recommendation.
1398
+ - **Q-51** — **What arms 13(d)'s latch?** *A:* 13(b)'s deeming, at the first
1399
+ state the geometry holds. *B:* 13(a)'s duty actually attaching. They differ
1400
+ where the geometry holds but a condition on 13(a) does not — `Q-50`'s
1401
+ surface. Default **A**: `hist:was_overtaking` is "was, at some earlier point
1402
+ in this encounter, an overtaking vessel" and `13b-overtaking` is geometry.
1403
+ No recommendation; downstream of `Q-50`.
1404
+ - **Q-52** — **What does 13(d)'s latch forbid?** *Narrow:* reclassification to
1405
+ *crossing* only, as the paragraph says, leaving head-on to Rule 14 on the
1406
+ geometry of the moment. *Broad:* the encounter stays an overtaking and no
1407
+ other Section II classification attaches. Both preserve the duty; they differ
1408
+ on encounter type, which Rule 17's phases and 14(a) hang off. Default
1409
+ **broad**: `13d` yields `encounter: overtaking` from history alone, `14b` and
1410
+ `15a-crossing` gate on `was_overtaking: false`. No recommendation.
1411
+ - **Q-53** — **Does 17(a)(ii) suspend 17(a)(i)'s duty, or add an exception?**
1412
+ *Suspension:* "may, however" lifts the duty once non-compliance is apparent;
1413
+ a monitor then flags nothing. *Exception:* the duty stands and a departure is
1414
+ lawful only as action to avoid collision by her manoeuvre alone; a monitor
1415
+ flags any other alteration. No default (Rule 17 has no entry). Recommend
1416
+ **exception**: 17(a)(ii) describes an action, not a proviso, and leaves a
1417
+ monitor something to check — a drafting argument, not a source.
1418
+ - **Q-54** — **Are Rule 17's phases monotone?** *Latching:* one three-valued
1419
+ monotone latch per stand-on vessel per encounter; late compliance does not
1420
+ take the permission away. *Re-evaluating:* each phase is a predicate on the
1421
+ current state and the vessel may fall back — and must she then hold her *new*
1422
+ course and speed? TLC distinguishes them on a four-state trace, so settle
1423
+ before P4.2. No default. Recommend **latching**: one late alteration does not
1424
+ restore reliance — an argument from purpose, not a source.
1425
+ - **Q-55** — **What does a visibility transition do to Section II state?**
1426
+ Rule 11 and 19(a) switch on the current state; no paragraph says what
1427
+ becomes of a 13(d) latch or a Rule 17 phase. *Persisting:* they belong to the
1428
+ encounter and survive the fog. *Resetting:* Section II starts afresh on the
1429
+ geometry when sight is regained — the reclassification 13(d) forbids, via
1430
+ visibility. No default (nothing is temporal). Recommend **persisting**, which
1431
+ `INV-13d`'s "same encounter" is written for; likeliest surprising TLC trace.
1432
+ - **Q-56** — **The third visibility state: a hole, or closed by the model?**
1433
+ Not in sight *and* not in or near restricted visibility (clear weather, beyond
1434
+ visual range, radar contact) is outside Rule 11 and 19(a): Section I only.
1435
+ *Hole:* represent it; a fact for "in or near restricted visibility" is owed.
1436
+ *Closed:* treat not-in-sight as Section III. Default **closed**: `19a` drops
1437
+ the second conjunct, recorded as a `gap`. Recommend **hole**: the default is
1438
+ safe for a switching consumer and unsafe for a traceability claim.
1439
+ - **Q-57** — **The baseline for "keep her course and speed"?** 17(a)(i) fixes
1440
+ no instant. *Attachment:* course and speed when the role attached; any later
1441
+ change is a departure — checkable, occasionally absurd. *Steady state:* the
1442
+ vessel's settled condition, so a turn in progress may complete — seamanlike,
1443
+ and needs a definition of "settled" the Rules lack. No default. Recommend
1444
+ **attachment**, with the departure tolerance an explicit monitor parameter.
1445
+
1446
+ Two decisions taken in pencil, reversible in one edit: the invariants live in
1447
+ their own document under `REQ-INV-1`–`REQ-INV-7` (§4.2 says why), and the id
1448
+ scheme is `REQ-INV-2`'s — cheap to change until P4.2 cites an id from a TLA+
1449
+ module, expensive after.