colregs 0.3.1 → 0.3.3

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.
@@ -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,19 +68,20 @@ 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
75
- suppressed", not unconditional — see Q-11: verified Inland structure
76
- (Rule 28 "[Reserved]") means silence-means-inherit would apply
77
- international law where the national body deliberately has none, so no
78
- non-`intl` jurisdiction lands before an explicit suppression mechanism
79
- exists. That bar is about suppression, not licensing: it is independent of
80
- REQ-PROV-2 and ADR 0010, and it binds whether a jurisdiction's text ships or
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, `rule:30a:mooring_buoy`/`rule:30b:mooring_buoy`).
83
- A delta that suppresses or replaces an `intl` entry still waits.
75
+ suppressed", not unconditional: verified Inland structure (Rule 28
76
+ "[Reserved]") means silence-means-inherit would apply international law
77
+ where the national body deliberately has none, so a jurisdiction MUST
78
+ tombstone each inherited entry it deliberately lacks in `suppressions[]`
79
+ (ADR 0018; Q-11). The delta is an RFC 7396 merge patch over `intl` by
80
+ entry id — own entries present, tombstones `null`, silence inherits — and
81
+ a test proves the stored tables equal to that patch applied. This binds
82
+ whether a jurisdiction's text ships or is withheld (REQ-PROV-2, ADR 0010
83
+ are separate). A delta that only *adds* entries has no tombstones (ADR
84
+ 0008); one that replaces an `intl` entry tombstones it and adds its own.
84
85
  - **REQ-SCOPE-4** — Adding a jurisdiction MUST be additive. It MUST NOT require
85
86
  a schema change or edits to existing `intl` entries.
86
87
  - **REQ-SCOPE-5** — Geography that gates a rule (Great Lakes, Western Rivers,
@@ -164,14 +165,14 @@ Four layers, each independently addressable.
164
165
  - **REQ-MODEL-6** — Entries MUST compose. Multiple entries applying to one fact
165
166
  record is the normal case, not an error (Rule 28 is "in addition to" Rule 23).
166
167
  - **REQ-MODEL-7** — Five relations MUST be supported:
167
- - `rel:includes` — import another entry's **lights only**, never its predicate;
168
- - `rel:in_lieu_of` — legal alternatives for the same fact record;
168
+ - `rel:includes` — import another entry's lights, modality and scalar gates, never its axes (ADR 0019);
169
+ - `rel:in_lieu_of` — legal alternatives for the same fact record; overlapping targets are alternatives to each other (ADR 0019);
169
170
  - `rel:excludes` — mutual exclusion, including across rules; symmetric
170
171
  (A excludes B implies B excludes A), and no participating entry MAY be
171
- forceful (`shall`/`shall-if-practicable`) — a directed "this one
172
- prevails" is `rel:overrides` (ADR 0007), not `rel:excludes`;
173
- - `rel:exempts` — one entry lifting another's obligation;
174
- - `rel:conditional_includes` — import or alternatives, gated on a predicate.
172
+ forceful (`modality:shall`/`modality:shall-if-practicable`) — a directed "this one
173
+ prevails" is `rel:overrides` (ADR 0007), not `rel:excludes`; a constraint on one display, never a removal (ADR 0019);
174
+ - `rel:exempts` — one entry lifting another's obligation; reaches an entry in force, never an import (ADR 0019);
175
+ - `rel:conditional_includes` — import or alternatives, gated on a predicate; a `one_of` yields exactly one per display, or none under a `may` carrier (ADR 0019).
175
176
  The five are not interchangeable; README.md holds the working semantics.
176
177
  - **REQ-MODEL-13** — Where a condition goes is not a style choice. A
177
178
  condition on whether a paragraph *applies to this vessel at all* MUST be in
@@ -297,27 +298,27 @@ towards, not because the shape is settled.
297
298
  two-subject entries and defaulted for the rest; no record in `rules.json`
298
299
  carries one, so a paragraph with no entry is uncategorised)** —
299
300
  Every rule paragraph record MUST carry exactly one `category` from the
300
- closed set `scope`, `definition`, `standard`, `display`,
301
- `classification`, `precedence`, `conduct`, `care`, `meta`. The field
302
- defaults to `display`, so existing entries are correct unedited. CI MUST
301
+ closed set `category:scope`, `category:definition`, `category:standard`, `category:display`,
302
+ `category:classification`, `category:precedence`, `category:conduct`, `category:care`, `category:meta`. The field
303
+ defaults to `category:display`, so existing entries are correct unedited. CI MUST
303
304
  fail on a value outside the set. Where a paragraph plays a second role,
304
305
  that role MUST be expressed as a relation (REQ-CAT-3), never as a second
305
306
  category.
306
- - **REQ-CAT-2** — `care` and `meta` paragraphs (Rules 2(a) and 2(b)) MUST NOT
307
+ - **REQ-CAT-2** — `category:care` and `category:meta` paragraphs (Rules 2(a) and 2(b)) MUST NOT
307
308
  be applicability entries. They MUST be recorded in a registry sibling to
308
309
  `known_omissions`, stating that the package represents them and evaluates
309
- neither. CI MUST fail on a `care` or `meta` paragraph that appears as an
310
+ neither. CI MUST fail on a `category:care` or `category:meta` paragraph that appears as an
310
311
  entry.
