colregs 0.3.0 → 0.3.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 (44) hide show
  1. package/README.md +13 -11
  2. package/data/applicability.json +478 -503
  3. package/data/facts.json +22 -22
  4. package/data/geometry.json +8 -8
  5. package/data/i18n/en.json +27 -0
  6. package/data/i18n/fi.json +25 -0
  7. package/data/images.json +32 -32
  8. package/data/operations.json +79 -0
  9. package/data/rules.json +5 -0
  10. package/data/version.json +1 -1
  11. package/docs/adr/0006-json-schema-and-identifier-diff.md +2 -0
  12. package/docs/adr/0011-api-shape.md +7 -7
  13. package/docs/adr/0012-trace-and-rule2-departure-api.md +2 -2
  14. package/docs/adr/0014-engine-interface-owned-by-colregs.md +103 -0
  15. package/docs/adr/0015-rule-ids-are-paragraph-keys.md +191 -0
  16. package/docs/adr/0016-encounter-roles-are-pooled-across-frames.md +82 -0
  17. package/docs/adr/0017-closed-vocabularies-are-prefixed-identifiers.md +105 -0
  18. package/docs/budgets.json +8 -15
  19. package/docs/decisions.md +6 -0
  20. package/docs/identifiers.md +121 -109
  21. package/docs/maritime-sources.md +58 -0
  22. package/docs/normative-language.md +103 -0
  23. package/docs/part-b-invariants.md +48 -45
  24. package/docs/requirements.md +147 -138
  25. package/fixtures/applicability-fixtures.json +190 -190
  26. package/fixtures/situation-fixtures.json +870 -599
  27. package/package.json +1 -1
  28. package/schema/applicability-fixtures.schema.json +4 -13
  29. package/schema/applicability.schema.json +77 -77
  30. package/schema/conduct-evaluation.schema.json +135 -0
  31. package/schema/display-evaluation.schema.json +146 -0
  32. package/schema/encounter-evaluation.schema.json +109 -0
  33. package/schema/evaluation.schema.json +149 -0
  34. package/schema/fact-record.schema.json +30 -0
  35. package/schema/facts.schema.json +4 -4
  36. package/schema/i18n-catalog.schema.json +47 -0
  37. package/schema/operations.schema.json +124 -0
  38. package/schema/rule2-departure-finding.schema.json +72 -0
  39. package/schema/rule2-departure-model.schema.json +159 -0
  40. package/schema/situation-fixtures.schema.json +30 -127
  41. package/schema/situation.schema.json +72 -0
  42. package/schema/trace.schema.json +33 -0
  43. package/data/deprecated-identifiers.json +0 -7
  44. package/schema/deprecated-identifiers.schema.json +0 -29
@@ -53,10 +53,10 @@ Neither consumer lives in this repo.
53
53
  | **paragraph path** | The citation unit: `27(a)(i)`, `25(d)(ii)`. Not the rule number. |
54
54
  | **fact record** | A set of facts about one vessel at one moment; the input. |
55
55
  | **entry** | One applicability record: predicate → lights/refs → modality → citation. |
56
- | **modality** | `shall` / `may` / `shall-if-practicable`. |
56
+ | **modality** | `modality:shall` / `modality:may` / `modality:shall-if-practicable`. |
57
57
  | **jurisdiction** | A body of rules: `intl`, `us/inland`, `ca/inland`, … |
58
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. |
59
+ | **identifier** | Any name the data is addressed by: entry id, paragraph path, light id, fact key, fact value, relation name, modality/role/encounter/category value, jurisdiction value. |
60
60
 
61
61
  ---
62
62
 
@@ -68,7 +68,7 @@ Neither consumer lives in this repo.
68
68
  applicability entry and every rule-text record, expressed as
69
69
  `<country-or-body>/<waters>` with `intl` as the reserved base value.
70
70
  Examples: `intl`, `us/inland`, `us/great-lakes`, `us/western-rivers`,
71
- `ca/inland`, `de/binnen`, `eu/cevni`.
71
+ `ca/inland`, `de/binnen`, `eu/cevni`. The jurisdiction value is itself an identifier, unprefixed and immutable under REQ-MODEL-10 (ADR 0017).
72
72
  - **REQ-SCOPE-3** — A jurisdiction MUST be expressible as a *delta*: entries
73
73
  absent from a jurisdiction's data inherit from `intl`. A jurisdiction MUST
74
74
  NOT require restating the whole body of rules. Inheritance is "unless
@@ -79,7 +79,7 @@ Neither consumer lives in this repo.
79
79
  exists. That bar is about suppression, not licensing: it is independent of
80
80
  REQ-PROV-2 and ADR 0010, and it binds whether a jurisdiction's text ships or
81
81
  is withheld. A delta that only *adds* entries is exempt: it suppresses nothing,
82
- so the Q-11 hazard cannot arise from it (ADR 0008, `30a-buoy`/`30b-buoy`).
82
+ so the Q-11 hazard cannot arise from it (ADR 0008, `rule:30a:mooring_buoy`/`rule:30b:mooring_buoy`).
83
83
  A delta that suppresses or replaces an `intl` entry still waits.
84
84
  - **REQ-SCOPE-4** — Adding a jurisdiction MUST be additive. It MUST NOT require
85
85
  a schema change or edits to existing `intl` entries.
@@ -156,7 +156,7 @@ Four layers, each independently addressable.
156
156
  identifiers do not.
157
157
  - **REQ-MODEL-4** — **Applicability entries**: `when` (predicate over facts) →
158
158
  lights or refs → modality → citation → jurisdiction. Every entry MUST have a
159
- stable id derived from its paragraph path (`25b`, `25d1`).
159
+ stable id, a paragraph key in the `rule:` namespace (`rule:25d_i`; ADR 0015).
160
160
  - **REQ-MODEL-5** — Gates MUST be expressed as predicates over facts
161
161
  (`fact:length_m < 7`), never as pre-enumerated tuples or configuration counts. Any
162
162
  count of "configurations" is an output of evaluation, never an input to the
@@ -168,7 +168,7 @@ Four layers, each independently addressable.
168
168
  - `rel:in_lieu_of` — legal alternatives for the same fact record;
169
169
  - `rel:excludes` — mutual exclusion, including across rules; symmetric
170
170
  (A excludes B implies B excludes A), and no participating entry MAY be
171
- forceful (`shall`/`shall-if-practicable`) — a directed "this one
171
+ forceful (`modality:shall`/`modality:shall-if-practicable`) — a directed "this one
172
172
  prevails" is `rel:overrides` (ADR 0007), not `rel:excludes`;
173
173
  - `rel:exempts` — one entry lifting another's obligation;
174
174
  - `rel:conditional_includes` — import or alternatives, gated on a predicate.
@@ -187,8 +187,8 @@ Four layers, each independently addressable.
187
187
  ADR 0005 §4.
188
188
  - **REQ-MODEL-12** — `rel:conditional_includes` currently carries three
189
189
  distinct shapes under one relation name: a bare `one_of` alternative set
190
- (`25d2`), a gated alternative set (`when` + `one_of`, `27f`), and a gated
191
- import with its own citation (`when` + `rel:includes` + `cite`, `29a`). Which
190
+ (`rule:25d_ii`), a gated alternative set (`when` + `one_of`, `rule:27f`), and a gated
191
+ import with its own citation (`when` + `rel:includes` + `cite`, `rule:29a`). Which
192
192
  behaviour applies is inferred from which keys are present. This is a
