colregs 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +8 -6
  2. package/data/applicability.json +219 -244
  3. package/data/facts.json +4 -4
  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 +1 -1
  13. package/docs/adr/0014-engine-interface-owned-by-colregs.md +103 -0
  14. package/docs/adr/0015-rule-ids-are-paragraph-keys.md +191 -0
  15. package/docs/budgets.json +5 -15
  16. package/docs/identifiers.md +49 -51
  17. package/docs/maritime-sources.md +58 -0
  18. package/docs/normative-language.md +103 -0
  19. package/docs/part-b-invariants.md +31 -29
  20. package/docs/requirements.md +80 -71
  21. package/fixtures/applicability-fixtures.json +190 -190
  22. package/fixtures/situation-fixtures.json +287 -287
  23. package/package.json +1 -1
  24. package/schema/applicability-fixtures.schema.json +4 -13
  25. package/schema/applicability.schema.json +27 -27
  26. package/schema/conduct-evaluation.schema.json +135 -0
  27. package/schema/display-evaluation.schema.json +146 -0
  28. package/schema/encounter-evaluation.schema.json +109 -0
  29. package/schema/evaluation.schema.json +149 -0
  30. package/schema/fact-record.schema.json +30 -0
  31. package/schema/i18n-catalog.schema.json +47 -0
  32. package/schema/operations.schema.json +124 -0
  33. package/schema/rule2-departure-finding.schema.json +72 -0
  34. package/schema/rule2-departure-model.schema.json +159 -0
  35. package/schema/situation-fixtures.schema.json +10 -146
  36. package/schema/situation.schema.json +72 -0
  37. package/schema/trace.schema.json +33 -0
  38. package/data/deprecated-identifiers.json +0 -7
  39. package/schema/deprecated-identifiers.schema.json +0 -29
@@ -34,9 +34,9 @@ suffix naming what distinguishes them.
34
34
  - Insertion appends a suffix and never renumbers; a suffix names something and
35
35
  is not an ordinal (`REQ-INV-2`).
36
36
  - The paragraph is the unit (ADR 0001): an invariant reading several takes the
37
- id of the one stating its operative content, as entry `14b` does.
37
+ id of the one stating its operative content, as entry `rule:14b` does.
38
38
  - `INV-` is a type prefix on a citation-derived name — the one departure from
39
- `docs/identifiers.md`, because `13a` is already an entry id. Jurisdiction is a
39
+ `docs/identifiers.md`, because `rule:13a` is already an entry id. Jurisdiction is a
40
40
  dimension (`REQ-SCOPE-2`, `Q-8`); only `intl` is populated.
41
41
 
42
42
  ---
@@ -82,10 +82,10 @@ not overtaking); its edges are the forward edges of Rule 21(c)'s sternlight
82
82
  arc, which 13(b)'s second limb states in light terms.
83
83
 
84
84
  - **Undetermined term.** "Coming up with" is a speed comparison the model cannot
85
- express (`Q-46`); `13b-overtaking` substitutes `pair:geo:tcpa_s > 0`, which
85
+ express (`Q-46`); `rule:13b` substitutes `pair:geo:tcpa_s > 0`, which
86
86
  admits a pair closing because the vessel ahead stopped. This states the rule.
87
87
  - **Not stated by 13(b).** Risk of collision: `Q-50`.
88
- - Entries: `13b-overtaking`, `13b-overtaken`;
88
+ - Entries: `rule:13b`;
89
89
  `situation.constants.overtaking_sector_from_deg`/`_to_deg` (ink). Settled by
90
90
  P2.2's Alloy sector model: a partition, or a bearing that falls in both.
91
91
 
@@ -100,9 +100,11 @@ overtaking vessel bears forward of her beam.
100
100
 
101
101
  - **Why separate.** A formalisation carrying encounter type per vessel
102
102
  classifies the overtaken side as a crossing, two types on one pair.
103
- - Entries: `13b-overtaking`, `13b-overtaken`, each other's `when` with subjects
104
- swapped. Settled by P4.2 carrying the type on the pair and TLC finding no
105
- state where the subjects disagree.
103
+ - **2026-09-16.** The two-entry form this section recorded is reversed by
104
+ ADR 0015 as rewritten: 13(b) is one symmetric entry, the same sector object
105
+ read on either subject under `any_of`. The invariant is unchanged.
106
+ - Entries: `rule:13b`. Settled by P4.2 carrying the type on the pair and TLC
107
+ finding no state where the subjects disagree.
106
108
 