311
- - **REQ-CAT-3** **(unimplemented in part — `shall-not` has no entry yet)** —
312
- The modality vocabulary MUST admit `shall-not` and `shall-not-impede`
313
- alongside `shall`, `may`, `shall-if-practicable`, `conditional` and
314
- `exempt`, and the relation vocabulary MUST admit `rel:overrides` as a
312
+ - **REQ-CAT-3** **(unimplemented in part — `modality:shall-not` has no entry yet)** —
313
+ The modality vocabulary MUST admit `modality:shall-not` and `modality:shall-not-impede`
314
+ alongside `modality:shall`, `modality:may`, `modality:shall-if-practicable`, `modality:conditional` and
315
+ `modality:exempt`, and the relation vocabulary MUST admit `rel:overrides` as a
315
316
  sixth verb beside REQ-MODEL-7's five. Both remain closed sets; CI MUST
316
317
  fail on a value outside them, and on a cycle in `rel:overrides`.
317
318
  - **REQ-CAT-4** — A two-subject rule MUST read a **situation record**:
318
319
  two per-vessel fact records, a kinematic state per vessel, relative
319
320
  geometry, and history. The per-vessel fact record MUST NOT change to accommodate it, and kinematic
320
- state MUST be a distinct fact class — a consumer that reads only `display`
321
+ state MUST be a distinct fact class — a consumer that reads only `category:display`
321
322
  entries MUST NOT be required to supply one. Adding the situation record
322
323
  MUST leave every existing fixture valid unedited.
323
324
  - **REQ-CAT-5** — A situation MUST NOT be expressible in the current
@@ -328,10 +329,10 @@ towards, not because the shape is settled.
328
329
  - **REQ-CAT-6** — The situation record MUST be declared in
329
330
  `data/facts.json` under `situation`, and MUST address each vessel's facts
330
331
  through the subject namespace of `docs/identifiers.md`:
331
- `<subject>:<class>:<key>`, subject from `own`/`other`/`pair`, class from
332
- `fact`/`kin`/`geo`/`hist`/`env`. A key with no subject segment MUST mean `own:`,
332
+ `<subject>:<class>:<key>`, subject from `self`/`other`/`pair`, class from
333
+ `fact`/`kin`/`geo`/`hist`/`env`. A key with no subject segment MUST mean `self:`,
333
334
  so that every predicate and fixture published today is a valid situation
334
- predicate unedited. `own:fact:*` and `other:fact:*` MUST resolve to the
335
+ predicate unedited. `self:fact:*` and `other:fact:*` MUST resolve to the
335
336
  per-vessel fact record key for key, with no key renamed or copied.
336
337
  `pair` MUST carry only classes whose facts are symmetric between the two
337
338
  vessels; `env` — where the encounter is happening — is `pair`-only for that
@@ -350,27 +351,27 @@ towards, not because the shape is settled.
350
351
  `expect` MUST be either a bare entry id — the published one-subject form,
351
352
  asserting nothing about modality — or `{entry, modality}` naming the
352
353
  modality that entry is expected to carry, which is what Q-5 needs. A case
353
- whose `status` is `illustrative` MUST assert no entries and MUST NOT join
354
- the fixture replay; it fixes the shape and the namespace before the
355
- entries exist. CI MUST fail on an undeclared fact, an unresolvable key, an
356
- unknown entry id, an unknown modality, and on an `illustrative` case that
357
- names an entry.
354
+ MAY state `roles`, the pooled two-frame answer for both subjects (ADR
355
+ 0016). An `illustrative` case MUST assert no entries and MUST NOT join the
356
+ replay. CI MUST fail on an undeclared fact, an unresolvable key, an unknown
357
+ entry id or modality, a stated role the pooled read does not yield, and on
358
+ an `illustrative` case that names an entry.
358
359
 
359
360
  - **REQ-CAT-8** — A two-subject entry MUST state an `effect` and MUST NOT
360
- state `lights`. For a `precedence` entry the effect MUST be a role per
361
- subject, `{own, other}`, from the closed set `give-way`, `stand-on`,
362
- `shall-not-impede`, `keep-clear`, `none`; for a `scope` entry it MUST name
361
+ state `lights`. For a `category:precedence` entry the effect MUST be a role per
362
+ subject, `{self, other}`, from the closed set `role:give-way`, `role:stand-on`,
363
+ `role:shall-not-impede`, `role:keep-clear`, `role:none`; for a `category:scope` entry it MUST name
363
364
  the part, the section and the rules that section governs; for a
364
- `classification` entry it MUST carry exactly one key, either `encounter`
365
- from the closed set `head-on`, `crossing`, `overtaking`, `none`, or
366
- `risk_of_collision`, whose only value is `true`. `stand-on` MUST
367
- appear only as the counterpart of `give-way`, and the counterpart of
368
- `shall-not-impede` MUST be `none` — Rule 8(f)(iii) is why. CI MUST fail on a
365
+ `category:classification` entry it MUST carry exactly one key, either `encounter`
366
+ from the closed set `encounter:head-on`, `encounter:crossing`, `encounter:overtaking`, `encounter:none`, or
367
+ `risk_of_collision`, whose only value is `true`. `role:stand-on` MUST
368
+ appear only as the counterpart of `role:give-way`, and the counterpart of
369
+ `role:shall-not-impede` MUST be `role:none` — Rule 8(f)(iii) is why. CI MUST fail on a
369
370
  role or an encounter outside its set, on an effect whose shape does not match
