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/README.md +24 -9
- package/data/applicability.json +143 -18
- package/data/corpora.json +5 -5
- package/data/editions.json +7 -2
- package/data/i18n/en.json +71 -5
- package/data/i18n/fi.json +2 -2
- package/data/images.json +12 -4
- package/data/lights.json +10 -20
- package/data/rules.json +216 -1
- package/data/text/intl/1977/fi.finlex.json +881 -0
- package/data/version.json +1 -1
- package/docs/adr/0010-text-withheld-jurisdictions.md +2 -0
- package/docs/adr/0013-corpus-files-with-editions.md +19 -0
- package/docs/adr/0018-jurisdiction-delta-is-a-merge-patch.md +102 -0
- package/docs/adr/0019-relation-reach-and-import-reads.md +106 -0
- package/docs/adr/0020-skeleton-is-a-delta.md +80 -0
- package/docs/budgets.json +4 -1
- package/docs/decisions.md +4 -0
- package/docs/gates.json +41 -0
- package/docs/identifiers.md +4 -1
- package/docs/maritime-sources.md +17 -0
- package/docs/part-b-invariants.md +26 -22
- package/docs/requirements.md +87 -88
- package/fixtures/applicability-fixtures.json +90 -0
- package/package.json +4 -1
- package/schema/applicability.schema.json +15 -0
- package/schema/display-evaluation.schema.json +0 -4
- package/schema/i18n-catalog.schema.json +25 -4
- package/schema/lights.schema.json +2 -3
- package/schema/rules.schema.json +48 -0
- package/data/text/intl/2016/fi.finlex.json +0 -22
package/docs/requirements.md
CHANGED
|
@@ -72,15 +72,16 @@ Neither consumer lives in this repo.
|
|
|
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
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
A delta that
|
|
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
|
|
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
172
|
forceful (`modality:shall`/`modality: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.
|
|
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
|
|
@@ -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**
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
with per-language catalogs, separate from legal
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
|
|
@@ -638,8 +639,7 @@ specification until 1.0.
|
|
|
638
639
|
|
|
639
640
|
### Open gates
|
|
640
641
|
|
|
641
|
-
Each
|
|
642
|
-
|
|
642
|
+
Each names the declined design, closing event, and trigger.
|
|
643
643
|
- **GATE-1 — `paragraph_id` split from `citation_path`**
|
|
644
644
|
(ADR 0003, declined; REQ-LANG-3, REQ-PKG-4).
|
|
645
645
|
*Closing event*: the 1.0 tag. Before it, splitting the two is a
|
|
@@ -763,8 +763,9 @@ Each gate names the declined design, the closing event, and the trigger.
|
|
|
763
763
|
unlikely short of major success. Recorded regardless: "unlikely" is not
|
|
764
764
|
a closing event (REQ-GATE-1).
|
|
765
765
|
|
|
766
|
-
|
|
767
|
-
|
|
766
|
+
Four gates from ADR 0013 (option B), *closing event* for all four the first national text whose edition cannot be determined: **GATE-7 — validity intervals on editions (`in_force_until`)**, trigger an edition superseded with no successor to bound it; **GATE-8 — a per-source publication record separate from the edition (FRBR manifestation)**, trigger two published sources for one edition that disagree; **GATE-9 — a content digest per corpus for verification**, trigger a corpus differing from its cited source with no edition or source change; **GATE-10 — a skeleton per edition**, trigger the first amendment that deletes or renumbers a path.
|
|
767
|
+
|
|
768
|
+
Gates whose closing event is "none" are recorded because a future reader will otherwise re-ask whether they were merely deferred. They were not.
|
|
768
769
|
|
|
769
770
|
### Gate status is data
|
|
770
771
|
|
|
@@ -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.
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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
|
|
@@ -1153,7 +1153,7 @@ named that gap before the class existed.
|
|
|
1153
1153
|
first-cut table, but it is the one paragraph of Rule 13 that assigns a role
|
|
1154
1154
|
and a `category:classification` entry has nowhere to put one. Entry `rule:13a` is
|
|
1155
1155
|
`category:precedence` here, with 13(b)'s sector test left for the `category:classification`
|
|
1156
|
-
entry that would set the `hist:was_overtaking`
|
|
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*
|
|
@@ -1161,7 +1161,7 @@ named that gap before the class existed.
|
|
|
1161
1161
|
encounter type belongs to the pair and reading aspect alone classified the
|
|
1162
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
|
-
|
|
1164
|
+
overtaking history, as an `any_of`, which closes the gap the entry recorded. 13(d) is a
|
|
1165
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
|
|
@@ -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`
|
|
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
|
|
@@ -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
|
|
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
|
|
@@ -1344,7 +1344,7 @@ 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
|
|
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.
|
|
@@ -1354,14 +1354,14 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
|
|
|
1354
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
|
|
1358
|
-
test is suppressed on the other, newly-gaining vessel — once
|
|
1359
|
-
always overtaking, per 13(d)'s own text, so a geometry test
|
|
1360
|
-
newly name a second give-way vessel must not fire while the
|
|
1361
|
-
holds the role by history alone. `rule:13a`'s sector branch now
|
|
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
|
|
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
1367
|
`self:geo:rel_bearing_deg`, `other:geo:rel_bearing_deg`, the two
|
|
@@ -1392,7 +1392,7 @@ 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)
|
|
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
|
|
@@ -1416,6 +1416,7 @@ written up in `docs/identifiers.md` §"Effects"; what it could not is here.
|
|
|
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`).
|
|
1419
|
+
- **Q-58** — **Do the Rule 18/12 role entries need `other:hist:was_overtaking: false`, like `rule:13a` and `rule:15a:keep_out_of_the_way` (Q-47)?** The nine `18a*`/`18b*`/`18c*` and three `12a*` entries carry no such gate, and `rule:13a` overrides them only when *self* holds the history; when the *other* holds it, self is named give-way under Rule 18 or 12 while 13(a) puts the duty on the other alone. Default **ungated** (nothing changes), recorded as a `gap` on the twelve. Recommend **gated**, in Q-47's shape: 13(a)'s 'notwithstanding' and Rule 18's own exception for Rule 13 both displace these entries, and Q-47 already ruled the history decides who holds the role. colregs-engine#75 (closed) read the table as self-centric and recommended a consumer swap subjects for the other's duty; that answers the other's role, not self's wrong one. `colregs#117`.
|
|
1419
1420
|
|
|
1420
1421
|
### From the Part B invariants (P4.1)
|
|
1421
1422
|
|
|
@@ -1426,22 +1427,20 @@ nothing is blocked while open.
|
|
|
1426
1427
|
- **Q-50** — **Does risk of collision gate Rules 13 and 18?** 14(a) and 15(a)
|
|
1427
1428
|
say "so as to involve risk of collision"; Rule 13 and Rule 18 do not.
|
|
1428
1429
|
*Wide:* they attach whenever in sight and the geometry holds — Rule 11 is the
|
|
1429
|
-
only gate Section II states
|
|
1430
|
-
give-way and Rule 16 binds her. *Narrow:* Section II's duties attach only with
|
|
1430
|
+
only gate Section II states. *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
|
-
`rule:13d` and every Rule 18 entry read `in_sight` only.
|
|
1433
|
-
-
|
|
1432
|
+
`rule:13d` and every Rule 18 entry read `in_sight` only. **Ruled
|
|
1433
|
+
2026-09-17:** wide — the window is the encounter itself. A pair the engine is
|
|
1434
|
+
evaluating is an encounter, at whatever range suits the vessels; inside it 13
|
|
1435
|
+
and 18 attach on sight and geometry alone, and how close is clear stays a
|
|
1436
|
+
monitor parameter. *The Nowy Sacz* [1977] 2 Lloyd's Rep 91 (CA) holds risk
|
|
1437
|
+
of collision unnecessary for the overtaking rule; *Meghna Princess* [2017]
|
|
1438
|
+
SGHC 220 [56] restates it; nothing found on Rule 18 either way (colregs#72).
|
|
1439
|
+
- **Q-51** — **What arms 13(d)'s overtaking history?** *A:* 13(b)'s deeming, at the first
|
|
1434
1440
|
state the geometry holds. *B:* 13(a)'s duty actually attaching. They differ
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
latch arms on risk of collision and then persists; no authority was found on
|
|
1439
|
-
overtaking geometry with no risk of collision. Free to reverse: four entries
|
|
1440
|
-
(`rule:13a`, `rule:13b`, `rule:13d`) and their fixtures, and nothing consumes the one
|
|
1441
|
-
state this changes the answer for. Settled by: a decision on Rule 13 itself,
|
|
1442
|
-
or Cockcroft & Lameijer on whether overtaking status needs risk of
|
|
1443
|
-
collision.
|
|
1444
|
-
- **Q-52** — **What does 13(d)'s latch forbid?** *Narrow:* reclassification to
|
|
1441
|
+
only on `Q-50`'s surface. **Ruled 2026-09-17:** B, closed by `Q-50` wide —
|
|
1442
|
+
with no gate between geometry and duty the two readings coincide (colregs#72).
|
|
1443
|
+
- **Q-52** — **What does 13(d)'s overtaking history forbid?** *Narrow:* reclassification to
|
|
1445
1444
|
*crossing* only, as the paragraph says, leaving head-on to Rule 14 on the
|
|
1446
1445
|
geometry of the moment. *Broad:* the encounter stays an overtaking and no
|
|
1447
1446
|
other Section II classification attaches. Both preserve the duty; they differ
|
|
@@ -1456,23 +1455,25 @@ nothing is blocked while open.
|
|
|
1456
1455
|
*Suspension:* "may, however" lifts the duty once non-compliance is apparent;
|
|
1457
1456
|
a monitor then flags nothing. *Exception:* the duty stands and a departure is
|
|
1458
1457
|
lawful only as action to avoid collision by her manoeuvre alone; a monitor
|
|
1459
|
-
flags any other alteration. No default (Rule 17 has no entry).
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1458
|
+
flags any other alteration. No default (Rule 17 has no entry). **Ruled
|
|
1459
|
+
2026-09-16:** exception — the 17(a)(i) duty stands and a departure is lawful
|
|
1460
|
+
only as action to avoid collision; a monitor flags any other alteration.
|
|
1461
|
+
Purpose, not source (colregs#72); read with `Q-54`.
|
|
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)
|
|
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
|
-
visibility. No default (nothing is temporal).
|
|
1475
|
-
|
|
1474
|
+
visibility. No default (nothing is temporal). **Deferred indefinitely** (Solace,
|
|
1475
|
+
2026-09-16): no authority either way (colregs#72); scenario contrived. Lean, not
|
|
1476
|
+
ruling: **resetting** — a new encounter after the fog; persisting withdrawn.
|
|
1476
1477
|
- **Q-56** — **The third visibility state: a hole, or closed by the model?**
|
|
1477
1478
|
Not in sight *and* not in or near restricted visibility (clear weather, beyond
|
|
1478
1479
|
visual range, radar contact) is outside Rule 11 and 19(a): Section I only.
|
|
@@ -1494,7 +1495,5 @@ module, expensive after.
|
|
|
1494
1495
|
|
|
1495
1496
|
A third, ruled rather than pencil: **`docs/part-b-invariants.md` stays
|
|
1496
1497
|
hand-written Markdown; no derived JSON registry.** Ruled 2026-09-08. Revisit
|
|
1497
|
-
only if P4.2's TLA+ needs to cite `INV-` ids mechanically
|
|
1498
|
-
|
|
1499
|
-
revisit costs one file's worth of tooling, not a re-derivation of the ids
|
|
1500
|
-
themselves.
|
|
1498
|
+
only if P4.2's TLA+ needs to cite `INV-` ids mechanically; the cost then is one
|
|
1499
|
+
file's worth of tooling, not a re-derivation of the ids.
|
|
@@ -923,6 +923,96 @@
|
|
|
923
923
|
"fact:length_m": 11.6
|
|
924
924
|
},
|
|
925
925
|
"expect": []
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
"name": "constrained by draft, US Inland: Rule 28 is [Reserved], the record is out of vocabulary and selects nothing",
|
|
929
|
+
"jurisdiction": "us/inland",
|
|
930
|
+
"facts": {
|
|
931
|
+
"fact:propulsion": "propulsion:power",
|
|
932
|
+
"fact:activity": "activity:cbd",
|
|
933
|
+
"fact:position": "position:underway",
|
|
934
|
+
"fact:length_m": 200
|
|
935
|
+
},
|
|
936
|
+
"expect": []
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
"name": "6 m outboard, max speed 6 kn, US Inland: 23(d)(ii) has no Inland counterpart, 23(d)(i) is replaced by 23(d), 23(a) is inherited",
|
|
940
|
+
"jurisdiction": "us/inland",
|
|
941
|
+
"facts": {
|
|
942
|
+
"fact:propulsion": "propulsion:power",
|
|
943
|
+
"fact:activity": "activity:none",
|
|
944
|
+
"fact:position": "position:underway",
|
|
945
|
+
"fact:length_m": 6,
|
|
946
|
+
"fact:max_speed_kn": 6
|
|
947
|
+
},
|
|
948
|
+
"expect": [
|
|
949
|
+
"rule:23a_i",
|
|
950
|
+
"rule:23a_ii",
|
|
951
|
+
"rule:23a_iii_iv",
|
|
952
|
+
"rule:23d"
|
|
953
|
+
]
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
"name": "constrained by draft, at anchor, US Inland: Rule 30 is inherited untouched",
|
|
957
|
+
"jurisdiction": "us/inland",
|
|
958
|
+
"facts": {
|
|
959
|
+
"fact:propulsion": "propulsion:power",
|
|
960
|
+
"fact:activity": "activity:cbd",
|
|
961
|
+
"fact:position": "position:anchored",
|
|
962
|
+
"fact:length_m": 200
|
|
963
|
+
},
|
|
964
|
+
"expect": [
|
|
965
|
+
"rule:30a",
|
|
966
|
+
"rule:30c"
|
|
967
|
+
]
|
|
968
|
+
},
|
|
969
|
+
{
|
|
970
|
+
"name": "same yacht motoring, US Inland: 23(d)(i) is replaced by Inland 23(d)",
|
|
971
|
+
"jurisdiction": "us/inland",
|
|
972
|
+
"facts": {
|
|
973
|
+
"fact:propulsion": "propulsion:power",
|
|
974
|
+
"fact:activity": "activity:none",
|
|
975
|
+
"fact:position": "position:underway",
|
|
976
|
+
"fact:length_m": 11.6
|
|
977
|
+
},
|
|
978
|
+
"expect": [
|
|
979
|
+
"rule:23a_i",
|
|
980
|
+
"rule:23a_ii",
|
|
981
|
+
"rule:23a_iii_iv",
|
|
982
|
+
"rule:23d"
|
|
983
|
+
]
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
"name": "pushing ahead, not a composite unit, US Inland: 24(c)(iii) replaces the sternlight with two towing lights",
|
|
987
|
+
"jurisdiction": "us/inland",
|
|
988
|
+
"facts": {
|
|
989
|
+
"fact:propulsion": "propulsion:power",
|
|
990
|
+
"fact:activity": "activity:pushing",
|
|
991
|
+
"fact:position": "position:underway",
|
|
992
|
+
"fact:length_m": 30,
|
|
993
|
+
"fact:composite_unit": false
|
|
994
|
+
},
|
|
995
|
+
"expect": [
|
|
996
|
+
"rule:24c:towing_lights",
|
|
997
|
+
"rule:24c:underway_lights"
|
|
998
|
+
]
|
|
999
|
+
},
|
|
1000
|
+
{
|
|
1001
|
+
"name": "pushing ahead, not a composite unit, at anchor, US Inland (issue #137 review: sidelights/towing lights are underway-gated, masthead only at anchor)",
|
|
1002
|
+
"jurisdiction": "us/inland",
|
|
1003
|
+
"facts": {
|
|
1004
|
+
"fact:propulsion": "propulsion:power",
|
|
1005
|
+
"fact:activity": "activity:pushing",
|
|
1006
|
+
"fact:position": "position:anchored",
|
|
1007
|
+
"fact:length_m": 30,
|
|
1008
|
+
"fact:composite_unit": false
|
|
1009
|
+
},
|
|
1010
|
+
"expect": [
|
|
1011
|
+
"rule:24c:towing_lights",
|
|
1012
|
+
"rule:30a",
|
|
1013
|
+
"rule:30b",
|
|
1014
|
+
"rule:30c"
|
|
1015
|
+
]
|
|
926
1016
|
}
|
|
927
1017
|
]
|
|
928
1018
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "colregs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "COLREGS 72 and its national amalgamations as language-neutral JSON — rule text, light definitions, and applicability predicates — with cross-implementation fixtures",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
+
"colregs": {
|
|
7
|
+
"referenceLanguage": "en"
|
|
8
|
+
},
|
|
6
9
|
"repository": {
|
|
7
10
|
"type": "git",
|
|
8
11
|
"url": "git+https://github.com/mark-brannan/colregs.git"
|
|
@@ -306,6 +306,21 @@
|
|
|
306
306
|
"classification_shape": { "type": "string" }
|
|
307
307
|
}
|
|
308
308
|
},
|
|
309
|
+
"suppressions": {
|
|
310
|
+
"$comment": "Tombstones (REQ-SCOPE-3, ADR 0018): a jurisdiction deliberately lacks an inherited intl entry, as distinct from not-yet-transcribed. With the jurisdiction's own entries these form its RFC 7396 merge patch over intl; suppresses is the key that patch sets to null.",
|
|
311
|
+
"type": "array",
|
|
312
|
+
"items": {
|
|
313
|
+
"type": "object",
|
|
314
|
+
"additionalProperties": false,
|
|
315
|
+
"required": ["jurisdiction", "suppresses", "cite", "why"],
|
|
316
|
+
"properties": {
|
|
317
|
+
"jurisdiction": { "type": "string", "pattern": "^[a-z]+(/[a-z]+)+$" },
|
|
318
|
+
"suppresses": { "$ref": "#/$defs/ruleId" },
|
|
319
|
+
"cite": { "type": "string", "minLength": 1 },
|
|
320
|
+
"why": { "type": "string", "minLength": 1 }
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
},
|
|
309
324
|
"known_omissions": {
|
|
310
325
|
"type": "array",
|
|
311
326
|
"items": {
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"colregs",
|
|
10
10
|
"applied",
|
|
11
11
|
"exempted",
|
|
12
|
-
"excluded",
|
|
13
12
|
"overridden",
|
|
14
13
|
"displays",
|
|
15
14
|
"optional_additions",
|
|
@@ -27,9 +26,6 @@
|
|
|
27
26
|
"exempted": {
|
|
28
27
|
"$ref": "evaluation.schema.json#/$defs/byEntryList"
|
|
29
28
|
},
|
|
30
|
-
"excluded": {
|
|
31
|
-
"$ref": "evaluation.schema.json#/$defs/byEntryList"
|
|
32
|
-
},
|
|
33
29
|
"overridden": {
|
|
34
30
|
"$ref": "evaluation.schema.json#/$defs/byEntryList"
|
|
35
31
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://github.com/mark-brannan/colregs/schema/i18n-catalog.schema.json",
|
|
4
4
|
"title": "data/i18n/*.json",
|
|
5
|
-
"description": "Display catalog for one BCP 47 language: UI strings for
|
|
5
|
+
"description": "Display catalog for one BCP 47 language: UI strings for the closed vocabularies the package emits (lights, modalities, roles, encounters, jurisdictions, closed-list fact values), not legal text -- see docs/adr/0003-language-as-a-dimension.md 'Display catalogs' and REQ-LANG-6.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
8
|
"required": ["language", "provenance", "strings"],
|
|
@@ -25,18 +25,39 @@
|
|
|
25
25
|
},
|
|
26
26
|
"strings": {
|
|
27
27
|
"type": "object",
|
|
28
|
-
"description": "One section per vocabulary. Every section is keyed by the identifier itself, as documented in docs/identifiers.md -- light
|
|
28
|
+
"description": "One section per vocabulary (REQ-LANG-6, REQ-LANG-9's ruling docs/adr/0017). Every section is keyed by the identifier itself, as documented in docs/identifiers.md -- light, modality, role and encounter identifiers carry a type prefix; jurisdiction and closed-list fact values are keyed by their own bare or fact-prefixed form. Values are static strings: no interpolation, no plurals -- the consumer's i18n system owns composition.",
|
|
29
29
|
"additionalProperties": false,
|
|
30
30
|
"properties": {
|
|
31
|
-
"
|
|
31
|
+
"lights": {
|
|
32
32
|
"type": "object",
|
|
33
33
|
"propertyNames": { "pattern": "^light:[a-z_]+$" },
|
|
34
34
|
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
35
35
|
},
|
|
36
|
-
"
|
|
36
|
+
"modalities": {
|
|
37
37
|
"type": "object",
|
|
38
38
|
"propertyNames": { "pattern": "^modality:[a-z]+(-[a-z]+)*$" },
|
|
39
39
|
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
40
|
+
},
|
|
41
|
+
"roles": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"propertyNames": { "pattern": "^role:[a-z]+(-[a-z]+)*$" },
|
|
44
|
+
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
45
|
+
},
|
|
46
|
+
"encounters": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"propertyNames": { "pattern": "^encounter:[a-z]+(-[a-z]+)*$" },
|
|
49
|
+
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
50
|
+
},
|
|
51
|
+
"jurisdictions": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"propertyNames": { "pattern": "^[a-z]+(/[a-z]+)*$" },
|
|
54
|
+
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
55
|
+
},
|
|
56
|
+
"facts": {
|
|
57
|
+
"type": "object",
|
|
58
|
+
"description": "Closed-list fact-value labels only (Tier A): propulsion, activity, position, rule18_class, dynamics, obstruction_side, wind_side. Field names (fact:length_m, geo:tcpa_s, ...) have no closed list behind them and are never catalogued here -- form-label text and unit/number formatting are the consumer's.",
|
|
59
|
+
"propertyNames": { "pattern": "^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$" },
|
|
60
|
+
"additionalProperties": { "$ref": "#/$defs/label" }
|
|
40
61
|
}
|
|
41
62
|
}
|
|
42
63
|
}
|
|
@@ -53,10 +53,9 @@
|
|
|
53
53
|
"^light:[a-z_]+$": {
|
|
54
54
|
"type": "object",
|
|
55
55
|
"additionalProperties": false,
|
|
56
|
-
"required": ["
|
|
56
|
+
"required": ["term", "cite", "character", "rule21"],
|
|
57
57
|
"properties": {
|
|
58
|
-
"
|
|
59
|
-
"colregs_term": { "type": "string", "minLength": 1 },
|
|
58
|
+
"term": { "type": "string", "minLength": 1 },
|
|
60
59
|
"cite": { "type": "string", "minLength": 1 },
|
|
61
60
|
"color": { "type": ["string", "null"] },
|
|
62
61
|
"color_note": { "type": "string" },
|
package/schema/rules.schema.json
CHANGED
|
@@ -12,6 +12,54 @@
|
|
|
12
12
|
"note": {
|
|
13
13
|
"type": "string"
|
|
14
14
|
},
|
|
15
|
+
"paragraphs": {
|
|
16
|
+
"$ref": "#/$defs/paragraphs"
|
|
17
|
+
},
|
|
18
|
+
"deltas": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"description": "Per-jurisdiction skeleton deltas over `paragraphs` (ADR 0020): own paragraphs by path, suppressed paths, everything else inherited.",
|
|
22
|
+
"patternProperties": {
|
|
23
|
+
"^[a-z]+(/[a-z]+)+$": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"required": [
|
|
27
|
+
"paragraphs",
|
|
28
|
+
"suppressions"
|
|
29
|
+
],
|
|
30
|
+
"properties": {
|
|
31
|
+
"note": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"paragraphs": {
|
|
35
|
+
"$ref": "#/$defs/paragraphs"
|
|
36
|
+
},
|
|
37
|
+
"suppressions": {
|
|
38
|
+
"type": "array",
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"required": [
|
|
43
|
+
"path",
|
|
44
|
+
"why"
|
|
45
|
+
],
|
|
46
|
+
"properties": {
|
|
47
|
+
"path": {
|
|
48
|
+
"$ref": "evaluation.schema.json#/$defs/paragraphCite"
|
|
49
|
+
},
|
|
50
|
+
"why": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"minLength": 1
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"$defs": {
|
|
15
63
|
"paragraphs": {
|
|
16
64
|
"type": "object",
|
|
17
65
|
"additionalProperties": false,
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "intl@2016.fi.finlex",
|
|
3
|
-
"edition": "intl@2016",
|
|
4
|
-
"edition_status": "claimed",
|
|
5
|
-
"language": "fi",
|
|
6
|
-
"source_id": "finlex",
|
|
7
|
-
"tier": "national",
|
|
8
|
-
"normalization": "NFC",
|
|
9
|
-
"source": {
|
|
10
|
-
"publisher": "Finlex (Oikeusministeriö), Suomen säädöskokoelman sopimussarja",
|
|
11
|
-
"title": "Asetus kansainvälisistä säännöistä yhteentörmäämisen ehkäisemiseksi merellä vuonna 1972 tehdyn yleissopimuksen voimaansaattamisesta, SopS 30/1977",
|
|
12
|
-
"url": "https://www.finlex.fi/fi/sopimukset/sopsteksti/1977/19770030",
|
|
13
|
-
"retrieved": "2026-09-12"
|
|
14
|
-
},
|
|
15
|
-
"rights": {
|
|
16
|
-
"source_text": "Tekijänoikeuslaki 404/1961 §9: no copyright in treaties and their official translations",
|
|
17
|
-
"redistribution_basis": "Finlex FAQ: published materials carry no usage restriction; open data CC BY 4.0",
|
|
18
|
-
"package_licence": "Apache-2.0"
|
|
19
|
-
},
|
|
20
|
-
"note": "Stub: identity and provenance only; the Finnish text is not transcribed yet. GATE-2 is adopted in docs/gates.json, settled by ADR 0013, so nothing structural blocks it.",
|
|
21
|
-
"paragraphs": {}
|
|
22
|
-
}
|