colregs 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/data/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.3.2"
2
+ "version": "0.3.4"
3
3
  }
@@ -102,6 +102,8 @@ data one.
102
102
  international law where a national body deliberately has none. That is
103
103
  about deltas, not licences; it survives this ADR untouched and is the live
104
104
  blocker on CEVNI. Read the two together or the wrong one gets blamed.
105
+ *(ADR 0018 has since supplied that mechanism; the bar is now "land with
106
+ your tombstones", not "wait".)*
105
107
  - `schema/rules.schema.json` carries the conditional: `text` required unless
106
108
  `text_status` is `withheld`, in which case it is forbidden and
107
109
  `withheld_reason` is required. Only `withheld_reason` is refused on a
@@ -53,6 +53,25 @@ anyone has checked, and the `us/inland@2014` edition is recalled, not
53
53
  verified, and says so. That is the honest cost of this option and the reason
54
54
  to look at both.
55
55
 
56
+ ## Considered and declined (amendment, 2026-09-16)
57
+
58
+ Four designs additive on option B, declined for now rather than on
59
+ principle — each recorded in requirements.md §10 as a timed gate, closing
60
+ event the first national text whose edition cannot be determined:
61
+
62
+ - **Validity intervals on editions (`in_force_until`).** (GATE-7)
63
+ `superseded_by` plus `in_force` already infers validity for every
64
+ edition on file; a dedicated field would duplicate that inference.
65
+ - **A per-source publication record separate from the edition, FRBR
66
+ manifestation.** (GATE-8) `source` lives on the corpus and one edition
67
+ has one source per jurisdiction today; nothing distinguishes yet.
68
+ - **A content digest per corpus for verification.** (GATE-9)
69
+ `edition_status` already flags an unchecked corpus; a digest adds
70
+ tamper/drift detection nothing on file has needed.
71
+ - **A skeleton per edition, instead of one shared skeleton.** (GATE-10)
72
+ Low risk today: no amendment has ever renumbered a rule (GATE-1's
73
+ verified history). The trigger is the first one that does.
74
+
56
75
  ## Consequences
57
76
 
58
77
  - Breaking file layout (REQ-PKG-4): `data/rules.json` no longer carries
@@ -0,0 +1,102 @@
1
+ # ADR 0018 — A jurisdiction delta is an RFC 7396 merge patch, and a tombstone is its `null`
2
+
3
+ Date: 2026-09-16
4
+ Status: proposed — merging this PR is the ruling; a revert undoes it
5
+
6
+ ## Context
7
+
8
+ REQ-SCOPE-3 says a jurisdiction is a delta over `intl`: entries it does not
9
+ mention are inherited. Q-11 found that unsafe as stated. 33 CFR 83 leaves
10
+ Rule 28 "[Reserved]" and has no counterpart to 23(d)(ii), so a `us/inland`
11
+ delta that was merely silent there would inherit `rule:28` and assert an
12
+ international obligation the Inland Rules deliberately do not carry. Both
13
+ absences are verified against the primary source (Cornell LII's copy of
14
+ 33 CFR 83: "§ 83.28 [Reserved] (Rule 28)"; 83.23(d) is a single paragraph
15
+ with no subparagraphs). Q-11 asked for tombstones — "this entry deliberately
16
+ does not exist here", distinguishable from "not yet transcribed" — and held
17
+ every non-`intl` jurisdiction until the mechanism existed. Issue #45 asked,
18
+ separately, which standard encoding the delta should follow.
19
+
20
+ Both questions have been waiting on a second jurisdiction to force them.
21
+ Issue #137 records that nothing was proposing one. `us/inland` already exists
22
+ with two add-only entries under ADR 0008's carve-out, and the two absences
23
+ above are the counterexample that carve-out was left open for: a delta that
24
+ must suppress, not only add.
25
+
26
+ ## Decision
27
+
28
+ 1. **The delta semantics are RFC 7396, JSON Merge Patch.** A jurisdiction's
29
+ delta over `intl` is, in meaning, a merge-patch document keyed by entry
30
+ id: present keys are that jurisdiction's own entries, `null` keys are its
31
+ tombstones, and every key the patch does not mention is inherited. Any
32
+ conformant merge-patch implementation applied to the `intl` entries by
33
+ id reproduces the jurisdiction's resolved rule set. RFC 6902 is not
34
+ adopted: an operation script with JSON Pointer paths would duplicate the
35
+ id addressing `docs/identifiers.md` already provides.
36
+
37
+ 2. **Storage stays columnar; the patch is derived.** Entries keep their
38
+ `jurisdiction` field in the one `entries[]` table, as ADR 0008 laid them
39
+ down. Tombstones are a second top-level table, `suppressions[]`, one
40
+ record per (jurisdiction, entry): `jurisdiction`, `suppresses` (the
41
+ `intl` entry id), `cite` (the paragraph that has no counterpart) and
42
+ `why` (one sentence and the source). `test/data.test.mjs` builds the
43
+ merge patch from those two tables, applies it with a literal RFC 7396
44
+ implementation, and asserts the result equals the evaluator's
45
+ jurisdiction filter. That test is the statement that storage and
46
+ semantics agree; if they ever diverge, the test names which.
47
+
48
+ 3. **Replace is suppress plus add.** A jurisdiction that reads a paragraph
49
+ differently tombstones the `intl` entry and adds its own, under its own
50
+ id (ADR 0015 — the ids are distinct because the norms are). There is no
51
+ third operation and no in-place edit of an `intl` entry: REQ-SCOPE-4
52
+ holds.
53
+
54
+ 4. **The array caveat is accepted and irrelevant here.** Merge Patch
55
+ replaces an array wholesale. The patch is keyed at entry granularity, so
56
+ the only arrays it ever touches are inside a whole entry being added, and
57
+ an entry is small. A jurisdiction never patches one element of an
58
+ inherited entry's `lights`; it replaces the entry (point 3).
59
+
60
+ 5. **Only an inherited entry can be tombstoned.** A tombstone naming a
61
+ jurisdiction's own entry, or another jurisdiction's, is rejected by test:
62
+ the first is a deletion, the second was never in force.
63
+
64
+ 6. **A tombstone is verified the way an entry is.** Each needs one fixture
65
+ under its jurisdiction whose facts match the suppressed entry's predicate
66
+ and whose expectation omits it, and one `intl` fixture showing the entry
67
+ in force at the base (REQ-VERIFY-3, both sides).
68
+
69
+ 7. **Two tombstones land with this ADR**, both verified: `us/inland`
70
+ suppresses `rule:28` (Rule 28 "[Reserved]") and `rule:23d_ii` (no
71
+ counterpart to the under-7 m, 7 kn exception). They are enough to
72
+ exercise inherit and delete; no verified replace case exists in Part C
73
+ yet, so that branch of point 3 is stated, schema-ready and unexercised.
74
+
75
+ ## Consequences
76
+
77
+ - **Q-11 is answered and its hold is lifted.** REQ-SCOPE-3's "no non-`intl`
78
+ jurisdiction lands before an explicit suppression mechanism exists" is
79
+ discharged by this mechanism; a jurisdiction lands with its tombstones or
80
+ it does not land. ADR 0008's add-only carve-out survives as the trivial
81
+ case: a delta with no tombstones is a merge patch with no `null`s.
82
+ - **Issue #45 is closed by this ADR.** README names the RFC beside the
83
+ jurisdiction paragraph so a consumer knows which library semantics
84
+ reproduce the inheritance.
85
+ - **A suppressed entry can leave a record out of vocabulary.** Under
86
+ `us/inland` a record carrying `activity:cbd` now selects nothing:
87
+ `rule:28` is gone and the Rule 23(a) entries it imported read
88
+ `activity:none`. That is the honest answer — "constrained by her draft" is
89
+ not an Inland status — and the package does not pick a reading. It is
90
+ recorded in `known_omissions` and pinned by a fixture. Whether the fact
91
+ vocabulary should carry per-jurisdiction membership so a consumer's
92
+ decode can be checked is a new question, not decided here.
93
+ - **`rule:23d_i` cites a path Inland does not spell.** 33 CFR 83.23(d) has
94
+ no `(i)`; the content sits at bare `83.23(d)`. The entry is inherited
95
+ correctly — the norm is the same — and the citation-spelling question is
96
+ GATE-1's, untouched here.
97
+ - **GATE-1, Q-10 and Q-8 are not taken.** Q-11 named a "second-jurisdiction
98
+ bundle"; this ADR takes only the item that gated data. The others stay
99
+ open on their own triggers.
100
+ - **Cost to reverse.** Delete `suppressions[]` from data, schema and the
101
+ three tests; the two fixtures fail and are deleted with them. No consumer
102
+ reads the table yet. Pre-1.0, a revert.
@@ -0,0 +1,106 @@
1
+ # ADR 0019 — What a relation reaches, and what an import reads
2
+
3
+ Date: 2026-09-16
4
+ Status: proposed — merging this PR is the ruling; a revert undoes it
5
+
6
+ ## Context
7
+
8
+ REQ-MODEL-7 and the README define the six relation verbs by meaning and
9
+ leave composition to the consumer (REQ-CONS-3). colregs-engine#33 checked
10
+ the seven composition decisions its evaluator makes where the data is
11
+ silent. ADR 0007 settled the largest, direction: a directed "this one
12
+ prevails" is `rel:overrides`, and `rel:excludes` is pick-one between
13
+ alternatives. Three readings of the verbs remain stated only in
14
+ colregs-engine's `docs/engine-notes.md` (items 2, 3 and 5) and pinned only
15
+ by its tests: how far a relation reaches, what a `one_of` yields, and which
16
+ part of a referenced entry's predicate an import consults. Each is a
17
+ reading of the Rules, and the package that carries the Rules should say it.
18
+
19
+ ## Decision
20
+
21
+ 1. **Displacing relations reach entries in force; composing relations
22
+ reach what is exhibited.** An entry is *in force* when its own predicate
23
+ holds. `rel:overrides` and `rel:exempts` act on entries in force and on
24
+ nothing else: an import is not in force, it is a light set its carrier
25
+ exhibits, and the carrier is what a displacing relation must name.
26
+ `rel:in_lieu_of`, `rel:excludes`, `rel:includes` and
27
+ `rel:conditional_includes` act on what one display may contain, imports
28
+ included, and remove nothing from the set of entries in force. Direction
29
+ is carried by the verb, never by modality: an override fires from a
30
+ forceful entry (ADR 0007), an exemption from a `modality:exempt` one,
31
+ and `rel:excludes` fires from nowhere — it is symmetric and already
32
+ barred to forceful entries by CI (`test/data.test.mjs`, "rel:excludes is
33
+ reciprocated"). A consumer that infers a veto from an excluder's modality
34
+ is reading a relation the data does not carry.
35
+
36
+ 2. **A `one_of` yields exactly one option per display, or none when the
37
+ carrier is `modality:may`.** Under a `may` carrier the chosen option is
38
+ exhibited in lieu of the carrier's own lights, and the none choice
39
+ exhibits them (25(d)(ii): the sailing lights, or failing them the torch).
40
+ An option already in force by its own predicate discharges the set: the
41
+ carrier imports nothing, and the option composes as the entry it is. A
42
+ vessel restricted in her ability to manoeuvre at anchor shows 30(a) or
43
+ 30(b) because 30(a) and 30(b) apply to her, not because 27(b)(iv)
44
+ redirects her to them. Every choice is returned (REQ-MODEL-8).
45
+
46
+ 3. **An import reads the referenced entry's lights, their modality, and
47
+ its scalar gates — never its axes.** An import is a `rel:includes`, the
48
+ `rel:includes` of a `rel:conditional_includes` branch, or a `one_of`
49
+ option. `facts.json`'s `axes` and `modifiers` are the field: a key
50
+ declared there is the vessel's situation, and the carrier's redirect has
51
+ already placed her in it — 30(d) sends a vessel aground to "the lights
52
+ prescribed in paragraph (a) or (b)", and that she is not at anchor is the
53
+ premise of the redirect, not a gate on it. A key not declared there is a
54
+ fact the redirect does not alter, and the referenced entry's condition
55
+ on it binds: 30(b)'s "less than 50 metres" binds a vessel aground as it
56
+ binds one at anchor, and 25(b)'s "less than 20 metres" binds a vessel
57
+ under oars. Modality is the referenced entry's, resolved against the
58
+ vessel (Rule 28's three reds are `may`; the Rule 23 lights it imports
59
+ stay `shall`). A gate the carrier needs that the source does not carry is
60
+ written on the carrier's branch `when`, as 27(f) and 29(a) do; nothing
61
+ is inferred from a source's axes in either direction. REQ-MODEL-7's
62
+ "lights only, never its predicate" is amended to say this.
63
+
64
+ 4. **Two entries in force whose `rel:in_lieu_of` targets intersect are
65
+ alternatives to each other** and never share a display. This is an
66
+ invariant of the verb, not a declared pair list. The two pairs the data
67
+ can hold in force together read that way in the text: 23(d)(ii)'s
68
+ display is 23(d)(i)'s with the sidelights made practicable-only, and
69
+ 25(d)(i)'s torch is what a vessel shows *if she does not* exhibit (a) or
70
+ (b). The Rule 24 entries that share targets — 24(a)(i) below and above
71
+ 200 m, and 24(c) — are disjoint on their own predicates and never meet.
72
+ A future pair that lawfully combines is the evidence to reopen this
73
+ point; until one exists, the target sets are the declaration.
74
+
75
+ Three shapes were considered and not adopted. Restating each option's
76
+ scalar gate on the carrier's branch (30(d) split at 50 m) keeps "lights
77
+ only" literal at the cost of transcribing 30(b)'s condition into 27(b)(iv),
78
+ 27(f), 29(a) and 30(d), and 25(b)'s into 25(d)(ii), plus a CI check to
79
+ police the copies; the text redirects, it does not restate, and REQ-MODEL-5
80
+ puts a gate where its fact lives. Declaring the point-4 pairs as a relation
81
+ duplicates what the target sets say. A per-verb "reaches imports" flag
82
+ would be set the same way on every entry, and a field nothing varies is
83
+ decoration.
84
+
85
+ ## Consequences
86
+
87
+ - **No data changes.** The README relation table, REQ-MODEL-7 and the
88
+ `relations` notes in `data/applicability.json` say the four points in
89
+ this PR. `docs/identifiers.md` and the schema are untouched.
90
+ - **colregs-engine implements this in one issue, three deletions.** Its
91
+ modality-inferred exclusion path goes: `rel:excludes` is a co-occurrence
92
+ check on a display and nothing more. Its `includeApplies` goes: it
93
+ consulted one axis by name on `rel:includes` imports, the inverse of
94
+ point 3, and no import in the data reaches it on a coherent record —
95
+ every carrier either shares the source's position gate (23(b), 23(c),
96
+ 25(c), 28), gates its branch on it (24, 27(f), 29(a)), or reads
97
+ `fact:making_way`, which refines `position:underway` (26(b)(iii),
98
+ 26(c)(iii), 27(a)(iii), 27(b)(iii)). The availability test it already
99
+ applies to `one_of` options becomes the one rule for every import. Its
100
+ `docs/engine-notes.md` items 2–5 become pointers here. colregs-engine#33
101
+ items 1, 6 and 7 stay the engine's: presentation and output shape.
102
+ - **A `one_of` option's scalar gate is a normative read of the source
103
+ entry.** Editing 30(b)'s length gate changes what a vessel aground may
104
+ show. That is the intended coupling: one paragraph, one gate.
105
+ - **Cost to reverse.** Delete this file and restore two sentences; the
106
+ engine's deleted paths come back by revert. Pre-1.0, a revert.
@@ -0,0 +1,80 @@
1
+ # ADR 0020 — The skeleton is a delta too: a jurisdiction's paragraphs are a merge patch over `intl`
2
+
3
+ Date: 2026-09-17
4
+ Status: proposed — merging this PR is the ruling; a revert undoes it
5
+
6
+ ## Context
7
+
8
+ ADR 0018 made the entries table a delta over `intl`. The skeleton was not
9
+ one. `data/rules.json` keyed every paragraph by bare path, one record per
10
+ key, and every one of them was `intl`; the corpus test asserted that a
11
+ corpus paragraph's path belongs to the corpus's own jurisdiction. So a
12
+ `us/inland` corpus could not carry `21(a)`: the key existed and was
13
+ `intl`'s. The 2026-08-30 diff of 33 CFR 83 against Part C found 18 paths
14
+ where Inland spells the same path with different text, three it does not
15
+ spell at all, and a dozen it adds. None of the 18 could be stated. That,
16
+ not a licence, is why the Inland corpus stub had no paragraphs (issue
17
+ #161), and why every planning session stalled on "the second jurisdiction".
18
+
19
+ Solace ruled on issue #137 on 2026-09-17: `us/inland`, Part C, before v1.
20
+
21
+ ## Decision
22
+
23
+ 1. **`rules.json` gains `deltas`, keyed by jurisdiction.** A delta has
24
+ `paragraphs` (own rows, keyed by path, each carrying its jurisdiction)
25
+ and `suppressions` (paths the source does not spell, each with a `why`).
26
+ `paragraphs` at the top level stays the `intl` base, untouched, so every
27
+ existing consumer reads what it read.
28
+
29
+ 2. **A jurisdiction's resolved skeleton is the RFC 7396 merge patch of its
30
+ delta over the base**, the same statement ADR 0018 makes for entries: own
31
+ rows present, suppressed paths `null`, an unmentioned path inherited
32
+ whole. A restated path merges field by field, so an own row that says
33
+ nothing about `images` inherits the base figure. The test builds the
34
+ patch, applies a literal RFC 7396 implementation, and asserts the
35
+ resolved skeleton is what corpora, entries and fixtures key into.
36
+
37
+ 3. **A path is stated in a delta when its text differs from `intl` or has no
38
+ `intl` counterpart; suppressed when the source does not spell it; silent
39
+ otherwise.** A `[Reserved]` section is a spelled path with reserved text,
40
+ so it is stated, not suppressed: Inland `28` and `26(d)` are rows whose
41
+ corpus text will be `[Reserved]`.
42
+
43
+ 4. **An entry in force under a jurisdiction cites a path in that
44
+ jurisdiction's resolved skeleton.** An inherited `intl` entry whose path
45
+ the delta suppresses cannot stand by silence: it is tombstoned, and where
46
+ the norm survives under another path, replaced (ADR 0018 point 3).
47
+
48
+ 5. **`us/inland` lands with its Part C skeleton delta**, every row from
49
+ `docs/verification/2026-08-30-q6-q8.md`: 19 restated paths (the 18
50
+ differing plus `28`), 18 Inland-only paths, and `23(d)(i)`, `23(d)(ii)`,
51
+ `23(d)(iii)` suppressed. A new sub-paragraph is stated when `intl`
52
+ already carries sibling sub-rows of that parent; where `intl`'s parent is
53
+ one row, the parent is restated and the sub-paragraph waits for the
54
+ corpus. So `24(f)`'s Inland `(iii)` and `22(d)`'s Inland `(ii)` wait
55
+ (`24(f)`, `22(d)` are one row each in `intl`), while `24(g)(v)` is stated
56
+ (`intl`'s `24(g)(i)` is a sibling row). `NRHB_23_e.png` and
57
+ `NRHB_24_j.png` are mapped to `23(e)` and `24(j)` and stop being
58
+ unmapped.
59
+
60
+ 6. **The first replace lands with it.** Inland 83.23(d) is the under-12 m
61
+ provision as one paragraph; `23(d)(i)` is not a path there. Point 4
62
+ forces the branch ADR 0018 left unexercised: `rule:23d_i` is tombstoned
63
+ under `us/inland` and `rule:23d`, same predicate and lights, cites
64
+ `23(d)`. Fixtures show both sides.
65
+
66
+ ## Consequences
67
+
68
+ - The Inland corpus can now be filled: every path it will carry resolves.
69
+ Text is 17 U.S.C. 105, so REQ-PROV-2 does not gate it. That is the next PR.
70
+ - `us/inland` is now six applicability records and a skeleton delta of 40
71
+ rows. README's coverage statement says so; it is still not a model of the
72
+ Inland Rules until the entries for the restated paths land.
73
+ - The skeleton edition `us/inland@2014` is declared and still recalled, not
74
+ verified against the Federal Register (REQ-LANG-10). The corpus fetch
75
+ verifies it or corrects it.
76
+ - GATE-1 is untouched: a path that differs across jurisdictions at one time
77
+ is REQ-MODEL-1 working as designed, and this ADR gives it a home.
78
+ - **Cost to reverse.** Delete `deltas` from data and schema, the resolver and
79
+ three tests, `rule:23d` and its tombstone, two fixtures; unmap two images.
80
+ No consumer reads `deltas` yet. Pre-1.0, a revert.
package/docs/budgets.json CHANGED
@@ -23,9 +23,12 @@
23
23
  "docs/adr/0015-rule-ids-are-paragraph-keys.md": 210,
24
24
  "docs/adr/0016-encounter-roles-are-pooled-across-frames.md": 90,
25
25
  "docs/adr/0017-closed-vocabularies-are-prefixed-identifiers.md": 120,
26
+ "docs/adr/0018-jurisdiction-delta-is-a-merge-patch.md": 120,
27
+ "docs/adr/0019-relation-reach-and-import-reads.md": 110,
26
28
  "docs/timeline.md": 130,
27
29
  "docs/maritime-sources.md": 130,
28
- "docs/decisions.md": 40
30
+ "docs/decisions.md": 40,
31
+ "docs/adr/0020-skeleton-is-a-delta.md": 110
29
32
  },
30
33
  "json_prose": {
31
34
  "targets": [
package/docs/decisions.md CHANGED
@@ -3,4 +3,8 @@
3
3
  Rulings from `/sequence` sessions and other closed judgment calls. One line
4
4
  each: date, short name, the answer, a link to the argument.
5
5
 
6
+ - 2026-09-16 — docs ownership: colregs-engine's docs are sited wrong; colregs owns docs going forward, no new doc lands in colregs-engine. `normative-language.md` was already migrated the same day (commit fe0f8c2, #125); migration of the remaining three (`formal-methods-glossary.md`, `formal-methods-reading-list.md`, `engine-notes.md`) is not yet scheduled. Argued on kanban; no public writeup to link.
6
7
  - 2026-09-16 — own vs self: rename the subject segment `own` to `self` across the situation record (fact keys, precedence effect keys, facts.json, fixtures, docs/identifiers.md). Work spawned as [colregs#138](https://github.com/mark-brannan/colregs/issues/138).
8
+ - 2026-09-16 — Q-54, Rule 17's phases are monotone: once 17(a)(ii) permission or the 17(b) duty has arisen for the stand-on vessel, it does not fall back on belated give-way compliance. Argued in [colregs#72](https://github.com/mark-brannan/colregs/issues/72); recorded in `docs/requirements.md`.
9
+ - 2026-09-16 — Q-53, 17(a)(ii) is an exception, not a suspension: the stand-on vessel's duty stands and a departure is lawful only as action to avoid collision; a monitor flags any other alteration. Argued in [colregs#72](https://github.com/mark-brannan/colregs/issues/72); recorded in `docs/requirements.md`.
10
+ - 2026-09-17 — second jurisdiction: `us/inland`, Part C, before v1. Ruled on [colregs#137](https://github.com/mark-brannan/colregs/issues/137); skeleton delta lands under ADR 0020, text and entries follow.
package/docs/gates.json CHANGED
@@ -11,6 +11,7 @@
11
11
  "first-non-english-corpus": "the second corpus of any one jurisdiction, which in practice is the first non-English text",
12
12
  "first-community-translation-of-national-corpus": "the first `community`-tier translation of a `national`-tier corpus",
13
13
  "first-external-contribution": "the first merged contribution from someone other than the copyright holder",
14
+ "first-undated-national-edition": "the first national text whose edition cannot be determined",
14
15
  "none": "the decline does not get cheaper or dearer with time; recorded so it is not re-read as merely deferred"
15
16
  },
16
17
  "statuses": {
@@ -79,6 +80,46 @@
79
80
  "status": "open",
80
81
  "settled_by": null,
81
82
  "note": "ADR 0004 settles the code licence (MIT \u2192 Apache-2.0) and leaves the data licence open. Already-published npm versions stay under the licence they shipped with; the gate governs future releases only, and is held open deliberately by REQ-PROV-7's CONTRIBUTING.md terms (DCO-style certification plus a relicensing grant); a CLA-assistant bot is the upgrade path if contributors arrive."
83
+ },
84
+ {
85
+ "id": "GATE-7",
86
+ "title": "validity intervals on editions (`in_force_until`)",
87
+ "declined_in": "docs/adr/0013-corpus-files-with-editions.md",
88
+ "closing_event": "first-undated-national-edition",
89
+ "trigger": "an edition superseded with no successor edition registered to bound it \u2014 repeal without replacement, or two editions of one jurisdiction whose validity ranges cannot be ordered from `superseded_by` alone",
90
+ "status": "open",
91
+ "settled_by": null,
92
+ "note": "Declined alongside ADR 0013 (option B, GATE-2 adopted): `superseded_by` plus `in_force` infers validity for every edition on file today. An explicit `in_force_until` is additive, not a rewrite, so paying for it before a case needs it buys nothing."
93
+ },
94
+ {
95
+ "id": "GATE-8",
96
+ "title": "a per-source publication record separate from the edition (FRBR manifestation)",
97
+ "declined_in": "docs/adr/0013-corpus-files-with-editions.md",
98
+ "closing_event": "first-undated-national-edition",
99
+ "trigger": "two distinct published sources for the same edition that disagree \u2014 e.g. an official gazette printing and a codifier's republication of the same edition differing in errata \u2014 so \"the source\" stops being a property of the edition",
100
+ "status": "open",
101
+ "settled_by": null,
102
+ "note": "Declined alongside ADR 0013: today `source` lives on the corpus and one edition has one source per jurisdiction. A manifestation layer is additive when a second publication record is actually needed."
103
+ },
104
+ {
105
+ "id": "GATE-9",
106
+ "title": "a content digest per corpus for verification",
107
+ "declined_in": "docs/adr/0013-corpus-files-with-editions.md",
108
+ "closing_event": "first-undated-national-edition",
109
+ "trigger": "a corpus found to differ from its cited source with no accompanying edition or source change \u2014 silent drift a hash would have caught and prose review did not",
110
+ "status": "open",
111
+ "settled_by": null,
112
+ "note": "Declined alongside ADR 0013: `edition_status` (verified/claimed/unknown, this ADR's before-merge item 1) already flags an unchecked corpus. A digest adds tamper/drift detection on top, which nothing on file today has needed."
113
+ },
114
+ {
115
+ "id": "GATE-10",
116
+ "title": "a skeleton per edition",
117
+ "declined_in": "docs/adr/0013-corpus-files-with-editions.md",
118
+ "closing_event": "first-undated-national-edition",
119
+ "trigger": "the first amendment that deletes or renumbers a path",
120
+ "status": "open",
121
+ "settled_by": null,
122
+ "note": "Declined alongside ADR 0013: one shared `data/rules.json` skeleton is low risk because no amendment has ever renumbered a rule (seven IMO amendments since 1972, none doing so). A per-edition skeleton is the fallback the day one does."
82
123
  }
83
124
  ]
84
125
  }
@@ -181,7 +181,7 @@ is an enumerated fact, so its values follow the bare-fact-name rule above:
181
181
  Rule 13(d) is the reason history is a class and not a note. Once a vessel is
182
182
  overtaking, a subsequent alteration of the bearing does not make her a
183
183
  crossing vessel; the instantaneous geometry, read alone, says otherwise and
184
- hands the duty to the wrong vessel. So the latch is a fact:
184
+ hands the duty to the wrong vessel. So overtaking history is a fact:
185
185
 
186
186
  - `self:hist:was_overtaking` — this subject was, earlier in this encounter,
187
187
  an overtaking vessel with respect to the other.
@@ -433,6 +433,9 @@ implemented in the reference evaluator and asserted by the fixtures.
433
433
  words. It is deliberately not a light reference and does not resolve to
434
434
  one.
435
435
 
436
+ Not being an identifier says nothing about whether a vocabulary gets a
437
+ catalog label; see REQ-LANG-6.
438
+
436
439
  ## This does not reverse GATE-5
437
440
 
438
441
  GATE-5 declined a CI-enforced terminology glossary, permanently, for the
@@ -26,6 +26,12 @@ question the rule text leaves open.
26
26
  - **Nautical Institute — *Action by the Stand-On Vessel*** (Seaways case study). The stand-on vessel's stages as taught; does not reach whether they are reversible.
27
27
  <https://www.nautinst.org/resources-page/200115-action-by-the-stand-on-vessel.html>
28
28
  - **USCG Navigation Rules (Amalgamated)**. <https://www.navcen.uscg.gov/navigation-rules-amalgamated>
29
+ - **Steamship Mutual — *Navigation in Restricted Visibility***. Confirms Section II reapplies once vessels are in sight of one another again; silent on whether status accumulated before the loss of sight (a `Q-51`/`Q-52` classification, a `Q-54` Rule 17 stage) carries forward.
30
+ <https://www.steamshipmutual.com/publications/articles/restrictedvisibility0109>
31
+ - **Britannia P&I — *Navigation in restricted visibility***. No stand-on vessel exists under Rule 19; also silent on status continuity across the transition.
32
+ <https://britanniapandi.com/en_gb/guidance/navigation-in-restricted-visibility/>
33
+ - **Professional Mariner — *Overtaking or crossing? Don't assume what other ship will do***. The Rule 13(d) bearing-shift overtaking history, discussed only within continuous visual contact.
34
+ <https://professionalmariner.com/overtaking-or-crossing-dont-assume-what-other-ship-will-do/>
29
35
 
30
36
  ## Marine incident analysis
31
37
 
@@ -47,6 +53,16 @@ ambiguous give-way/stand-on roles are what the Rules are written against.
47
53
  <https://www.bahamasmaritime.com/wp-content/uploads/2026/02/2026-5-Polesie-Verity-ReportAndAnnexes.pdf>
48
54
  - IMO GISIS Marine Casualties and Incidents module. Not a paper but a source class: the mandatory-reporting database of marine safety investigation reports. Ground truth for real COLREGS-relevant incidents.
49
55
  <https://www.imo.org/en/OurWork/IIIS/Pages/Marine-Safety-Investigation-reports.aspx>
56
+ - NTSB/MAR-16/01 — *Conti Peridot*/*Carla Maersk* collision, Houston Ship Channel. Occurred entirely within restricted visibility; no in-sight phase, no Rule 13/17 discussion. Checked for `Q-55` and found not on point.
57
+ <https://www.ntsb.gov/investigations/AccidentReports/Reports/MAR1601.pdf>
58
+ - Dutch Safety Board — *Collision in Restricted Visibility* (*VB Seal*/*Gulholmen*, Maasmond, 2026). Rules appendix cites only Rules 6 and 19; the encounter never had an in-sight phase. Checked for `Q-55` and found not on point.
59
+ <https://onderzoeksraad.nl/wp-content/uploads/2026/07/collision-in-restricted-visibility.pdf>
60
+ - TSB Canada M23C0143 — ferry *Svanoy*. Fog/lookout casualty; no Section II status question arises.
61
+ <https://www.tsb.gc.ca/eng/rapports-reports/marine/2023/m23c0143/m23c0143.html>
62
+ - SWZ Maritime on Nautical Institute MARS 202601 (near-miss in fog). Operational-failure summary only; no rule-regime discussion.
63
+ <https://swzmaritime.nl/news/2026/02/13/near-vessel-collision-in-fog/> · MARS index: <https://www.nautinst.org/technical-resources/mars.html>
64
+ - Marine Insight — fog/TSS-turn collision write-up. Overtaking occurred entirely within fog; no visibility transition at issue.
65
+ <https://www.marineinsight.com/real-life-incident-vessels-collide-in-dense-fog-during-sudden-tss-turn/>
50
66
 
51
67
  ## Known gaps
52
68
 
@@ -55,4 +71,5 @@ ambiguous give-way/stand-on roles are what the Rules are written against.
55
71
  manoeuvrability, shoal water, a lee shore, set, visibility or sea state.
56
72
  - Two standard texts — Cockcroft & Lameijer, *A Guide to the Collision Avoidance Rules*, and Farwell's *Rules of the Nautical Road* — are not online. Either may settle how the stages of a close-quarters encounter are divided, and whether they are treated as irreversible.
57
73
  - Several of the questions in `docs/requirements.md` §11 appear unlitigated: overtaking geometry with no risk of collision, an overtaking situation becoming a head-on, resumption of course by a stand-on vessel that has acted, and the fate of accumulated Section II state across a visibility transition.
74
+ - `Q-55` (visibility transition): checked casualty reports, P&I guidance and trade-press commentary beyond the sources above — no authority found in either direction on whether a `Q-51`/`Q-52` classification or a `Q-54` Rule 17 stage survives a restricted-visibility interruption or resets on regaining sight. Deferred indefinitely, 2026-09-16; Cockcroft & Lameijer and Farwell (both already listed above as unreachable) remain the most plausible sources to settle it.
58
75
  - BAILII refuses automated access. Use the National Archives Find Case Law service: <https://caselaw.nationalarchives.gov.uk/>
@@ -67,7 +67,7 @@ is Rules 11–18, III is Rule 19; which governs a pair is `INV-19a-scope`.
67
67
  # Rule 13 — Overtaking
68
68
 
69
69
  13(a) assigns a role, 13(b) deems the encounter, 13(c) resolves doubt, 13(d)
70
- latches the result against the geometry that follows.
70
+ persists the result against the geometry that follows.
71
71
 
72
72
  ### INV-13b — the overtaking deeming test
73
73
 
@@ -122,7 +122,7 @@ well as Rules 14 and 15.
122
122
  Settled by P4.2's role assignment: the override is or is not needed to keep
123
123
  "never both give-way" true.
124
124
 
125
- ### INV-13d — the latch: the classification survives the geometry
125
+ ### INV-13d — overtaking history: the classification survives the geometry
126
126
 
127
127
  `13(d)` · classification · temporal, a state to every later state of the
128
128
  encounter · `✎`
@@ -140,10 +140,11 @@ until self is finally past and clear, the encounter type of the pair is
140
140
  forbids: an overtaking drawn out on the bow reads *crossing*, and hands
141
141
  give-way to the wrong vessel.
142
142
  - **Undetermined term.** "Finally past and clear" has no fact and no threshold;
143
- the data's latch is consumer-cleared and never self-clears (`Q-47`), a trace
144
- model's is its segmentation, and no bearing or range is invented here.
145
- - **Readings in doubt.** Two: what arms the latch, `Q-51`; what it forbids,
146
- `Q-52`.
143
+ the data's overtaking history is consumer-cleared and never self-clears
144
+ (`Q-47`), a trace model's is its segmentation, and no bearing or range is
145
+ invented here.
146
+ - **Readings in doubt.** Two: what arms the overtaking history, `Q-51`; what it
147
+ forbids, `Q-52`.
147
148
  - Entries: `rule:13d`, reading `self`/`other:hist:was_overtaking` and no geometry; the
148
149
  `was_overtaking: false` gates on `rule:14b`, `rule:15a:crossing`, `rule:15a:keep_out_of_the_way`
149
150
  implement `Q-52`'s *broad* reading. Settled by `Q-51`, `Q-52`, then TLC on a
@@ -162,8 +163,8 @@ type alone cannot distinguish `Q-52`'s readings.
162
163
 
163
164
  - **State remembered.** As `INV-13d`.
164
165
  - Entries: `rule:13a`'s `any_of` second limb, `self:hist:was_overtaking: true` — role
165
- asserted from the latch directly, keeping the limbs separable. Settled by
166
- `Q-52`.
166
+ asserted from the overtaking history directly, keeping the limbs separable.
167
+ Settled by `Q-52`.
167
168
 
168
169
  ---
169
170
 
@@ -174,10 +175,10 @@ type alone cannot distinguish `Q-52`'s readings.
174
175
  `14(b)` reading 14(a)'s conditions · classification · single-state · `✎`
175
176
 
176
177
  **Invariant.** At any state at which two power-driven vessels are in sight,
177
- both underway, with risk of collision, and neither latched under `INV-13d`, a
178
- head-on situation is deemed to exist exactly when each sees the other ahead or
179
- nearly ahead: `self:geo:rel_bearing_deg` and `other:geo:rel_bearing_deg` each
180
- in [0°, 11.25°] ∪ [348.75°, 360°).
178
+ both underway, with risk of collision, and neither carrying overtaking history
179
+ under `INV-13d`, a head-on situation is deemed to exist exactly when each sees
180
+ the other ahead or nearly ahead: `self:geo:rel_bearing_deg` and
181
+ `other:geo:rel_bearing_deg` each in [0°, 11.25°] ∪ [348.75°, 360°).
181
182
 
182
183
  - **Both bearings, not one.** 14(b)'s lights limb is a statement about the
183
184
  *other* vessel's aspect; one bearing alone swallows part of the crossing
@@ -219,9 +220,9 @@ way; both are directed to act, and the duty is symmetric.
219
220
  `15(a)` · classification · single-state · `✎`
220
221
 
221
222
  **Invariant.** At any state at which two power-driven vessels are in sight,
222
- both underway, with risk of collision, and neither latched under `INV-13d`, the
223
- encounter type is `crossing` exactly when it is neither `overtaking` under
224
- `INV-13b` nor `head-on` under `INV-14b`.
223
+ both underway, with risk of collision, and neither carrying overtaking history
224
+ under `INV-13d`, the encounter type is `crossing` exactly when it is neither
225
+ `overtaking` under `INV-13b` nor `head-on` under `INV-14b`.
225
226
 
226
227
  - **Derived, not enumerated.** Enumerating the sector gives two statements of
227
228
  one boundary, and the partition's only failure mode is editing one;
@@ -395,7 +396,9 @@ without further action by the give-way vessel.
395
396
  - **Formally.** Reachability over the stand-on vessel's manoeuvring envelope:
396
397
  `Safe(s, σ_own, σ_other)` of ADR 0005 §5 with the give-way strategy set
397
398
  unconstrained — the first Part B invariant needing `kin:dynamics`.
398
- - **Reading in doubt.** Suspension or exception: `Q-53`.
399
+ - **Reading ruled.** Exception, not suspension (`Q-53`, 2026-09-16): the
400
+ 17(a)(i) duty stands and the only lawful departure is action to avoid
401
+ collision; a checker flags any other alteration.
399
402
 
400
403
  ### INV-17b — phase 3: the stand-on vessel shall act
401
404
 
@@ -462,11 +465,12 @@ is at each state in exactly one of three phases:
462
465
 
463
466
  Phase 3 dominates phase 2: an obligation is not qualified by a permission.
464
467
 
465
- - **Reading in doubt.** Monotone or not: `Q-54`.
466
- - **State remembered.** If monotone, one three-valued latch per stand-on vessel
467
- per encounter; if not, no latch but `INV-17c` still needs the phase of each
468
- action. TLC distinguishes them: under monotone a late-complying give-way
469
- vessel still leaves stand-on action permitted; under reversible it does not.
468
+ - **Reading ruled.** Monotone (`Q-54`): once phase 2 or 3 is reached for the
469
+ stand-on vessel in an encounter, it does not fall back on belated give-way
470
+ compliance.
471
+ - **State remembered.** One three-valued marker per stand-on vessel per
472
+ encounter, monotone: a late-complying give-way vessel still leaves stand-on
473
+ action permitted.
470
474
 
471
475
  ---
472
476
 
@@ -601,7 +605,7 @@ not jointly exhaustive (`INV-19a-third-state`); Rule 19 supplements Section I
601
605
 
602
606
  - **Temporal note.** The switch is a function of the current state; a pair may
603
607
  cross it and back inside one encounter, and no paragraph says what becomes of
604
- a 13(d) latch or a Rule 17 phase: `Q-55`.
608
+ a 13(d) overtaking history or a Rule 17 phase: `Q-55`.
605
609
  - **Undetermined term.** "In or near an area of restricted visibility" has no
606
610
  fact (3(l)'s atmospheric condition is nowhere in `data/facts.json`), so `rule:19a`
607
611
  selects Section III for any pair not in sight — wider — and records a gap.