370
371
  its category, and on a `rel:overrides` that resolves to no entry, points at an
371
372
  entry of a different category, or closes a cycle. `✎` pencil, with the rest of
372
373
  §4.1.
373
- - **REQ-CAT-9** — The `classification` entries for Rules 13, 14 and 15 MUST
374
+ - **REQ-CAT-9** — The `category:classification` entries for Rules 13, 14 and 15 MUST
374
375
  **partition** the pair's relative geometry: for any situation those entries
375
376
  all reach, exactly one encounter type MUST apply — never two, never none.
376
377
  The crossing sector MUST NOT be enumerated; it MUST be derived, as the
@@ -447,7 +448,7 @@ See ADR 0003.
447
448
  from the other, and no property beyond the language of the text — not
448
449
  source, audience, nor legal applicability — MUST be inferred from a tag.
449
450
  - **REQ-LANG-2** — Identifiers — entry ids, fact values, light ids,
450
- paragraph paths, relation names — MUST be language-neutral and MUST NOT
451
+ paragraph paths, relation names, modality/role/encounter/category values — MUST be language-neutral and MUST NOT
451
452
  be localized. Translations attach to identifiers; they never replace them.
452
453
  Identifiers are schema keywords, not display strings: each vocabulary
453
454
  distinguishes machine identifier, display label (catalog), and definition,
@@ -474,24 +475,21 @@ See ADR 0003.
474
475
  resolve to a known paragraph path, and on a corpus filename that disagrees
475
476
  with the file's internal metadata. Silence MUST NOT imply coverage (the
476
477
  language mirror of REQ-SCOPE-6).
477
- - **REQ-LANG-6** **(unimplemented — no display catalogs exist)** — Display
478
- strings for the identifier vocabularies (light names, fact-value labels,
479
- modality labels, image captions) MUST be addressable via stable string keys
480
- with per-language catalogs, separate from legal corpora. Catalog entries are
481
- static strings: no interpolation, plural or gender grammar — message
482
- composition belongs to the consumer's i18n system, and this package MUST NOT
483
- grow one. Each catalog MUST carry lightweight provenance: contributors,
484
- reviewers, review date, licence. Maintainer notes inside structural files
485
- are working documentation, not display strings, not part of the localization
486
- surface, and stay untranslated.
487
- - **REQ-LANG-7** **(unimplemented in part — no fallback policy is encoded, but
488
- the mixed-corpus statement is missing from the package documentation)** — The
489
- package MUST NOT encode a language fallback policy, and MUST NOT silently
490
- substitute one corpus for another. Text is only addressable inside a corpus,
491
- so every textual unit a consumer retrieves is attributable to its corpus;
492
- package documentation MUST state that a mixed-corpus rendering is never a
493
- single authoritative edition. Choice and fallback beyond that are the
494
- consumer's (the language mirror of REQ-CONS-3).
478
+ - **REQ-LANG-6** — Display strings for the closed vocabularies the package
479
+ emits (light, modality, role, encounter, jurisdiction, fact values, and
480
+ image captions **(unimplemented — no catalog yet)**) MUST be addressable
481
+ via stable string keys with per-language catalogs, separate from legal
482
+ corpora; not being an identifier does not exclude a vocabulary. Catalog
483
+ entries are static strings — no interpolation, plural or gender grammar —
484
+ and MUST carry provenance (contributors, reviewers, review date, licence);
485
+ definitions stay untranslated in structural files, not catalogued.
486
+ - **REQ-LANG-7** — The package MUST NOT encode a language fallback policy,
487
+ and MUST NOT silently substitute one corpus for another. Text is only
488
+ addressable inside a corpus, so every textual unit a consumer retrieves
489
+ is attributable to its corpus; package documentation MUST state that a
490
+ mixed-corpus rendering is never a single authoritative edition. Choice
491
+ and fallback beyond that are the consumer's (the language mirror of
492
+ REQ-CONS-3).
495
493
  - **REQ-LANG-8** — A `community`-tier corpus MUST record who produced and
496
494
  who reviewed it. Machine translation without named human review MUST NOT
497
495
  be accepted.
@@ -507,6 +505,9 @@ See ADR 0003.
507
505
  reflects. The two MAY differ — a corpus transcribed from an older
508
506
  consolidation is legitimate — but the difference MUST be machine-visible,
509
507
  never silent.
508
+ - **REQ-LANG-11** — Exactly one language MUST be declared reference-complete;
509
+ CI MUST fail if its catalog omits an emitted value. Other catalogs MAY be
510
+ partial, gated only by the existing key-resolution check.
510
511
 
511
512
  ---
512
513
 
@@ -805,7 +806,7 @@ Tracked here until resolved; each becomes an ADR.
805
806
  this package: a making-way indicator, and `design.maxSpeed`.
806
807
  - **Q-5** — REQ-VERIFY-5 asks for boundary fixtures on every numeric gate.
807
808
  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 `shall` to `may`, not