193
193
  **soft** requirement — the data is correct today and the tests cover it,
194
194
  so nothing is broken. It is recorded because a third jurisdiction adding
@@ -211,7 +211,7 @@ Four layers, each independently addressable.
211
211
  denoted, MUST be marked deprecated in data with the version that
212
212
  deprecated it, and MUST NOT be removed in the same major version.
213
213
  - **Mutating** one is forbidden. This covers the obvious case (renaming
214
- `25b`) and the dangerous quiet one: an identifier keeping its spelling
214
+ `rule:25b`) and the dangerous quiet one: an identifier keeping its spelling
215
215
  while changing what it denotes — a paragraph path repointed at
216
216
  different text, a fact value narrowed, a light id reassigned. A
217
217
  consumer cannot detect this, and every stored citation becomes silently
@@ -225,29 +225,28 @@ Four layers, each independently addressable.
225
225
  removing an identifier is a major version (REQ-PKG-4); repointing one is
226
226
  not a version event at all, because it is not permitted.
227
227
 
228
- **Immutability baseline: `0.1.1`.** The prohibitions above bind every
229
- identifier present in the first version released *after* `colregs@0.1.1`,
230
- and every identifier introduced from then on. Identifiers as they stood
231
- in `0.1.1` and earlier are outside the baseline. The reason, recorded so
232
- it is not mistaken for convenience later: `0.1.1` was published
233
- 2026-08-29, the day the package was seeded, before the identifier review
234
- this requirement itself calls for had been done and before any consumer
235
- existed. Read without a baseline, the requirement froze the vocabulary at
236
- the moment of its first accidental publication and forbade the one review
237
- it was written to make possible — including the vocabulary type-prefixing
238
- that resolved a live namespace collision (`docs/identifiers.md`). That is
239
- a defect in the requirement, not a licence to skip the review.
240
-
241
- The baseline is **set exactly once**. It MUST NOT be moved, raised,
242
- re-stated in a later version, or joined by a second baseline clause. This
243
- clause is the whole of the exception; there is no mechanism for granting
244
- another. Without that, "move the baseline" is a silent escape hatch from
228
+ **Immutability baseline: `1.0.0`.** The prohibitions above bind every
229
+ identifier present in `colregs@1.0.0` and every identifier introduced
230
+ from then on. Identifiers as they stood before `1.0.0` are outside the
231
+ baseline: while the package is pre-1.0 the schema is being designed, and
232
+ an identifier may be renamed or discarded without a deprecation record.
233
+ The baseline was first set at `0.1.1` on 2026-08-30, the day after the
234
+ package was seeded, so that the identifier review this requirement calls
235
+ for could happen at all. It was moved to `1.0.0` by Solace's ruling on
236
+ #121 (ADR 0015, 2026-09-16), which reshaped every entry id into a
237
+ paragraph key in the `rule:` namespace.
238
+
239
+ From `1.0.0` the baseline is **fixed**. It MUST NOT be moved, raised,
240
+ re-stated in a later version, or joined by a second baseline clause.
241
+ Without that, "move the baseline" is a silent escape hatch from
245
242
  REQ-MODEL-10 and the exception becomes the pattern — a specification that
246
243
  can suspend its own prohibition by editing one number is advisory, not
247
- normative. One recorded exception is a correction; a second is a policy.
244
+ normative.
248
245
 
249
246
  `test/data.test.mjs` pins the baseline literal and asserts it is stated
250
- exactly once. A build has no access to git history, so it cannot see the
247
+ exactly once. There is no identifier diff against the last release: ADR 0006
248
+ proposed one, ADR 0015 removed it pre-1.0, and it returns with the baseline
249
+ tag if at all. A build has no access to git history, so it cannot see the
251
250
  number being *edited* in place; a test that reconstructed history to
252
251
  check would cost more than it is worth and would still pass on a rewritten
253
252
  history. What it can refuse is a **second** baseline clause, which is the
@@ -274,14 +273,18 @@ Four layers, each independently addressable.
274
273
  names, not a modelling convenience of this package.
275
274
  - **`nuc`, `cbd`, `ram`, `ram_underwater`** — kept unspelled as terms of
276
275
  art; see `docs/identifiers.md` for the reasoning and the trap in `ram`.
276
+
277
+ ADR 0015 (Solace's ruling on #121, 2026-09-16) reopened the first two
278
+ bullets: an entry id is a paragraph key in the `rule:` namespace now, and
279
+ the suffix taxonomy went with it. They stand as the audit's record.
277
280
  - **REQ-MODEL-11** — Deprecated identifiers MUST be recorded as data — a
278
281
  registry naming each retired identifier, what it denoted, the version that
279
282
  deprecated it, and its replacement where one exists. Prose in a changelog
280
283
  MUST NOT stand in for it: a consumer pinned to an old version needs to
281
- resolve a stale identifier mechanically. The registry is
282
- `data/deprecated-identifiers.json`, schema-validated
283
- (`schema/deprecated-identifiers.schema.json`, ADR 0006); it ships empty
284
- until the first identifier is retired.
284
+ resolve a stale identifier mechanically. **The registry is absent until
285
+ `1.0.0`.** ADR 0015 deleted it, and the diff that read it: nothing before
286
+ the baseline is immutable, so nothing before it can be retired, and an
287
+ empty file with a dormant test is a mechanism that cannot fire.
285
288
 
286
289
  ### 4.1 Rule categories and the situation record
287
290
 
@@ -294,27 +297,27 @@ towards, not because the shape is settled.
294
297
  two-subject entries and defaulted for the rest; no record in `rules.json`
295
298
  carries one, so a paragraph with no entry is uncategorised)** —
296
299
  Every rule paragraph record MUST carry exactly one `category` from the
297
- closed set `scope`, `definition`, `standard`, `display`,
298
- `classification`, `precedence`, `conduct`, `care`, `meta`. The field
299
- defaults to `display`, so existing entries are correct unedited. CI MUST
300
+ closed set `category:scope`, `category:definition`, `category:standard`, `category:display`,
301
+ `category:classification`, `category:precedence`, `category:conduct`, `category:care`, `category:meta`. The field
302
+ defaults to `category:display`, so existing entries are correct unedited. CI MUST
300
303
  fail on a value outside the set. Where a paragraph plays a second role,
301
304
  that role MUST be expressed as a relation (REQ-CAT-3), never as a second
302
305
  category.
303
- - **REQ-CAT-2** — `care` and `meta` paragraphs (Rules 2(a) and 2(b)) MUST NOT
306
+ - **REQ-CAT-2** — `category:care` and `category:meta` paragraphs (Rules 2(a) and 2(b)) MUST NOT
304
307
  be applicability entries. They MUST be recorded in a registry sibling to
305
308
  `known_omissions`, stating that the package represents them and evaluates
306
- neither. CI MUST fail on a `care` or `meta` paragraph that appears as an
309
+ neither. CI MUST fail on a `category:care` or `category:meta` paragraph that appears as an
307
310
  entry.