107
109
  ### INV-13a — the overtaking vessel keeps out of the way
108
110
 
@@ -116,7 +118,7 @@ roles displace any role Rules 4–18 would otherwise assign to either vessel.
116
118
  well as Rules 14 and 15.
117
119
 
118
120
  - **Not stated by 13(a).** Risk of collision: `Q-50`.
119
- - Entries: `13a`, overriding all eleven Rule 18 and all three Rule 12 entries.
121
+ - Entries: `rule:13a`, overriding all eleven Rule 18 and all three Rule 12 entries.
120
122
  Settled by P4.2's role assignment: the override is or is not needed to keep
121
123
  "never both give-way" true.
122
124
 
@@ -142,8 +144,8 @@ until own is finally past and clear, the encounter type of the pair is
142
144
  model's is its segmentation, and no bearing or range is invented here.
143
145
  - **Readings in doubt.** Two: what arms the latch, `Q-51`; what it forbids,
144
146
  `Q-52`.
145
- - Entries: `13d`, reading `own`/`other:hist:was_overtaking` and no geometry; the
146
- `was_overtaking: false` gates on `14b`, `15a-crossing`, `15a-give-way`
147
+ - Entries: `rule:13d`, reading `own`/`other:hist:was_overtaking` and no geometry; the
148
+ `was_overtaking: false` gates on `rule:14b`, `rule:15a:crossing`, `rule:15a:keep_out_of_the_way`
147
149
  implement `Q-52`'s *broad* reading. Settled by `Q-51`, `Q-52`, then TLC on a
148
150
  three-state trace of an overtaking drawing out onto the bow.
149
151
 
@@ -159,7 +161,7 @@ the duty by its second clause, and a formalisation deriving role from encounter
159
161
  type alone cannot distinguish `Q-52`'s readings.
160
162
 
161
163
  - **State remembered.** As `INV-13d`.
162
- - Entries: `13a`'s `any_of` second limb, `own:hist:was_overtaking: true` — role
164
+ - Entries: `rule:13a`'s `any_of` second limb, `own:hist:was_overtaking: true` — role
163
165
  asserted from the latch directly, keeping the limbs separable. Settled by
164
166
  `Q-52`.
165
167
 
@@ -186,7 +188,7 @@ in [0°, 11.25°] ∪ [348.75°, 360°).
186
188
  that way.
187
189
  - **Not formalised.** The night and day observation limbs are stated as the
188
190
  geometry they encode; a vessel that cannot see the lights has 14(c).
189
- - Entries: `14b`. Settled by `INV-13b`'s partition sweep plus a decision on the
191
+ - Entries: `rule:14b`. Settled by `INV-13b`'s partition sweep plus a decision on the
190
192
  constant.
191
193
 
192
194
  ### INV-14a — both vessels alter to starboard
@@ -205,8 +207,8 @@ way; both are directed to act, and the duty is symmetric.
205
207
  - **Why it matters formally.** The one Section II encounter with no `stand-on`
206
208
  vessel, and why `INV-17a1-scope` has content.
207
209
  - Entries: none; `conduct`, in `known_omissions`, no conduct shape (`Q-45`);
208
- `14a` is retired in `data/deprecated-identifiers.json`. Settled by the first
209
- conduct monitor.
210
+ `14a` was never a name and is gone with the rest of the citation-derived ids
211
+ (ADR 0015). Settled by the first conduct monitor.
210
212
 
211
213
  ---
212
214
 
@@ -228,7 +230,7 @@ encounter type is `crossing` exactly when it is neither `overtaking` under
228
230
  - **Known incompleteness.** Two sailing vessels get no encounter type (Rules 14
229
231
  and 15 are gated on power, Rule 12 has no deeming paragraph): the Rules'. A
230
232
  pair with the history fact absent gets none: the model's (`Q-43`).
231
- - Entries: `15a-crossing`.
233
+ - Entries: `rule:15a:crossing`.
232
234
 
233
235
  ### INV-15a-give-way — the vessel with the other to starboard gives way
234
236
 