809
+ `modality_by`, not in the entry's `when` — they flip `modality:shall` to `modality:may`, not
809
810
  which entries apply. The fixture format only asserts applying entry ids, not
810
811
  expected modality, so there is no way to fixture these three without
811
812
  extending the schema to carry expected modality per entry. Not done
@@ -930,14 +931,13 @@ Tracked here until resolved; each becomes an ADR.
930
931
  Rule 28 "[Reserved]" and has no counterpart for `23(d)(ii)`/`(iii)`
931
932
  ([verification](verification/2026-08-30-q6-q8.md), Claim 1), so a
932
933
  `us/inland` delta that is merely silent there would inherit the `intl`
933
- entries and assert international obligations on inland waters. A delta
934
- needs explicit suppression records (tombstones) alongside overrides —
935
- "this path/entry deliberately does not exist here", distinguishable from
936
- "not yet transcribed". Decide the mechanism in the second-jurisdiction
937
- bundle (GATE-1 re-take, GATE-2, Q-10); until then no non-`intl`
938
- jurisdiction lands. This is the live blocker on CEVNI, and it is *not* the
939
- licence one: ADR 0010 removed the licence block by permitting structure with
940
- the text withheld, and left this one standing.
934
+ entries and assert international obligations on inland waters.
935
+ **Resolved 2026-09-16, ADR 0018.** Tombstones: `suppressions[]` in
936
+ `data/applicability.json`, one record per (jurisdiction, `intl` entry),
937
+ and the whole delta is an RFC 7396 merge patch by entry id, proven by
938
+ test; the two verified Inland absences are the first tombstones. The hold
939
+ on non-`intl` jurisdictions is lifted (CEVNI: structure unblocked on both
940
+ counts, this and ADR 0010). GATE-1, Q-10, Q-8 stay open on their triggers.
941
941
  Also from the same verification pass, tracked on the global board rather
942
942
  than here: four transcription defects in `data/rules.json` itself
943
943
  (`21(a)`, `21(b)`, `23(b)`, `29(b)`) — a data fix, not a design
@@ -956,7 +956,7 @@ listed here, one line each, because the ADR is what makes them live. Most are
956
956
  - **Q-14** — Which category does each paragraph take? The proposal's table is
957
957
  a first cut; settled paragraph by paragraph as Rules 1–19 are transcribed.
958
958
  PR #24 settles the first sixteen and departs from the table once: 13(a) is
959
- `precedence`, not `classification` (`Q-37`).
959
+ `category:precedence`, not `category:classification` (`Q-37`).
960
960
  - **Q-15** — Which verification tool discharges each category (Alloy, Z3, TLA+,
961
961
  STL, Rocq)? Settled by building one proof per category, not by argument.
962
962
  *(engine)*
@@ -1004,38 +1004,38 @@ listed here, one line each, because the ADR is what makes them live. Most are
1004
1004
  - **Q-26** — How large is the relative-frame state space? The 10⁴–10⁶ figure
1005
1005
  is a back-of-envelope guess; settled by a worksheet. *(engine)*
1006
1006
  - **Q-27** — What are the field names for `category`, `subjects`, `when`,
1007
- `effect` and the widened `modality`? Settled when the first non-`display`
1007
+ `effect` and the widened `modality`? Settled when the first non-`category:display`
1008
1008
  entry lands, and cheap to change until then.
1009
1009
  Unchanged by PR #22, which names none of those five. The names it
1010
1010
  does fix — `situation`, the four classes, the three subjects — are
1011
1011
  REQ-CAT-6's and are equally pencil.
1012
1012
  - **Q-28** — What namespace distinguishes the two subjects of a two-subject
1013
- 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
1014
1014
  `docs/identifiers.md`; settled before Rule 18 lands, and it is an
1015
1015
  identifier decision under REQ-MODEL-10.