308
- - **REQ-CAT-3** **(unimplemented in part — `shall-not` has no entry yet)** —
309
- The modality vocabulary MUST admit `shall-not` and `shall-not-impede`
310
- alongside `shall`, `may`, `shall-if-practicable`, `conditional` and
311
- `exempt`, and the relation vocabulary MUST admit `rel:overrides` as a
311
+ - **REQ-CAT-3** **(unimplemented in part — `modality:shall-not` has no entry yet)** —
312
+ The modality vocabulary MUST admit `modality:shall-not` and `modality:shall-not-impede`
313
+ alongside `modality:shall`, `modality:may`, `modality:shall-if-practicable`, `modality:conditional` and
314
+ `modality:exempt`, and the relation vocabulary MUST admit `rel:overrides` as a
312
315
  sixth verb beside REQ-MODEL-7's five. Both remain closed sets; CI MUST
313
316
  fail on a value outside them, and on a cycle in `rel:overrides`.
314
317
  - **REQ-CAT-4** — A two-subject rule MUST read a **situation record**:
315
318
  two per-vessel fact records, a kinematic state per vessel, relative
316
319
  geometry, and history. The per-vessel fact record MUST NOT change to accommodate it, and kinematic
317
- state MUST be a distinct fact class — a consumer that reads only `display`
320
+ state MUST be a distinct fact class — a consumer that reads only `category:display`
318
321
  entries MUST NOT be required to supply one. Adding the situation record
319
322
  MUST leave every existing fixture valid unedited.
320
323
  - **REQ-CAT-5** — A situation MUST NOT be expressible in the current
@@ -325,10 +328,10 @@ towards, not because the shape is settled.
325
328
  - **REQ-CAT-6** — The situation record MUST be declared in
326
329
  `data/facts.json` under `situation`, and MUST address each vessel's facts
327
330
  through the subject namespace of `docs/identifiers.md`:
328
- `<subject>:<class>:<key>`, subject from `own`/`other`/`pair`, class from
329
- `fact`/`kin`/`geo`/`hist`/`env`. A key with no subject segment MUST mean `own:`,
331
+ `<subject>:<class>:<key>`, subject from `self`/`other`/`pair`, class from
332
+ `fact`/`kin`/`geo`/`hist`/`env`. A key with no subject segment MUST mean `self:`,
330
333
  so that every predicate and fixture published today is a valid situation
331
- predicate unedited. `own:fact:*` and `other:fact:*` MUST resolve to the
334
+ predicate unedited. `self:fact:*` and `other:fact:*` MUST resolve to the
332
335
  per-vessel fact record key for key, with no key renamed or copied.
333
336
  `pair` MUST carry only classes whose facts are symmetric between the two
334
337
  vessels; `env` — where the encounter is happening — is `pair`-only for that
@@ -347,27 +350,27 @@ towards, not because the shape is settled.
347
350
  `expect` MUST be either a bare entry id — the published one-subject form,
348
351
  asserting nothing about modality — or `{entry, modality}` naming the
349
352
  modality that entry is expected to carry, which is what Q-5 needs. A case
350
- whose `status` is `illustrative` MUST assert no entries and MUST NOT join
351
- the fixture replay; it fixes the shape and the namespace before the
352
- entries exist. CI MUST fail on an undeclared fact, an unresolvable key, an
353
- unknown entry id, an unknown modality, and on an `illustrative` case that
354
- names an entry.
353
+ MAY state `roles`, the pooled two-frame answer for both subjects (ADR
354
+ 0016). An `illustrative` case MUST assert no entries and MUST NOT join the
355
+ replay. CI MUST fail on an undeclared fact, an unresolvable key, an unknown
356
+ entry id or modality, a stated role the pooled read does not yield, and on
357
+ an `illustrative` case that names an entry.
355
358
 
356
359
  - **REQ-CAT-8** — A two-subject entry MUST state an `effect` and MUST NOT
357
- state `lights`. For a `precedence` entry the effect MUST be a role per
358
- subject, `{own, other}`, from the closed set `give-way`, `stand-on`,
359
- `shall-not-impede`, `keep-clear`, `none`; for a `scope` entry it MUST name
360
+ state `lights`. For a `category:precedence` entry the effect MUST be a role per
361
+ subject, `{self, other}`, from the closed set `role:give-way`, `role:stand-on`,
362
+ `role:shall-not-impede`, `role:keep-clear`, `role:none`; for a `category:scope` entry it MUST name
360
363
  the part, the section and the rules that section governs; for a
361
- `classification` entry it MUST carry exactly one key, either `encounter`
362
- from the closed set `head-on`, `crossing`, `overtaking`, `none`, or
363
- `risk_of_collision`, whose only value is `true`. `stand-on` MUST
364
- appear only as the counterpart of `give-way`, and the counterpart of
365
- `shall-not-impede` MUST be `none` — Rule 8(f)(iii) is why. CI MUST fail on a
364
+ `category:classification` entry it MUST carry exactly one key, either `encounter`
365
+ from the closed set `encounter:head-on`, `encounter:crossing`, `encounter:overtaking`, `encounter:none`, or
366
+ `risk_of_collision`, whose only value is `true`. `role:stand-on` MUST
367
+ appear only as the counterpart of `role:give-way`, and the counterpart of
368
+ `role:shall-not-impede` MUST be `role:none` — Rule 8(f)(iii) is why. CI MUST fail on a
366
369
  role or an encounter outside its set, on an effect whose shape does not match
367
370
  its category, and on a `rel:overrides` that resolves to no entry, points at an
368
371
  entry of a different category, or closes a cycle. `✎` pencil, with the rest of
369
372
  §4.1.
370
- - **REQ-CAT-9** — The `classification` entries for Rules 13, 14 and 15 MUST
373
+ - **REQ-CAT-9** — The `category:classification` entries for Rules 13, 14 and 15 MUST
371
374
  **partition** the pair's relative geometry: for any situation those entries
372
375
  all reach, exactly one encounter type MUST apply — never two, never none.
373
376
  The crossing sector MUST NOT be enumerated; it MUST be derived, as the
@@ -444,7 +447,7 @@ See ADR 0003.
444
447
  from the other, and no property beyond the language of the text — not
445
448
  source, audience, nor legal applicability — MUST be inferred from a tag.
446
449
  - **REQ-LANG-2** — Identifiers — entry ids, fact values, light ids,
447
- paragraph paths, relation names — MUST be language-neutral and MUST NOT
450
+ paragraph paths, relation names, modality/role/encounter/category values — MUST be language-neutral and MUST NOT
448
451
  be localized. Translations attach to identifiers; they never replace them.
449
452
  Identifiers are schema keywords, not display strings: each vocabulary
450
453
  distinguishes machine identifier, display label (catalog), and definition,
@@ -801,8 +804,8 @@ Tracked here until resolved; each becomes an ADR.
801
804
  - **Q-4** — Two upstream SignalK spec asks are outstanding and independent of
802
805
  this package: a making-way indicator, and `design.maxSpeed`.
803
806
  - **Q-5** — REQ-VERIFY-5 asks for boundary fixtures on every numeric gate.
804
- Three gates (`23a2`, `26b-mast`, `30c`'s `fact:length_m` thresholds) live only in
805
- `modality_by`, not in the entry's `when` — they flip `shall` to `may`, not
807
+ Three gates (`rule:23a_ii`, `rule:26b_ii`, `rule:30c`'s `fact:length_m` thresholds) live only in
808
+ `modality_by`, not in the entry's `when` — they flip `modality:shall` to `modality:may`, not
806
809
  which entries apply. The fixture format only asserts applying entry ids, not
807
810
  expected modality, so there is no way to fixture these three without
808
811
  extending the schema to carry expected modality per entry. Not done
@@ -814,8 +817,8 @@ Tracked here until resolved; each becomes an ADR.
814
817
  id asserts nothing, so `applicability-fixtures.json` stays byte-identical
815
818
  and needs no migration; REQ-CAT-7 states the rule and
816
819
  `fixtures/situation-fixtures.json` carries the worked example. What is left
817
- is not a decision but the work: writing the boundary fixtures for `23a2`,
818
- `26b-mast` and `30c` in the new form. Pencil, so a session that finds a
820
+ is not a decision but the work: writing the boundary fixtures for `rule:23a_ii`,
821
+ `rule:26b_ii` and `rule:30c` in the new form. Pencil, so a session that finds a
819
822
  better shape may change it, logging the change; settled for good by those
820
823
  three fixtures actually landing.
821
824
  - **Q-6** — The treaty-language facts behind §5 (en/fr authentic, es/ru
@@ -873,7 +876,7 @@ Tracked here until resolved; each becomes an ADR.
873
876
  `24(d)`, `24(f)`, `24(g)`, `24(i)`, `25(d)(i)`, `25(d)(ii)`, `25(e)`,
874
877
  `26(d)`, `30(e)`), plus one structural path-mismatch (`23(d)(i)` — the
875
878
  Inland equivalent sits at bare `23(d)`, not `23(d)(i)`), one whole-rule
876
- clean absence (`28`, "[Reserved]" in Inland), and two clean intl-only
879
+ clean absence (`rule:28`, "[Reserved]" in Inland), and two clean intl-only
877
880
  absences. Secondary claim (amendment history): also refuted — the WIG
878
881
  amendment (A.910(22), 2001) explicitly renumbers, displacing the
879
882
  pre-existing `23(c)` (small-vessel alternative lights) to `23(d)`; a 1981
@@ -953,7 +956,7 @@ listed here, one line each, because the ADR is what makes them live. Most are
953
956
  - **Q-14** — Which category does each paragraph take? The proposal's table is
954
957
  a first cut; settled paragraph by paragraph as Rules 1–19 are transcribed.
955
958
  PR #24 settles the first sixteen and departs from the table once: 13(a) is
956
- `precedence`, not `classification` (`Q-37`).
959
+ `category:precedence`, not `category:classification` (`Q-37`).
957
960
  - **Q-15** — Which verification tool discharges each category (Alloy, Z3, TLA+,
958
961
  STL, Rocq)? Settled by building one proof per category, not by argument.
959
962
  *(engine)*
@@ -962,6 +965,11 @@ listed here, one line each, because the ADR is what makes them live. Most are
962
965
  invariant that does not fit. *(engine)*
963
966
  - **Q-17** — What separation distance *d* defines the "safe" level? Fixed to
964
967
  one value to start; settled by the sensitivity matrix of Q-22. *(engine)*
968
+ One data point: `docs/maritime-sources.md`'s MAIB *Polesie*/*Verity* report
969
+ cites UK case law putting close-quarters at a ~12-minute TCPA and adapts a
970
+ suggested-TCPA table (its Figure 16) from *A Guide to the Collision
971
+ Avoidance Rules* — not a d in metres, but a real-world anchor for the
972
+ sensitivity matrix.
965
973
  - **Q-18** — What is the dynamics model, and what is the list of dynamics
966
974
  classes (tanker, ferry, yacht, …)? Settled by the first two-vessel
967
975
  computation; the class list is a data question once it stabilises.
@@ -983,8 +991,10 @@ listed here, one line each, because the ADR is what makes them live. Most are
983
991
  it have to be computed at runtime? Settled by the first two-vessel
984
992
  computation's cost. *(engine)*
985
993
  - **Q-23** — Is Rule 2(b) a duty where departure is necessary, and does the
986
- departing vessel bear the burden? Settled by reading the cases (*The Bywell
987
- Castle*, *Boy Andrew v St Rognvald*, both unverified), not by advocacy.
994
+ departing vessel bear the burden? Partly settled — yes and yes — by
995
+ `docs/maritime-sources.md`'s *Ever Smart* and *Crowley* entries; the
996
+ taxonomy of qualifying circumstances, and *The Bywell Castle* and *Boy
997
+ Andrew v St Rognvald*, are still unread. *colregs-engine* issue #83.
988
998
  - **Q-24** — Are the four worked illustrations (R0, R1, R2,
989
999
  `inconclusive-in-model`) actually in the regions they are said to be in?
990
1000
  They fix meanings, not numbers; settled by computing them. *(engine)*
@@ -994,38 +1004,38 @@ listed here, one line each, because the ADR is what makes them live. Most are
994
1004
  - **Q-26** — How large is the relative-frame state space? The 10⁴–10⁶ figure
995
1005
  is a back-of-envelope guess; settled by a worksheet. *(engine)*
996
1006
  - **Q-27** — What are the field names for `category`, `subjects`, `when`,
997
- `effect` and the widened `modality`? Settled when the first non-`display`
1007
+ `effect` and the widened `modality`? Settled when the first non-`category:display`
998
1008
  entry lands, and cheap to change until then.
999
1009
  Unchanged by PR #22, which names none of those five. The names it
1000
1010
  does fix — `situation`, the four classes, the three subjects — are
1001
1011
  REQ-CAT-6's and are equally pencil.
1002
1012
  - **Q-28** — What namespace distinguishes the two subjects of a two-subject
1003
- entry (`own:` / `other:` is the working proposal)? No such segment exists in
1013
+ entry (`self:` / `other:` is the working proposal)? No such segment exists in
1004
1014
  `docs/identifiers.md`; settled before Rule 18 lands, and it is an
1005
1015
  identifier decision under REQ-MODEL-10.
1006
1016
  **Decided in pencil 2026-09-04** (PR #22): `<subject>:<class>:<key>`
1007
- with subject `own`/`other`/`pair` and class `fact`/`kin`/`geo`/`hist`, and a
1008
- bare key meaning `own:`. Written up in `docs/identifiers.md` §"Two
1017
+ with subject `self`/`other`/`pair` and class `fact`/`kin`/`geo`/`hist`, and a
1018
+ bare key meaning `self:`. Written up in `docs/identifiers.md` §"Two
1009
1019
  subjects", required by REQ-CAT-6, and exercised by
1010
1020
  `fixtures/situation-fixtures.json`. Three things the working proposal did
1011
1021
  not have: a third subject, because range and in-sight belong to the
1012
1022
  encounter and not to either vessel; a class segment, so kinematics and
1013
1023
  history are new classes rather than new fact keys; and the bare-key default,
1014
1024
  which is what makes the whole thing additive under REQ-MODEL-10 — no
1015
- existing identifier is renamed or repointed, and `own`/`other`/`pair` become
1025
+ existing identifier is renamed or repointed, and `self`/`other`/`pair` become
1016
1026
  reserved at the head of the identifier space, which is the only cost.
1017
1027
  Settled for good by Rule 18 being written against it.
1018
1028
  - **Q-29** — What are the file names and schemas for the invariants file and
1019
1029
  the region grid, and how does a level-3 invariant carry `jurisdiction`?
1020
1030
  Settled when the first invariant is written down.
1021
- - **Q-30** — What does the `care`/`meta` registry look like as a file — its
1031
+ - **Q-30** — What does the `category:care`/`category:meta` registry look like as a file — its
1022
1032
  name, its schema, and its relationship to `known_omissions`? Settled by
1023
1033
  REQ-CAT-2's implementation, which is the next data change after this ADR.
1024
1034
 
1025
1035
  **Decided in pencil, PR #23.** The registry is `represented_paragraphs`,
1026
1036
  a sibling array to `known_omissions` in `data/applicability.json`. Each
1027
1037
  record: `id` (paragraph-derived, e.g. `2a`), `jurisdiction`, `cite`,
1028
- `category` (`care` or `meta`), and a one-sentence `note`; no `when`, no
1038
+ `category` (`category:care` or `category:meta`), and a one-sentence `note`; no `when`, no
1029
1039
  `lights` — a registry record states that the paragraph is represented
1030
1040
  and evaluated by nothing here, never a predicate. Holds the `2(a)` and
1031
1041
  `2(b)` records this PR adds. `✎` under `docs/conventions.md`: the file
@@ -1039,8 +1049,8 @@ here rather than in a commit message. All pencil.
1039
1049
 
1040
1050
  **Decided in pencil 2026-09-04 (PR #24)**, answering the data half of `Q-27`:
1041
1051
  the field names are `category`, `subjects` and `effect`, and `effect` is
1042
- `{own, other}` roles for a `precedence` entry and `{part, section,
1043
- applies_rules}` for a `scope` one. Written up in `docs/identifiers.md`
1052
+ `{self, other}` roles for a `category:precedence` entry and `{part, section,
1053
+ applies_rules}` for a `category:scope` one. Written up in `docs/identifiers.md`
1044
1054
  §"Effects", required by `REQ-CAT-8`, and exercised by
1045
1055
  `fixtures/situation-fixtures.json`. `Q-28`'s namespace is settled for good by
1046
1056
  the same PR — Rule 18 is written against it and it held, with one addition:
@@ -1052,13 +1062,13 @@ named that gap before the class existed.
1052
1062
  - **Q-31** — `modality` is a single closed value, and 18(c), 18(d)(i) and 9(a)
1053
1063
  each carry two deontic qualifications at once: a practicability caveat
1054
1064
  ("so far as possible", "if the circumstances of the case admit") *and* the
1055
- duty itself. 18(c) is expressible because `shall-if-practicable` already
1065
+ duty itself. 18(c) is expressible because `modality:shall-if-practicable` already
1056
1066
  exists; 18(d)(i) is not, and its caveat is dropped with a `gap` note on the
1057
1067
  entry. Settled by deciding whether practicability is a second field beside
1058
1068
  `modality` rather than a value inside it — which is the same question
1059
1069
  `modality_by` answers for the light rules, and should probably be answered
1060
1070
  the same way. **Narrowed, not settled, 2026-09-04 (PR #25):** 18(d)(i) is now
1061
- `shall-if-practicable` with `effect.own: shall-not-impede`, so the two
1071
+ `modality:shall-if-practicable` with `effect.self: role:shall-not-impede`, so the two
1062
1072
  qualifications sit in two fields and neither is dropped. That works only
1063
1073
  because this duty happens to be a *role*, which `effect` already carries;
1064
1074
  9(a)'s "if the circumstances of the case admit" has no second field to move
@@ -1076,7 +1086,7 @@ named that gap before the class existed.
1076
1086
  `rule18_class:fishing` by 3(d), and the 27(c) tow that severely restricts the
1077
1087
  pair — the one the old predicates could not catch at all — to
1078
1088
  `rule18_class:ram`, via a new boolean `fact:tow_restricts_deviation`. Every
1079
- Rule 18, 9 and 10 entry reads the class; no `precedence` entry reads
1089
+ Rule 18, 9 and 10 entry reads the class; no `category:precedence` entry reads
1080
1090
  `fact:activity` any more, and a test enforces that. `fact:activity` itself is
1081
1091
  unchanged and no entry that reads it was touched. What is *not* settled: the
1082
1092
  eighth rank Rule 18 distinguishes is the seaplane of 3(e), and it has no
@@ -1106,7 +1116,7 @@ named that gap before the class existed.
1106
1116
  alternative was declined: it would have produced a predicate no reader could
1107
1117
  check against the rule text, to avoid a language feature the rules themselves
1108
1118
  use in plain words.
1109
- - **Q-34** — A `shall-not-impede` entry names a duty toward `other`, but the
1119
+ - **Q-34** — A `modality:shall-not-impede` entry names a duty toward `other`, but the
1110
1120
  paragraphs identify the protected vessel by a property this package does not
1111
1121
  carry: "a vessel which can safely navigate only within a narrow channel"
1112
1122
  (9(b), 9(d)), "any vessel following a traffic lane" (10(i), 10(j)), and a
@@ -1120,8 +1130,8 @@ named that gap before the class existed.
1120
1130
  protected-vessel property is a per-vessel fact, consumer-supplied like
1121
1131
  `pair:env:narrow_channel` and `pair:env:traffic_lane` are.** `fact:confined_to_channel`
1122
1132
  and `fact:following_traffic_lane` name it, in the same shape as the existing
1123
- `fact:near_channel` and `fact:obstruction_exists`; entries `9b`, `10i` and
1124
- `10j` now read `other:fact:confined_to_channel`/`other:fact:following_traffic_lane`
1133
+ `fact:near_channel` and `fact:obstruction_exists`; entries `rule:9b`, `rule:10i` and
1134
+ `rule:10j` now read `other:fact:confined_to_channel`/`other:fact:following_traffic_lane`
1125
1135
  and their `gap` fields are closed. `9(d)` has no entry yet, so it inherits
1126
1136
  the same fact when one is written. **18(d)(i) is deliberately left open**:
1127
1137
  "exhibiting the signals in Rule 28" is a display-compliance fact rather than
@@ -1129,40 +1139,40 @@ named that gap before the class existed.
1129
1139
  CLAUDE.md "Coverage") — settling it is a narrower, separate decision.
1130
1140
  - **Q-35** — 8(f)(iii)'s antecedent is "a vessel, the passage of which is not to
1131
1141
  be impeded" — the *output* of another norm, not a fact. A precedence
1132
- predicate reads only facts, so entry `8f3` reads the risk-of-collision half
1142
+ predicate reads only facts, so entry `rule:8f_iii` reads the risk-of-collision half
1133
1143
  alone and applies to every pair with risk of collision. Settled by deciding
1134
1144
  whether a norm may read another norm's effect, which is the same question a
1135
- `conduct` monitor will ask about role and phase.
1145
+ `category:conduct` monitor will ask about role and phase.
1136
1146
  - **Q-36** — Rule 18(a)(iv) and 18(d)(i) are both in force between a sailing
1137
1147
  vessel and a vessel constrained by her draught: the CBD vessel gives way, and
1138
1148
  the sailing vessel must not impede her. Neither overrides the other and the
1139
- model records both, so one subject holds `stand-on` and `shall-not-impede`
1149
+ model records both, so one subject holds `role:stand-on` and `role:shall-not-impede`
1140
1150
  at once. The test suite pins it as a finding rather than asserting it away.
1141
1151
  Settled by reading 8(f)(ii) against the cases, not by picking a role.
1142
- - **Q-37** — 13(a) is `classification` in ADR 0005 §1 and in the proposal's
1152
+ - **Q-37** — 13(a) is `category:classification` in ADR 0005 §1 and in the proposal's
1143
1153
  first-cut table, but it is the one paragraph of Rule 13 that assigns a role
1144
- and a `classification` entry has nowhere to put one. Entry `13a` is
1145
- `precedence` here, with 13(b)'s sector test left for the `classification`
1154
+ and a `category:classification` entry has nowhere to put one. Entry `rule:13a` is
1155
+ `category:precedence` here, with 13(b)'s sector test left for the `category:classification`
1146
1156
  entry that would set the `hist:was_overtaking` latch. Settled with the rest
1147
1157
  of `Q-14`, paragraph by paragraph.
1148
1158
 
1149
1159
  **Closed in pencil 2026-09-04 (PR #26).** 13(b) is now written, as *two*
1150
- `classification` entries rather than one — `13b-overtaking` and
1151
- `13b-overtaken` — because the encounter type belongs to the pair and reading
1152
- aspect alone classified the overtaken vessel's side of the same encounter as
1153
- a crossing. 13(a) stays `precedence`, and its predicate now carries both
1160
+ `category:classification` entries rather than one — one per subject — because the
1161
+ encounter type belongs to the pair and reading aspect alone classified the
1162
+ overtaken vessel's side of the same encounter as a crossing. 13(a) stays `category:precedence`, and its predicate now carries both
1154
1163
  halves of "any vessel overtaking any other": the 13(b) sector and the 13(d)
1155
1164
  latch, as an `any_of`, which closes the gap the entry recorded. 13(d) is a
1156
- third `classification` entry, reading history and no geometry at all. The
1165
+ third `category:classification` entry, reading history and no geometry at all. The
1157
1166
  split confirms the thing ADR 0005 §1 was really defending — one category per
1158
- paragraph — and costs one paragraph two entries, which the entry-id suffix
1159
- scheme was already built for.
1167
+ paragraph. **Reversed in part, 2026-09-16:** ADR 0015 as rewritten makes
1168
+ 13(b) one symmetric entry, `rule:13b`, reading the same sector object on
1169
+ either subject under `any_of`. 13(a) staying `category:precedence` is untouched.
1160
1170
  - **Q-38** — 9(d), 18(d)(ii), 18(e), 18(f)(ii), 1(a)–(e) and 20(b)–(c) are
1161
1171
  recorded in `known_omissions` rather than modelled: 9(d) needs the channel's
1162
1172
  axis, 18(e) needs a fact for being a seaplane, 20(b)–(c) need time of day,
1163
1173
  and 1(a)–(e) are addressed to an authority rather than to a vessel. Settled
1164
1174
  one at a time as the facts they need land; none blocks the rest of Part B.
1165
- - **Q-39** — Rule 4's `scope` entry has an empty `when`, because "any condition
1175
+ - **Q-39** — Rule 4's `category:scope` entry has an empty `when`, because "any condition
1166
1176
  of visibility" is the absence of a condition. That makes it unfalsifiable —
1167
1177
  `REQ-VERIFY-3`'s "excluded by at least one fixture" half cannot be satisfied
1168
1178
  and the test exempts it explicitly. Settled by deciding whether an ungated
@@ -1171,19 +1181,19 @@ named that gap before the class existed.
1171
1181
 
1172
1182
  ### From the classification norms (PR #26)
1173
1183
 
1174
- Rules 7(d), 12, 13(b)–(d), 14 and 15 are the first `classification` entries and
1175
- the second family of `precedence` ones. All pencil. What the model expressed is
1184
+ Rules 7(d), 12, 13(b)–(d), 14 and 15 are the first `category:classification` entries and
1185
+ the second family of `category:precedence` ones. All pencil. What the model expressed is
1176
1186
  written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1177
1187
 
1178
- - **Q-40** — **Rule 12 is `precedence`, not `classification`.** ADR 0005 §1 and
1179
- the proposal's table both file it under `classification`; it produces a role
1188
+ - **Q-40** — **Rule 12 is `category:precedence`, not `category:classification`.** ADR 0005 §1 and
1189
+ the proposal's table both file it under `category:classification`; it produces a role
1180
1190
  — "one of them shall keep out of the way of the other" — and a
1181
1191
  classification effect has nowhere to put one, which is `Q-37`'s argument
1182
1192
  applied a second time. Two sailing vessels are still in a head-on, a crossing
1183
1193
  or an overtaking; Rule 12 says which of them gives way, not what kind of
1184
- meeting it is. 12(b) is a `definition` and is the cite on `kin:wind_side`
1194
+ meeting it is. 12(b) is a `category:definition` and is the cite on `kin:wind_side`
1185
1195
  rather than an entry. The second half of the question is narrower and worse:
1186
- 12(a) says "two sailing vessels", which is 3(c), but entries `12a1`–`12a3`
1196
+ 12(a) says "two sailing vessels", which is 3(c), but entries the three Rule 12 entries
1187
1197
  read `rule18_class:sail` instead, so a vessel engaged in fishing under sail
1188
1198
  falls out of Rule 12 — because letting her in would have given her a give-way
1189
1199
  duty under 12(a) and a stand-on role under 18(b)(iii) with no override
@@ -1203,7 +1213,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1203
1213
  it: Rule 18's chapeau excepts Rules 9, 10 and 13 and no others, so every
1204
1214
  Rule 18 norm that can be in force between two sailing vessels — 18(b)(i)–(iii)
1205
1215
  from the ordinary sailing vessel's side, 18(c)(i)–(ii) from the fishing
1206
- vessel's — carries `rel:overrides` against `12a1`–`12a3`. 13(a), being
1216
+ vessel's — carries `rel:overrides` against the three Rule 12 entries. 13(a), being
1207
1217
  "notwithstanding" the whole of Sections I and II, overrides them too, which
1208
1218
  it had to: two sailing vessels in an overtaking held 13(a)'s and 12(a)(ii)'s
1209
1219
  roles at once and nothing had noticed. Two fixtures and a sweep over sailing
@@ -1217,21 +1227,21 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1217
1227
 
1218
1228
  **Decided in pencil 2026-09-05 (PR #46): Rule 15 reads 3(b), and Rule 18
1219
1229
  overrides it too.** The same question answered the other way for Rule 15.
1220
- `15a-give-way` kept the four Rule 18 ranks — NUC, RAM, fishing and WIG —
1230
+ `rule:15a:keep_out_of_the_way` kept the four Rule 18 ranks — NUC, RAM, fishing and WIG —
1221
1231
  out of Rule 15 by negating them on both subjects in its own predicate; the
1222
1232
  negation is gone, both subjects gate on `fact:propulsion: propulsion:power`
1223
- which is 3(b), and `18a1`–`18a3`, `18c1`–`18c2` and `18f1` carry
1233
+ which is 3(b), and the 18(a)(i)–(iii) entries, the two 18(c) entries and `rule:18f_i` carry
1224
1234
  `rel:overrides` against it. The gate was not merely the relation said in
1225
1235
  the wrong place. It produced the right roles wherever Rule 18 speaks and
1226
1236
  *no* role at all where Rule 18 is silent: two vessels engaged in fishing
1227
1237
  under power, and a vessel not under command crossing one restricted in her
1228
1238
  ability to manoeuvre under power, are pairs Rule 18 does not order, and
1229
1239
  neither vessel took a helm role from any entry. Both are fixtures now, and
1230
- both failed on the data before the change — `15a-crossing` classified the
1240
+ both failed on the data before the change — `rule:15a:crossing` classified the
1231
1241
  encounter and nothing assigned a role. What it leaves is Rule 12's residue
1232
1242
  again: on those unordered pairs Rule 15 lays a give-way duty on a vessel
1233
1243
  that may be unable to discharge it, which is Rule 2's region and is
1234
- recorded, not gated. `13a` needs no override against `15a-give-way` — the
1244
+ recorded, not gated. `rule:13a` needs no override against `rule:15a:keep_out_of_the_way` — the
1235
1245
  entry excludes every overtaking by the `hist:was_overtaking` latch and by
1236
1246
  13(b)'s sector — and a test pins that absence so it stays a reason rather
1237
1247
  than an oversight. The hand-list of six is asserted complete by a derived
@@ -1245,7 +1255,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1245
1255
  which is still how the fixtures are written and is what makes these six
1246
1256
  overrides observable rather than invisible.
1247
1257
 
1248
- The category half — Rule 12 as `precedence` — is unchanged and stays with
1258
+ The category half — Rule 12 as `category:precedence` — is unchanged and stays with
1249
1259
  `Q-14`.
1250
1260
  - **Q-41** — **13(c) and 14(c) invert the absent-fact rule.** "When a vessel is
1251
1261
  in any doubt as to whether she is overtaking, she shall assume that this is
@@ -1272,7 +1282,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1272
1282
  judgement. Settled by deciding whether the vocabulary gains one — `Q-31`'s
1273
1283
  neighbour, not its duplicate.
1274
1284
  - **Q-43** — **The partition needs history to be present, and says nothing when
1275
- it is absent.** `14b` and `15a-crossing` are gated on `hist:was_overtaking`
1285
+ it is absent.** `rule:14b` and `rule:15a:crossing` are gated on `hist:was_overtaking`
1276
1286
  being `false` on both subjects, which is 13(d)'s requirement and the only way
1277
1287
  the three encounter types stay disjoint once the latch is set. Because absent
1278
1288
  is absent, a situation that omits the fact is classified as *no encounter at
@@ -1306,27 +1316,26 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1306
1316
  the same question `Q-39` asks about an ungated norm, from the other end.
1307
1317
 
1308
1318
  **Decided in pencil 2026-09-05 (PR #36): the head-on classification cites
1309
- 14(b), and 14(a) is `conduct`.** The question assumed 14(b) produced no
1319
+ 14(b), and 14(a) is `category:conduct`.** The question assumed 14(b) produced no
1310
1320
  effect of its own. It produces the only effect the entry has: "such a
1311
1321
  situation shall be deemed to exist when…" is the deeming test, and
1312
- `{"encounter": "head-on"}` is what a deeming test yields — exactly as
1313
- `13b-overtaking` and `13b-overtaken` cite 13(b), the deeming paragraph,
1322
+ `{"encounter": "encounter:head-on"}` is what a deeming test yields — exactly as
1323
+ `rule:13b` cites 13(b), the deeming paragraph,
1314
1324
  and not 13(a). 14(a) states the situation in words ("reciprocal or nearly
1315
1325
  reciprocal courses") and imposes the duty ("each shall alter her course to
1316
- starboard"); the duty is `conduct`, and the words are what 14(b) makes
1317
- checkable. So the entry is `14b`, cites 14(b), and reads nothing 14(b) does
1326
+ starboard"); the duty is `category:conduct`, and the words are what 14(b) makes
1327
+ checkable. So the entry is `rule:14b`, cites 14(b), and reads nothing 14(b) does
1318
1328
  not fix; 14(a) joins `known_omissions` as conduct beside 18(d)(ii), and
1319
- `14a` is retired in `retired_entry_ids` and, because v0.1.3 shipped it,
1320
- recorded in `data/deprecated-identifiers.json` with `14b` as its
1321
- replacement — the registry's first record (REQ-MODEL-11). The
1329
+ the `14a` id it displaced is gone with the rest of the citation-derived ids
1330
+ and leaves no record behind it (ADR 0015). The
1322
1331
  general question — whether a paragraph with no effect of its own gets an
1323
1332
  entry — is `Q-39`'s and is untouched; this paragraph turned out not to be an
1324
1333
  instance of it.
1325
1334
  - **Q-46** — **"Coming up with" is a comparison of two facts.** 13(b) deems a
1326
1335
  vessel to be overtaking when *coming up with* another from more than 22.5°
1327
- abaft her beam. That is `own:kin:sog_kn` against `other:kin:sog_kn`, and the
1336
+ abaft her beam. That is `self:kin:sog_kn` against `other:kin:sog_kn`, and the
1328
1337
  predicate language compares a fact to a constant and never one fact to
1329
- another — the same wall `12a2` hits on "both have the wind on the same side",
1338
+ another — the same wall `rule:12a_ii` hits on "both have the wind on the same side",
1330
1339
  which it gets over only because that comparison has two values to enumerate
1331
1340
  and this one has infinitely many. `pair:geo:tcpa_s > 0` stands in: the pair
1332
1341
  is closing, and closing from abaft the beam is coming up. It excludes the
@@ -1338,30 +1347,30 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1338
1347
  - **Q-47** — **13(d)'s latch never clears.** The paragraph runs "until she is
1339
1348
  finally past and clear", nothing in the fact vocabulary carries that, and so
1340
1349
  in this model `hist:was_overtaking` is set by a consumer and cleared by a
1341
- consumer while entry `13d` classifies an overtaking for as long as it stands.
1350
+ consumer while entry `rule:13d` classifies an overtaking for as long as it stands.
1342
1351
  Not approximated with a range or a bearing: past and clear is a seamanship
1343
1352
  judgement of the same kind as risk of collision, and a threshold for it would
1344
1353
  be a number invented rather than declared. Settled by whatever settles the
1345
- `conduct` monitors, which are the things that watch a duty end rather than
1354
+ `category:conduct` monitors, which are the things that watch a duty end rather than
1346
1355
  begin.
1347
1356
 
1348
1357
  **Ruled 2026-09-08:** while one vessel holds the latch, 13(a)'s sector
1349
1358
  test is suppressed on the other, newly-gaining vessel — once overtaking,
1350
1359
  always overtaking, per 13(d)'s own text, so a geometry test that would
1351
1360
  newly name a second give-way vessel must not fire while the first still
1352
- holds the role by history alone. `13a`'s sector branch now also reads
1361
+ holds the role by history alone. `rule:13a`'s sector branch now also reads
1353
1362
  `other:hist:was_overtaking: false`; the closing fixture in
1354
1363
  `fixtures/situation-fixtures.json` is the case this closes — a vessel
1355
1364
  drops back onto the latch-holder's own stern, and only the latch-holder
1356
1365
  gives way.
1357
1366
  - **Q-48** — **Nothing checks that a situation is geometrically possible.**
1358
- `own:geo:rel_bearing_deg`, `other:geo:rel_bearing_deg`, the two
1367
+ `self:geo:rel_bearing_deg`, `other:geo:rel_bearing_deg`, the two
1359
1368
  `kin:heading_deg` and the two `kin:sog_kn` are six facts related by two
1360
1369
  equations, and the situation record enforces neither. A consumer — or a
1361
1370
  fixture — can state a pair of bearings that no two headings produce, and the
1362
1371
  entries will classify it without complaint. It bites in one visible place:
1363
1372
  where both vessels have the other on the starboard side, which cannot happen
1364
- on a collision course, `15a-give-way` applies to both of them and the "never
1373
+ on a collision course, `rule:15a:keep_out_of_the_way` applies to both of them and the "never
1365
1374
  both give-way" property fails. The fixtures added here are built from a
1366
1375
  heading and a bearing so that they are consistent by construction, and the
1367
1376
  file says so; the model is not. Settled by deciding whether the record gains
@@ -1372,7 +1381,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1372
1381
  **Decided in pencil 2026-09-05: the record gains a consistency check,
1373
1382
  declared in data and enforced in the suite.** `data/facts.json` declares the
1374
1383
  equations under `situation.geometry.consistency` — the two relative bearings
1375
- are two readings of one line of sight (`own + own heading + 180 ≡ aspect +
1384
+ are two readings of one line of sight (`self + self heading + 180 ≡ aspect +
1376
1385
  other heading`), positions reproduce range and both bearings, and the two
1377
1386
  headings and speeds reproduce CPA, TCPA and bearing rate — with tolerances,
1378
1387
  and `REQ-VERIFY-8` requires the suite to apply them. A quantity a record does
@@ -1384,12 +1393,12 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1384
1393
  and speeds. Two cases could not keep their story: the R1 head-on had both
1385
1394
  vessels with the other to starboard, which no speeds make a steady bearing,
1386
1395
  and is recast as one; the 13(d) latch case is 400 m abeam with the CPA
1387
- already past, and lost `7d1`. The partition sweep now constructs positions
1396
+ already past, and lost `rule:7d_i`. The partition sweep now constructs positions
1388
1397
  and headings for every bearing pair and is consistent at every point. The
1389
1398
  "never both give-way" property is asserted over a sweep of steady-bearing
1390
1399
  geometries — every relative bearing, several speed pairs, both intercept
1391
1400
  solutions — where it is a theorem rather than an observation:
1392
- `u·sin(own bearing) = −v·sin(aspect)`, so the two bearings lie on opposite
1401
+ `u·sin(self bearing) = −v·sin(aspect)`, so the two bearings lie on opposite
1393
1402
  sides and 15(a) can name only one vessel. The both-starboard counterexample
1394
1403
  is pinned as a record the check rejects. What is *not* settled, and is
1395
1404
  pinned too: the theorem is exact only at a bearing rate of zero, and
@@ -1401,12 +1410,12 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1401
1410
  the relative quantities as derived facts stays open in the block's
1402
1411
  `settled_by`.
1403
1412
 
1404
- - **Q-49** — **Must `13d`'s effect cross the Section II/III boundary for Rule 19(d)(i) to be expressible?**
1405
- - *broad* — drop `13d`'s `pair:geo:in_sight` gate so `encounter: overtaking` is visible in Section III; breaks the scope invariant.
1406
- - *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.
1413
+ - **Q-49** — **Must `rule:13d`'s effect cross the Section II/III boundary for Rule 19(d)(i) to be expressible?**
1414
+ - *broad* — drop `rule:13d`'s `pair:geo:in_sight` gate so `encounter: overtaking` is visible in Section III; breaks the scope invariant.
1415
+ - *narrow* — `rule:13d` stays gated; a 19(d)(i) entry reads `self:hist:was_overtaking`/`other:hist:was_overtaking` directly, as `rule:14b` and `rule:15a:crossing` already do.
1407
1416
  - Default: narrow (nothing changes).
1408
1417
  - Recommendation: narrow — the test named below shows the fact resolves out of sight
1409
- (`Q-49: hist:was_overtaking resolves out of sight; 13d does not fire`, `test/data.test.mjs`).
1418
+ (`Q-49: hist:was_overtaking resolves out of sight; rule:13d does not fire`, `test/data.test.mjs`).
1410
1419
 
1411
1420
  ### From the Part B invariants (P4.1)
1412
1421
 
@@ -1419,8 +1428,8 @@ nothing is blocked while open.
1419
1428
  *Wide:* they attach whenever in sight and the geometry holds — Rule 11 is the
1420
1429
  only gate Section II states — so a vessel overtaking a mile clear abeam is
1421
1430
  give-way and Rule 16 binds her. *Narrow:* Section II's duties attach only with
1422
- risk of collision; 14 and 15 are emphasis. Default **wide**: `13a`, `13b-*`,
1423
- `13d` and every Rule 18 entry read `in_sight` only. No recommendation.
1431
+ risk of collision; 14 and 15 are emphasis. Default **wide**: `rule:13a`, `rule:13b`,
1432
+ `rule:13d` and every Rule 18 entry read `in_sight` only. No recommendation.
1424
1433
  - **Q-51** — **What arms 13(d)'s latch?** *A:* 13(b)'s deeming, at the first
1425
1434
  state the geometry holds. *B:* 13(a)'s duty actually attaching. They differ
1426
1435
  where the geometry holds but a condition on 13(a) does not — `Q-50`'s
@@ -1428,7 +1437,7 @@ nothing is blocked while open.
1428
1437
  duty attaches. KIVELI [2025] EWHC 1185 (Admlty) holds the analogous Rule 14
1429
1438
  latch arms on risk of collision and then persists; no authority was found on
1430
1439
  overtaking geometry with no risk of collision. Free to reverse: four entries
1431
- (`13a`, `13b-*`, `13d`) and their fixtures, and nothing consumes the one
1440
+ (`rule:13a`, `rule:13b`, `rule:13d`) and their fixtures, and nothing consumes the one
1432
1441
  state this changes the answer for. Settled by: a decision on Rule 13 itself,
1433
1442
  or Cockcroft & Lameijer on whether overtaking status needs risk of
1434
1443
  collision.
@@ -1438,8 +1447,8 @@ nothing is blocked while open.
1438
1447
  other Section II classification attaches. Both preserve the duty; they differ
1439
1448
  on encounter type, which Rule 17's phases and 14(a) hang off.
1440
1449
  Pencilled **broad** ✎ (Solace, 2026-09-14), which is also the data's
1441
- default: `13d` yields `encounter: overtaking` from history alone, `14b` and
1442
- `15a-crossing` gate on `was_overtaking: false`. 13(a)'s "notwithstanding"
1450
+ default: `rule:13d` yields `encounter: overtaking` from history alone, `rule:14b` and
1451
+ `rule:15a:crossing` gate on `was_overtaking: false`. 13(a)'s "notwithstanding"
1443
1452
  already displaces Rule 14; eCOLREGs states the broad reading as conventional.
1444
1453
  Settled by: a case or commentary on an overtaking becoming a head-on; none
1445
1454
  found.
@@ -1468,7 +1477,7 @@ nothing is blocked while open.
1468
1477
  Not in sight *and* not in or near restricted visibility (clear weather, beyond
1469
1478
  visual range, radar contact) is outside Rule 11 and 19(a): Section I only.
1470
1479
  *Hole:* represent it; a fact for "in or near restricted visibility" is owed.
1471
- *Closed:* treat not-in-sight as Section III. Default **closed**: `19a` drops
1480
+ *Closed:* treat not-in-sight as Section III. Default **closed**: `rule:19a` drops
1472
1481
  the second conjunct, recorded as a `gap`. Recommend **hole**: the default is
1473
1482
  safe for a switching consumer and unsafe for a traceability claim.
1474
1483
  - **Q-57** — **The baseline for "keep her course and speed"?** 17(a)(i) fixes