@@ -241,7 +243,7 @@ other holds `stand-on`.
241
243
  - **Undetermined term.** "On her own starboard side" has no sector in the
242
244
  paragraph; the data reads `own:geo:rel_bearing_deg` in (0°, 112.5°], its upper
243
245
  edge 13(b)'s constant, so it is checkable against the partition.
244
- - Entries: `15a-give-way`, plus six `rel:overrides` from Rule 18 entries, since
246
+ - Entries: `rule:15a:keep_out_of_the_way`, plus six `rel:overrides` from Rule 18 entries, since
245
247
  Rule 18's chapeau excepts Rules 9, 10 and 13 and no others.
246
248
 
247
249
  ### INV-15a-single — at most one give-way vessel in a crossing
@@ -277,7 +279,7 @@ advancing position.
277
279
  segment ("ahead of" a moving vessel), and the state the role attached.
278
280
  - **Undetermined term.** "If the circumstances of the case admit" has nowhere to
279
281
  live — `modality` is one closed value, an action has no `effect` — `Q-31`.
280
- - Entries: none; a `gap` on `15a-give-way`.
282
+ - Entries: none; a `gap` on `rule:15a:keep_out_of_the_way`.
281
283
 
282
284
  ---
283
285
 
@@ -443,7 +445,7 @@ discharge her obligation.
443
445
  - **Why separate.** The natural automaton takes the give-way duty as an input to
444
446
  its transitions; 17(d) says the arrow does not run back, so model two
445
447
  obligations holding concurrently, not one machine with one obligation.
446
- - Entries: none; nearest is 8(f)(ii)'s parallel for `shall-not-impede`, `8f3`.
448
+ - Entries: none; nearest is 8(f)(ii)'s parallel for `shall-not-impede`, `rule:8f_iii`.
447
449
 
448
450
  ### INV-17-phases — the phase structure
449
451
 
@@ -485,9 +487,9 @@ governs.
485
487
  - **Why both directions.** "To nothing else" is what runs the `rel:overrides`
486
488
  edges from Rule 18 *to* Rules 12 and 15; got wrong once, found by a sweep
487
489
  (`Q-40`).
488
- - Entries: overrides on `13a` against all Rule 18 and Rule 12 entries; on
489
- `18a1`–`18a3`, `18c1`–`18c2`, `18f1` against `15a-give-way`; on the Rule 18
490
- entries that can meet two sailing vessels against `12a1`–`12a3`; a derived
490
+ - Entries: overrides on `rule:13a` against all Rule 18 and Rule 12 entries; on
491
+ the 18(a)(i)–(iii) entries, the two 18(c) entries, `rule:18f_i` against `rule:15a:keep_out_of_the_way`; on the Rule 18
492
+ entries that can meet two sailing vessels against the three Rule 12 entries; a derived
491
493
  check asserts the hand-list of six against Rule 15 is complete.
492
494
 
493
495
  ### INV-18-order — the rank order
@@ -510,7 +512,7 @@ The subject holds `give-way`; the object `stand-on`.
510
512
  (`Q-32`) is the model's decode onto these ranks. A vessel constrained by her
511
513
  draught is a power-driven vessel for 18(a) and is ranked by it.
512
514
  - **Not stated by Rule 18.** Risk of collision and encounter type: `Q-50`.
513
- - Entries: `18a1`–`18a4`, `18b1`–`18b3`, `18c1`–`18c2`.
515
+ - Entries: the four 18(a) entries, the three 18(b) entries, the two 18(c) entries.
514
516
 
515
517
  ### INV-18-partial — the order is partial, and the gaps are the Rules'
516
518
 
@@ -542,7 +544,7 @@ discharging `INV-16` requires of her.
542
544
 
543
545
  - **Why stated.** Read as a condition on the antecedent, it gives a roleless
544
546
  pair exactly when compliance is hard and the roles matter.
545
- - Entries: `18c1`, `18c2`, modality `shall-if-practicable` with effect
547
+ - Entries: `rule:18c_i`, `rule:18c_ii`, modality `shall-if-practicable` with effect
546
548
  `give-way`/`stand-on` — `Q-31`'s shape, resolved only because the duty is a
547
549
  role.
548
550
 
@@ -563,8 +565,8 @@ is not relieved (8(f)(ii)).
563
565
  protected vessel a Rule 17 duty no paragraph confers — 8(f)(iii)'s content,