1016
1016
  **Decided in pencil 2026-09-04** (PR #22): `<subject>:<class>:<key>`
1017
- with subject `own`/`other`/`pair` and class `fact`/`kin`/`geo`/`hist`, and a
1018
- 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
1019
1019
  subjects", required by REQ-CAT-6, and exercised by
1020
1020
  `fixtures/situation-fixtures.json`. Three things the working proposal did
1021
1021
  not have: a third subject, because range and in-sight belong to the
1022
1022
  encounter and not to either vessel; a class segment, so kinematics and
1023
1023
  history are new classes rather than new fact keys; and the bare-key default,
1024
1024
  which is what makes the whole thing additive under REQ-MODEL-10 — no
1025
- existing identifier is renamed or repointed, and `own`/`other`/`pair` become
1025
+ existing identifier is renamed or repointed, and `self`/`other`/`pair` become
1026
1026
  reserved at the head of the identifier space, which is the only cost.
1027
1027
  Settled for good by Rule 18 being written against it.
1028
1028
  - **Q-29** — What are the file names and schemas for the invariants file and
1029
1029
  the region grid, and how does a level-3 invariant carry `jurisdiction`?
1030
1030
  Settled when the first invariant is written down.
1031
- - **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
1032
1032
  name, its schema, and its relationship to `known_omissions`? Settled by
1033
1033
  REQ-CAT-2's implementation, which is the next data change after this ADR.
1034
1034
 
1035
1035
  **Decided in pencil, PR #23.** The registry is `represented_paragraphs`,
1036
1036
  a sibling array to `known_omissions` in `data/applicability.json`. Each
1037
1037
  record: `id` (paragraph-derived, e.g. `2a`), `jurisdiction`, `cite`,
1038
- `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
1039
1039
  `lights` — a registry record states that the paragraph is represented
1040
1040
  and evaluated by nothing here, never a predicate. Holds the `2(a)` and
1041
1041
  `2(b)` records this PR adds. `✎` under `docs/conventions.md`: the file
@@ -1049,8 +1049,8 @@ here rather than in a commit message. All pencil.
1049
1049
 
1050
1050
  **Decided in pencil 2026-09-04 (PR #24)**, answering the data half of `Q-27`:
1051
1051
  the field names are `category`, `subjects` and `effect`, and `effect` is
1052
- `{own, other}` roles for a `precedence` entry and `{part, section,
1053
- 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`
1054
1054
  §"Effects", required by `REQ-CAT-8`, and exercised by
1055
1055
  `fixtures/situation-fixtures.json`. `Q-28`'s namespace is settled for good by
1056
1056
  the same PR — Rule 18 is written against it and it held, with one addition:
@@ -1062,13 +1062,13 @@ named that gap before the class existed.
1062
1062
  - **Q-31** — `modality` is a single closed value, and 18(c), 18(d)(i) and 9(a)
1063
1063
  each carry two deontic qualifications at once: a practicability caveat
1064
1064
  ("so far as possible", "if the circumstances of the case admit") *and* the
1065
- duty itself. 18(c) is expressible because `shall-if-practicable` already
1065
+ duty itself. 18(c) is expressible because `modality:shall-if-practicable` already
1066
1066
  exists; 18(d)(i) is not, and its caveat is dropped with a `gap` note on the
1067
1067
  entry. Settled by deciding whether practicability is a second field beside
1068
1068
  `modality` rather than a value inside it — which is the same question
1069
1069
  `modality_by` answers for the light rules, and should probably be answered
1070
1070
  the same way. **Narrowed, not settled, 2026-09-04 (PR #25):** 18(d)(i) is now
1071
- `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
1072
1072
  qualifications sit in two fields and neither is dropped. That works only
1073
1073
  because this duty happens to be a *role*, which `effect` already carries;
1074
1074
  9(a)'s "if the circumstances of the case admit" has no second field to move
@@ -1086,7 +1086,7 @@ named that gap before the class existed.
1086
1086
  `rule18_class:fishing` by 3(d), and the 27(c) tow that severely restricts the
1087
1087
  pair — the one the old predicates could not catch at all — to
1088
1088
  `rule18_class:ram`, via a new boolean `fact:tow_restricts_deviation`. Every
1089
- 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
1090
1090
  `fact:activity` any more, and a test enforces that. `fact:activity` itself is
1091
1091
  unchanged and no entry that reads it was touched. What is *not* settled: the
1092
1092
  eighth rank Rule 18 distinguishes is the seaplane of 3(e), and it has no
@@ -1116,7 +1116,7 @@ named that gap before the class existed.
1116
1116
  alternative was declined: it would have produced a predicate no reader could
1117
1117
  check against the rule text, to avoid a language feature the rules themselves
1118
1118
  use in plain words.
1119
- - **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
1120
1120
  paragraphs identify the protected vessel by a property this package does not
1121
1121
  carry: "a vessel which can safely navigate only within a narrow channel"
1122
1122
  (9(b), 9(d)), "any vessel following a traffic lane" (10(i), 10(j)), and a
@@ -1142,37 +1142,37 @@ named that gap before the class existed.
1142
1142
  predicate reads only facts, so entry `rule:8f_iii` reads the risk-of-collision half
1143
1143
  alone and applies to every pair with risk of collision. Settled by deciding
1144
1144
  whether a norm may read another norm's effect, which is the same question a
1145
- `conduct` monitor will ask about role and phase.
1145
+ `category:conduct` monitor will ask about role and phase.
1146
1146
  - **Q-36** — Rule 18(a)(iv) and 18(d)(i) are both in force between a sailing
1147
1147
  vessel and a vessel constrained by her draught: the CBD vessel gives way, and
1148
1148
  the sailing vessel must not impede her. Neither overrides the other and the
1149
- 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`
1150
1150
  at once. The test suite pins it as a finding rather than asserting it away.
1151
1151
  Settled by reading 8(f)(ii) against the cases, not by picking a role.
1152
- - **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
1153
1153
  first-cut table, but it is the one paragraph of Rule 13 that assigns a role
1154
- and a `classification` entry has nowhere to put one. Entry `rule:13a` is
1155
- `precedence` here, with 13(b)'s sector test left for the `classification`
1156
- entry that would set the `hist:was_overtaking` latch. Settled with the rest
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`
1156
+ entry that would set the `hist:was_overtaking` overtaking-history fact. Settled with the rest
1157
1157
  of `Q-14`, paragraph by paragraph.
1158
1158
 
1159
1159
  **Closed in pencil 2026-09-04 (PR #26).** 13(b) is now written, as *two*
1160
- `classification` entries rather than one — one per subject — because the
1160
+ `category:classification` entries rather than one — one per subject — because the
1161
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
1162
+ overtaken vessel's side of the same encounter as a crossing. 13(a) stays `category:precedence`, and its predicate now carries both
1163
1163
  halves of "any vessel overtaking any other": the 13(b) sector and the 13(d)
1164
- latch, as an `any_of`, which closes the gap the entry recorded. 13(d) is a
1165
- third `classification` entry, reading history and no geometry at all. The
1164
+ overtaking history, as an `any_of`, which closes the gap the entry recorded. 13(d) is a
1165
+ third `category:classification` entry, reading history and no geometry at all. The
1166
1166
  split confirms the thing ADR 0005 §1 was really defending — one category per
1167
1167
  paragraph. **Reversed in part, 2026-09-16:** ADR 0015 as rewritten makes
1168
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.
1169
+ either subject under `any_of`. 13(a) staying `category:precedence` is untouched.
1170
1170
  - **Q-38** — 9(d), 18(d)(ii), 18(e), 18(f)(ii), 1(a)–(e) and 20(b)–(c) are
1171
1171
  recorded in `known_omissions` rather than modelled: 9(d) needs the channel's
1172
1172
  axis, 18(e) needs a fact for being a seaplane, 20(b)–(c) need time of day,
1173
1173
  and 1(a)–(e) are addressed to an authority rather than to a vessel. Settled
1174
1174
  one at a time as the facts they need land; none blocks the rest of Part B.
1175
- - **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
1176
1176
  of visibility" is the absence of a condition. That makes it unfalsifiable —
1177
1177
  `REQ-VERIFY-3`'s "excluded by at least one fixture" half cannot be satisfied
1178
1178
  and the test exempts it explicitly. Settled by deciding whether an ungated
@@ -1181,17 +1181,17 @@ named that gap before the class existed.
1181
1181
 
1182
1182
  ### From the classification norms (PR #26)
1183
1183
 
1184
- Rules 7(d), 12, 13(b)–(d), 14 and 15 are the first `classification` entries and
1185
- 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
1186
1186
  written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1187
1187
 
1188
- - **Q-40** — **Rule 12 is `precedence`, not `classification`.** ADR 0005 §1 and
1189
- 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
1190
1190
  — "one of them shall keep out of the way of the other" — and a
1191
1191
  classification effect has nowhere to put one, which is `Q-37`'s argument
1192
1192
  applied a second time. Two sailing vessels are still in a head-on, a crossing
1193
1193
  or an overtaking; Rule 12 says which of them gives way, not what kind of
1194
- 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`
1195
1195
  rather than an entry. The second half of the question is narrower and worse:
1196
1196
  12(a) says "two sailing vessels", which is 3(c), but entries the three Rule 12 entries
1197
1197
  read `rule18_class:sail` instead, so a vessel engaged in fishing under sail
@@ -1242,7 +1242,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1242
1242
  again: on those unordered pairs Rule 15 lays a give-way duty on a vessel
1243
1243
  that may be unable to discharge it, which is Rule 2's region and is
1244
1244
  recorded, not gated. `rule:13a` needs no override against `rule:15a:keep_out_of_the_way` — the
1245
- entry excludes every overtaking by the `hist:was_overtaking` latch and by
1245
+ entry excludes every overtaking by the `hist:was_overtaking` overtaking history and by
1246
1246
  13(b)'s sector — and a test pins that absence so it stays a reason rather
1247
1247
  than an oversight. The hand-list of six is asserted complete by a derived
1248
1248
  check: every Rule 18 entry that assigns a helm role and does not gate a
@@ -1255,7 +1255,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1255
1255
  which is still how the fixtures are written and is what makes these six
1256
1256
  overrides observable rather than invisible.
1257
1257
 
1258
- 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
1259
1259
  `Q-14`.
1260
1260
  - **Q-41** — **13(c) and 14(c) invert the absent-fact rule.** "When a vessel is
1261
1261
  in any doubt as to whether she is overtaking, she shall assume that this is
@@ -1284,7 +1284,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1284
1284
  - **Q-43** — **The partition needs history to be present, and says nothing when
1285
1285
  it is absent.** `rule:14b` and `rule:15a:crossing` are gated on `hist:was_overtaking`
1286
1286
  being `false` on both subjects, which is 13(d)'s requirement and the only way
1287
- the three encounter types stay disjoint once the latch is set. Because absent
1287
+ the three encounter types stay disjoint once the overtaking history is set. Because absent
1288
1288
  is absent, a situation that omits the fact is classified as *no encounter at
1289
1289
  all* rather than as a head-on or a crossing. That is conservative in the
1290
1290
  right direction and completely silent, which is the wrong way to be
@@ -1316,14 +1316,14 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1316
1316
  the same question `Q-39` asks about an ungated norm, from the other end.
1317
1317
 
1318
1318
  **Decided in pencil 2026-09-05 (PR #36): the head-on classification cites
1319
- 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
1320
1320
  effect of its own. It produces the only effect the entry has: "such a
1321
1321
  situation shall be deemed to exist when…" is the deeming test, and
1322
- `{"encounter": "head-on"}` is what a deeming test yields — exactly as
1322
+ `{"encounter": "encounter:head-on"}` is what a deeming test yields — exactly as
1323
1323
  `rule:13b` cites 13(b), the deeming paragraph,
1324
1324
  and not 13(a). 14(a) states the situation in words ("reciprocal or nearly
1325
1325
  reciprocal courses") and imposes the duty ("each shall alter her course to
1326
- starboard"); the duty is `conduct`, and the words are what 14(b) makes
1326
+ starboard"); the duty is `category:conduct`, and the words are what 14(b) makes
1327
1327
  checkable. So the entry is `rule:14b`, cites 14(b), and reads nothing 14(b) does
1328
1328
  not fix; 14(a) joins `known_omissions` as conduct beside 18(d)(ii), and
1329
1329
  the `14a` id it displaced is gone with the rest of the citation-derived ids
@@ -1333,7 +1333,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1333
1333
  instance of it.
1334
1334
  - **Q-46** — **"Coming up with" is a comparison of two facts.** 13(b) deems a
1335
1335
  vessel to be overtaking when *coming up with* another from more than 22.5°
1336
- 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
1337
1337
  predicate language compares a fact to a constant and never one fact to
1338
1338
  another — the same wall `rule:12a_ii` hits on "both have the wind on the same side",
1339
1339
  which it gets over only because that comparison has two values to enumerate
@@ -1344,27 +1344,27 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1344
1344
  in seamanship and is one here. Settled by deciding whether the language gains
1345
1345
  fact-to-fact comparison — a bigger change than `not` and `any_of` were, and
1346
1346
  not one to make for a single paragraph.
1347
- - **Q-47** — **13(d)'s latch never clears.** The paragraph runs "until she is
1347
+ - **Q-47** — **13(d)'s overtaking history never clears.** The paragraph runs "until she is
1348
1348
  finally past and clear", nothing in the fact vocabulary carries that, and so
1349
1349
  in this model `hist:was_overtaking` is set by a consumer and cleared by a
1350
1350
  consumer while entry `rule:13d` classifies an overtaking for as long as it stands.
1351
1351
  Not approximated with a range or a bearing: past and clear is a seamanship
1352
1352
  judgement of the same kind as risk of collision, and a threshold for it would
1353
1353
  be a number invented rather than declared. Settled by whatever settles the
1354
- `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
1355
1355
  begin.
1356
1356
 
1357
- **Ruled 2026-09-08:** while one vessel holds the latch, 13(a)'s sector
1358
- test is suppressed on the other, newly-gaining vessel — once overtaking,
1359
- always overtaking, per 13(d)'s own text, so a geometry test that would
1360
- newly name a second give-way vessel must not fire while the first still
1361
- holds the role by history alone. `rule:13a`'s sector branch now also reads
1362
- `other:hist:was_overtaking: false`; the closing fixture in
1357
+ **Ruled 2026-09-08:** while one vessel's overtaking history stands, 13(a)'s
1358
+ sector test is suppressed on the other, newly-gaining vessel — once
1359
+ overtaking, always overtaking, per 13(d)'s own text, so a geometry test
1360
+ that would newly name a second give-way vessel must not fire while the
1361
+ first still holds the role by history alone. `rule:13a`'s sector branch now
1362
+ also reads `other:hist:was_overtaking: false`; the closing fixture in
1363
1363
  `fixtures/situation-fixtures.json` is the case this closes — a vessel
1364
- drops back onto the latch-holder's own stern, and only the latch-holder
1364
+ drops back onto the history-holder's own stern, and only the history-holder
1365
1365
  gives way.
1366
1366
  - **Q-48** — **Nothing checks that a situation is geometrically possible.**
1367
- `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
1368
1368
  `kin:heading_deg` and the two `kin:sog_kn` are six facts related by two
1369
1369
  equations, and the situation record enforces neither. A consumer — or a
1370
1370
  fixture — can state a pair of bearings that no two headings produce, and the
@@ -1381,7 +1381,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1381
1381
  **Decided in pencil 2026-09-05: the record gains a consistency check,
1382
1382
  declared in data and enforced in the suite.** `data/facts.json` declares the
1383
1383
  equations under `situation.geometry.consistency` — the two relative bearings
1384
- 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 +
1385
1385
  other heading`), positions reproduce range and both bearings, and the two
1386
1386
  headings and speeds reproduce CPA, TCPA and bearing rate — with tolerances,
1387
1387
  and `REQ-VERIFY-8` requires the suite to apply them. A quantity a record does
@@ -1392,13 +1392,13 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1392
1392
  bearing-rate values were placeholders. They were re-derived from the headings
1393
1393
  and speeds. Two cases could not keep their story: the R1 head-on had both
1394
1394
  vessels with the other to starboard, which no speeds make a steady bearing,
1395
- and is recast as one; the 13(d) latch case is 400 m abeam with the CPA
1395
+ and is recast as one; the 13(d) overtaking-history case is 400 m abeam with the CPA
1396
1396
  already past, and lost `rule:7d_i`. The partition sweep now constructs positions
1397
1397
  and headings for every bearing pair and is consistent at every point. The
1398
1398
  "never both give-way" property is asserted over a sweep of steady-bearing
1399
1399
  geometries — every relative bearing, several speed pairs, both intercept
1400
1400
  solutions — where it is a theorem rather than an observation:
1401
- `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
1402
1402
  sides and 15(a) can name only one vessel. The both-starboard counterexample
1403
1403
  is pinned as a record the check rejects. What is *not* settled, and is
1404
1404
  pinned too: the theorem is exact only at a bearing rate of zero, and
@@ -1412,7 +1412,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
1412
1412
 
1413
1413
  - **Q-49** — **Must `rule:13d`'s effect cross the Section II/III boundary for Rule 19(d)(i) to be expressible?**
1414
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.
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.
1416
1416
  - Default: narrow (nothing changes).
1417
1417
  - Recommendation: narrow — the test named below shows the fact resolves out of sight
1418
1418
  (`Q-49: hist:was_overtaking resolves out of sight; rule:13d does not fire`, `test/data.test.mjs`).
@@ -1430,18 +1430,18 @@ nothing is blocked while open.
1430
1430
  give-way and Rule 16 binds her. *Narrow:* Section II's duties attach only with
1431
1431
  risk of collision; 14 and 15 are emphasis. Default **wide**: `rule:13a`, `rule:13b`,
1432
1432
  `rule:13d` and every Rule 18 entry read `in_sight` only. No recommendation.
1433
- - **Q-51** — **What arms 13(d)'s latch?** *A:* 13(b)'s deeming, at the first
1433
+ - **Q-51** — **What arms 13(d)'s overtaking history?** *A:* 13(b)'s deeming, at the first
1434
1434
  state the geometry holds. *B:* 13(a)'s duty actually attaching. They differ
1435
1435
  where the geometry holds but a condition on 13(a) does not — `Q-50`'s
1436
- surface. Pencilled **B** ✎ (Solace, 2026-09-14): the latch arms when the
1436
+ surface. Pencilled **B** ✎ (Solace, 2026-09-14): the overtaking history arms when the
1437
1437
  duty attaches. KIVELI [2025] EWHC 1185 (Admlty) holds the analogous Rule 14
1438
- latch arms on risk of collision and then persists; no authority was found on
1438
+ history arms on risk of collision and then persists; no authority was found on
1439
1439
  overtaking geometry with no risk of collision. Free to reverse: four entries
1440
1440
  (`rule:13a`, `rule:13b`, `rule:13d`) and their fixtures, and nothing consumes the one
1441
1441
  state this changes the answer for. Settled by: a decision on Rule 13 itself,
1442
1442
  or Cockcroft & Lameijer on whether overtaking status needs risk of
1443
1443
  collision.
1444
- - **Q-52** — **What does 13(d)'s latch forbid?** *Narrow:* reclassification to
1444
+ - **Q-52** — **What does 13(d)'s overtaking history forbid?** *Narrow:* reclassification to
1445
1445
  *crossing* only, as the paragraph says, leaving head-on to Rule 14 on the
1446
1446
  geometry of the moment. *Broad:* the encounter stays an overtaking and no
1447
1447
  other Section II classification attaches. Both preserve the duty; they differ
@@ -1459,16 +1459,16 @@ nothing is blocked while open.
1459
1459
  flags any other alteration. No default (Rule 17 has no entry). Recommend
1460
1460
  **exception**: 17(a)(ii) describes an action, not a proviso, and leaves a
1461
1461
  monitor something to check — a drafting argument, not a source.
1462
- - **Q-54** — **Are Rule 17's phases monotone?** *Latching:* one three-valued
1463
- monotone latch per stand-on vessel per encounter; late compliance does not
1464
- take the permission away. *Re-evaluating:* each phase is a predicate on the
1465
- current state and the vessel may fall back — and must she then hold her *new*
1466
- course and speed? TLC distinguishes them on a four-state trace, so settle
1467
- before P4.2. No default. Recommend **latching**: one late alteration does not
1468
- restore reliance — an argument from purpose, not a source.
1462
+ - **Q-54** — **Are Rule 17's phases monotone?** *Monotone:* one three-valued
1463
+ marker per stand-on vessel per encounter; late compliance does not take the
1464
+ permission away. *Re-evaluating:* each phase is a predicate on the current
1465
+ state and the vessel may fall back — must she then hold her *new* course
1466
+ and speed? TLC distinguishes them on a four-state trace. **Ruled
1467
+ 2026-09-16:** monotone — permission or duty, once arisen, survives belated
1468
+ compliance; a fall-back needs a baseline the Rules lack (`Q-57`). No holding on point (colregs#72); *Ever Smart* [2021] UKSC 6 para 61 has the obligation cease at 17(a)(ii)/17(b) with no revival — consistent with monotone, not a ruling on it.
1469
1469
  - **Q-55** — **What does a visibility transition do to Section II state?**
1470
1470
  Rule 11 and 19(a) switch on the current state; no paragraph says what
1471
- becomes of a 13(d) latch or a Rule 17 phase. *Persisting:* they belong to the
1471
+ becomes of a 13(d) overtaking history or a Rule 17 phase. *Persisting:* they belong to the
1472
1472
  encounter and survive the fog. *Resetting:* Section II starts afresh on the
1473
1473
  geometry when sight is regained — the reclassification 13(d) forbids, via
1474
1474
  visibility. No default (nothing is temporal). Recommend **persisting**, which