Skip to content
mark-brannanPublic

About

COLREGS 72 as language-neutral JSON: rule text, light definitions, and applicability predicates, with national amalgamations as a first-class dimension. Data only, with cross-implementation fixtures.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

colregs

Two vessels are closing. What must they do? Who gives way? What must they display?

The COLREGS, the International Regulations for Preventing Collisions at Sea, answer all three. This project transforms the colregs so that a machine can evaluate and reason about them deterministically: the whole of the rules as structured data, so the same situation always yields the same result, and every result can be traced back to the rule that produced it. Going further, the engine and the rules are then checked with formal methods, which means mathematically proving the rule set is consistent and complete rather than just testing it a bunch and hoping it all works out.

This package is the data: the rules as language-neutral JSON, the USCG's own diagrams, and enough geometry to draw the lights yourself. Jurisdictions are deltas on the international base, so national amalgamations hang off it rather than forking it.

Related packages:

See a live demo of searoom and the colregs data/engine.

Status: pre-release. Not complete, and not fit for navigation. Navigate by the published rules.

data/rules.json          the skeleton: paragraph paths, rule numbers, jurisdictions -- no text; non-intl jurisdictions as deltas
data/editions.json       which edition of which instrument each jurisdiction is on
data/text/               rule text, one corpus per edition x language x source
data/corpora.json        index of those corpora and how much each covers
data/lights.json         the six Rule 21 lights: colour, arc, Rule 22 range
data/shapes.json         the Annex I day shapes: dimensions and a reference SVG each
data/facts.json          the fact record, and how to decode SignalK navigation.state
data/applicability.json  predicate -> lights or day shapes, each entry also carrying modality, citation, jurisdiction
data/geometry.json       Annex I: heights, spacings, colour, intensity
data/images.json         every image, its source, and what it illustrates
images/                  38 USCG diagrams + 5 arc GIFs
fixtures/                fact records and the entries that apply to them

What this package does not do

It has no runtime and no dependencies. It does not infer anything: it is a pure function of the fact record, and deciding that a vessel is fishing, or aground, or making way is the caller's job. Nothing here reads a sensor.

dist/xml carries the same data as XML (W3C XPath 3.1 fn:json-to-xml), with json.xsd (ADR 0014).

It does not select a single display. Where the rules permit a choice, every lawful option comes back and none is picked. Selection belongs to the consumer.

Coverage

Every rule with a machine-checkable consequence: Part B conduct, Part C lights and shapes, Part D sound and light signals, and Annex I geometry. intl is the base; us/inland, ca/inland and eu/cevni are deltas on it. Today the entries hold Part C and Part D for intl. Part D's signals are entries like any other, keyed on the same paragraph paths: Rule 35 reads the vessel's own state, and Rule 34 reads what she is doing — an act the helm states, never a rate of turn this package infers. data/sounds.json holds the elements a signal is built from, as lights.json holds the lights. For Part C, lights and day shapes alike: a record that states fact:time: time:day selects the shapes; one that states no time selects the lights, night being assumed rather than gated. By day the lights are not silenced — Rule 20(c) makes them permitted in good visibility and leaves them required in restricted (ADR 0021). When every light in a display is modality:may, one lawful option shows none, and it comes back with empty entries: by day in good visibility Rule 20(c) requires no light (23(d)(i), 25(b), 24(a)(i)). docs/requirements.md is the numbered contract for all of it. One case the Convention cannot state, a vessel made fast to a mooring buoy, lives only under us/inland (ADR 0008); two the Inland Rules deliberately lack, Rule 28 and 23(d)(ii), are tombstoned there (ADR 0018); one it spells differently, 23(d), replaces the international entry, and one it states differently, the towing lights that replace 24(c)'s sternlight, is tombstoned and replaced under its own id. Its Part C skeleton is a delta of the same kind: the paths whose text differs, the paths only it has, the three it lacks (ADR 0020). That is the whole of us/inland today: seven records and a skeleton, not yet a model of the Inland Rules; its text and the entries for its own paths are the next work.

The layers

Rule text. Verbatim, keyed by paragraph path, like 27(a)(i), because the paragraph is the unit you actually cite. The paths live in a language-neutral skeleton; the words live in corpora, one per edition, language and source, each with its own provenance and legal tier. A mixed rendering across corpora is never a single authoritative edition. Where a licence bars republishing a jurisdiction's words, the paragraph is still modelled and its text withheld rather than paraphrased — evaluation never reads the text.

Light definitions. Rule 21's lights with colour, arc as a bearing range, and Rule 22 range by length band. Bearings run clockwise from right ahead; an arc whose from_deg exceeds its to_deg wraps through the bow. The day shapes are the same kind of record: Annex I's dimensions and an SVG drawn at them, 1 unit = 1 m, so a renderer scales rather than redraws.

Facts. Three orthogonal axes (fact:propulsion, fact:activity, fact:position), a fact:making_way modifier, and scalars such as fact:length_m. There is deliberately no vessel-class field: under COLREGS what a vessel is follows from what it is doing. A decode table maps SignalK's navigation.state onto the axes and names what the flattening loses.

Applicability entries. Each is a predicate over facts, a set of lights or day shapes or references to other entries, a modality, a citation, and a jurisdiction. Every entry has an id (rule:25b, rule:27a_iii) a consumer can point at.