564
566
  and why `none` is explicit.
565
567
  - **Undetermined term.** "Exhibiting the signals in Rule 28" is a
566
- display-compliance fact `18d1` does not read; the entry is wider (`Q-34`).
567
- - Entries: `18d1`, `8f3`.
568
+ display-compliance fact `rule:18d_i` does not read; the entry is wider (`Q-34`).
569
+ - Entries: `rule:18d_i`, `rule:8f_iii`.
568
570
 
569
571
  ### INV-18f1 — the WIG craft keeps well clear
570
572
 
@@ -575,7 +577,7 @@ in flight near the surface, she holds `keep-clear` with respect to every other
575
577
  vessel — keeps well clear and avoids impeding their navigation — and the other
576
578
  holds `none`. `keep-clear` is outside the give-way/stand-on pairing and Rule 16.
577
579
 
578
- - Entries: `18f1`.
580
+ - Entries: `rule:18f_i`.
579
581
 
580
582
  ---
581
583
 
@@ -601,9 +603,9 @@ not jointly exhaustive (`INV-19a-third-state`); Rule 19 supplements Section I
601
603
  cross it and back inside one encounter, and no paragraph says what becomes of
602
604
  a 13(d) latch or a Rule 17 phase: `Q-55`.
603
605
  - **Undetermined term.** "In or near an area of restricted visibility" has no
604
- fact (3(l)'s atmospheric condition is nowhere in `data/facts.json`), so `19a`
606
+ fact (3(l)'s atmospheric condition is nowhere in `data/facts.json`), so `rule:19a`
605
607
  selects Section III for any pair not in sight — wider — and records a gap.
606
- - Entries: `11`, `19a`, complementary on `pair:geo:in_sight`.
608
+ - Entries: `rule:11`, `rule:19a`, complementary on `pair:geo:in_sight`.
607
609
 
608
610
  ### INV-19a-noroles — Section III has no give-way and no stand-on vessel
609
611
 
@@ -633,7 +635,7 @@ excludes Section II, 19(a) excludes Rule 19, and only Section I governs.
633
635
  - **Why written down.** A hole forced by both scope paragraphs, which "not
634
636
  Section II, so Section III" will not have. The model closes it by dropping
635
637
  19(a)'s second conjunct — a decision, not a reading: `Q-56`.
636
- - Entries: `19a`'s `gap`.
638
+ - Entries: `rule:19a`'s `gap`.
637
639
 
638
640
  ### INV-19b — safe speed, and engines ready
639
641
 
@@ -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
@@ -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
 
@@ -801,7 +804,7 @@ 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
807
+ Three gates (`rule:23a_ii`, `rule:26b_ii`, `rule:30c`'s `fact:length_m` thresholds) live only in
805
808
  `modality_by`, not in the entry's `when` — they flip `shall` to `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
@@ -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
@@ -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)*
@@ -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,7 +1139,7 @@ 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
1145
  `conduct` monitor will ask about role and phase.
@@ -1141,22 +1151,22 @@ named that gap before the class existed.
1141
1151
  Settled by reading 8(f)(ii) against the cases, not by picking a role.
1142
1152
  - **Q-37** — 13(a) is `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
1154
+ and a `classification` entry has nowhere to put one. Entry `rule:13a` is
1145
1155
  `precedence` here, with 13(b)'s sector test left for the `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
+ `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 `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
1165
  third `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 `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,
@@ -1183,7 +1193,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1183
1193
  or an overtaking; Rule 12 says which of them gives way, not what kind of
1184
1194
  meeting it is. 12(b) is a `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
@@ -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
@@ -1310,15 +1320,14 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
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
1322
  `{"encounter": "head-on"}` is what a deeming test yields — exactly as
1313
- `13b-overtaking` and `13b-overtaken` cite 13(b), the deeming paragraph,
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
1326
  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
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.
@@ -1326,7 +1335,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1326
1335
  vessel to be overtaking when *coming up with* another from more than 22.5°
1327
1336
  abaft her beam. That is `own: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,7 +1347,7 @@ 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
@@ -1349,7 +1358,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
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
@@ -1361,7 +1370,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
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
@@ -1384,7 +1393,7 @@ 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
@@ -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 `own: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