Identifiers. Paragraph paths carry no prefix, because the path is the citation. Every other id names its namespace: rule:30a, light:masthead, fact:activity, activity:nuc, rel:in_lieu_of. Every identifier is immutable from 1.0.0; before then it may be renamed or discarded outright, and the deprecation registry is absent. See docs/identifiers.md.

Design

Requirements-first: sessions work against the numbered requirements in docs/requirements.md and decisions live in docs/adr/ rather than being argued again; the amendment and national-adoption history is in docs/timeline.md. Four ideas carry most of it.

The paragraph is the unit. Rule text, citations and composition all key on the paragraph path. Citation unit and composition unit turn out to be the same thing.

Jurisdiction is a dimension, not a fork. Every record carries a jurisdiction: intl, or <country-or-body>/<waters> as a delta on it. Entries a jurisdiction doesn't override are inherited, not restated. The delta is an RFC 7396 merge patch over intl keyed by entry id: the jurisdiction's own entries are its keys, its suppressions are the keys set to null, and silence inherits (ADR 0018). Any conformant merge-patch library reproduces the resolved rule set.

Predicates, not enumerations. Gates are fact:length_m < 7, never a pre-built list of configurations. Enumerated tables are where prior art silently loses rules; a predicate cannot omit a case it was never asked about.

Alternatives are first-class. A tricolor in lieu of separate sidelights, a torch in lieu of either. The data carries every lawful option with its modality and gate, and picks none of them.

Predicate semantics

An entry applies when every constraint in its when is satisfied. An absent fact never satisfies a constraint, including not: a duty is never laid on a vessel because a consumer left a field out.

form where means
{"gte": n} … {"lt": n} a fact's constraint numeric comparison
["a", "b"] a fact's constraint membership
"a" / true / 12 a fact's constraint equality
{"not": C} a fact's constraint the fact is present and does not satisfy C
{"any_of": [C, …]} a fact's constraint the fact satisfies at least one C
"any_of": [W, …] a key of a when at least one sub-predicate W holds

Entries compose: several apply to one fact record, and Rule 26 adds to Rule 23 rather than replacing it. A condition on whether a paragraph applies at all goes in the predicate; a condition on which of two applicable paragraphs prevails is a relation.

relation meaning
rel:includes import the referenced entry's lights and shapes, their modality and its scalar gates — never its axes (ADR 0019)
rel:conditional_includes import lights and shapes when the stated when holds; one_of is a set of legal alternatives, exactly one per display, or none under a may carrier
rel:in_lieu_of this entry's lights or shapes replace the referenced entries'; two entries replacing overlapping sets are alternatives to each other
rel:excludes must not be shown together: a pick-one between alternatives, never one obligation vetoing another; a constraint on one display, never a removal
rel:exempts the referenced requirement does not apply (30(e)); reaches an entry in force, never an import
rel:overrides this paragraph's requirement prevails over the referenced one's when both apply (Rule 18; Rule 26(a) over Rule 30's anchor lights); reaches an entry in force, never an import

Modality is modality:shall, modality:may, modality:shall-if-practicable, modality:shall-not, modality:shall-not-impede, or modality:conditional with a modality_by table when it turns on a fact. A modality_shifts record is the other half: a paragraph that changes the modality of the signals other entries prescribe rather than prescribing signals of its own. It carries a predicate, the signal kind it reaches and a map from modality to modality, and applies after the entry's own modality has resolved — Rule 20(c) is the one in the data, making a light modality:may by day in good visibility and leaving the day shapes alone.

Most entries read one vessel and produce lights. The Part B entries read two, a situation rather than a fact record, and produce an effect: which section governs, which vessel gives way, whether the encounter is situation:head-on, situation:crossing or situation:overtaking. They address each vessel through a subject segment (self:fact:activity, other:fact:propulsion, pair:geo:in_sight); a key with no subject means self:. The encounter sectors partition relative bearing, so no crossing sector is enumerated and none can drift. docs/identifiers.md has the vocabulary, docs/part-b-invariants.md the invariants, and fixtures/situation-fixtures.json is the contract.

Verifying

npm test

Every fixture reproduces exactly; every citation, cross-reference, light and geometry reference resolves; every image is on disk with its SHA-256 recorded; every fact a predicate reads is declared. A drift test cross-checks fact record to lights and lights back to entries, and fails on any collision the data doesn't declare through a relation. Every numeric gate has fixtures either side of its threshold, and every entry is exercised by at least one fixture and absent from another. The encounter sweeps assert that exactly one encounter applies at every bearing, and that no steady-bearing geometry makes both vessels give-way.

fixtures/applicability-fixtures.json and fixtures/situation-fixtures.json are the cross-implementation contract: an implementation in any language should reproduce those exactly. data/operations.json names the verbs an engine implements and binds each to its input schema, its result schema and the fixture file that exercises it (ADR 0014). evaluate(circumstances) is entered as a straw man; its schemas may change.

Provenance and licence

Rule text, the NRHB_* diagrams and the five *arc.gif files are USCG publications, public domain; see PROVENANCE.md. The compilation is Apache-2.0.

Not authoritative, not endorsed by the Coast Guard. Navigate by the published rules. The ca/inland delta carries the same condition its licence does: it must not be represented as an official version.

About

COLREGS 72 as language-neutral JSON: rule text, light definitions, and applicability predicates, with national amalgamations as a first-class dimension. Data only, with cross-implementation fixtures.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages