colregs 0.1.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +194 -26
  2. package/PROVENANCE.md +45 -12
  3. package/README.md +222 -23
  4. package/data/applicability.json +1252 -190
  5. package/data/deprecated-identifiers.json +7 -0
  6. package/data/facts.json +556 -113
  7. package/data/geometry.json +33 -33
  8. package/data/images.json +51 -25
  9. package/data/lights.json +35 -35
  10. package/data/rules.json +787 -3
  11. package/docs/adr/0001-name-and-jurisdiction-model.md +119 -1
  12. package/docs/adr/0003-language-as-a-dimension.md +220 -0
  13. package/docs/adr/0004-licence-layering.md +78 -0
  14. package/docs/adr/0005-rule-categories-and-the-situation-record.md +323 -0
  15. package/docs/adr/0006-json-schema-and-identifier-diff.md +95 -0
  16. package/docs/adr/0007-rule26-overrides-and-aground.md +68 -0
  17. package/docs/adr/0008-mooring-buoy-modifier.md +87 -0
  18. package/docs/budgets.json +162 -0
  19. package/docs/conventions.md +27 -0
  20. package/docs/gates.json +84 -0
  21. package/docs/identifiers.md +435 -0
  22. package/docs/part-b-invariants.md +922 -0
  23. package/docs/requirements.md +1251 -23
  24. package/docs/verification/2026-08-30-q6-q8.md +278 -0
  25. package/docs/verification/2026-09-05-rule27f-rule28-anchor-scenarios.md +330 -0
  26. package/fixtures/applicability-fixtures.json +361 -227
  27. package/fixtures/situation-fixtures.json +3673 -0
  28. package/package.json +16 -4
  29. package/schema/applicability-fixtures.schema.json +49 -0
  30. package/schema/applicability.schema.json +401 -0
  31. package/schema/deprecated-identifiers.schema.json +29 -0
  32. package/schema/facts.schema.json +793 -0
  33. package/schema/geometry.schema.json +239 -0
  34. package/schema/images.schema.json +53 -0
  35. package/schema/lights.schema.json +131 -0
  36. package/schema/rules.schema.json +50 -0
  37. package/schema/situation-fixtures.schema.json +325 -0
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "colregs",
3
- "version": "0.1.1",
3
+ "version": "0.2.2",
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
- "license": "MIT",
5
+ "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/mark-brannan/colregs.git"
@@ -17,6 +17,18 @@
17
17
  "collision-regulations",
18
18
  "navigation-lights"
19
19
  ],
20
- "scripts": { "test": "node --test test/*.mjs" },
21
- "files": ["data", "images", "fixtures", "docs", "PROVENANCE.md"]
20
+ "scripts": {
21
+ "test": "node --test test/*.mjs"
22
+ },
23
+ "files": [
24
+ "data",
25
+ "images",
26
+ "fixtures",
27
+ "docs",
28
+ "schema",
29
+ "PROVENANCE.md"
30
+ ],
31
+ "devDependencies": {
32
+ "ajv": "^8.20.0"
33
+ }
22
34
  }
@@ -0,0 +1,49 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/mark-brannan/colregs/schema/applicability-fixtures.schema.json",
4
+ "title": "fixtures/applicability-fixtures.json",
5
+ "description": "The cross-implementation contract: fact record -> expected entry ids. Structure only -- see docs/adr/0006-json-schema-and-identifier-diff.md.",
6
+ "$comment": "The top-level `jurisdiction` is the corpus default; a case may name its own, and is then evaluated against `intl` plus that jurisdiction's deltas (REQ-SCOPE-3).",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": ["jurisdiction", "cases"],
10
+ "$defs": {
11
+ "factValue": {
12
+ "oneOf": [
13
+ { "type": "string", "pattern": "^[a-z][a-z0-9_]*:[a-z0-9_]+$" },
14
+ { "type": "number" },
15
+ { "type": "boolean" }
16
+ ]
17
+ },
18
+ "entryId": { "type": "string", "pattern": "^[0-9]+[a-z0-9]*(-[a-z0-9]+)?$" }
19
+ },
20
+ "properties": {
21
+ "note": { "type": "string" },
22
+ "jurisdiction": { "type": "string", "pattern": "^[a-z]+(/[a-z]+)*$" },
23
+ "cases": {
24
+ "type": "array",
25
+ "minItems": 1,
26
+ "items": {
27
+ "type": "object",
28
+ "additionalProperties": false,
29
+ "required": ["name", "facts", "expect"],
30
+ "properties": {
31
+ "name": { "type": "string", "minLength": 1 },
32
+ "jurisdiction": { "type": "string", "pattern": "^[a-z]+(/[a-z]+)*$" },
33
+ "facts": {
34
+ "type": "object",
35
+ "minProperties": 1,
36
+ "additionalProperties": false,
37
+ "patternProperties": {
38
+ "^fact:[a-z0-9_]+$": { "$ref": "#/$defs/factValue" }
39
+ }
40
+ },
41
+ "expect": {
42
+ "type": "array",
43
+ "items": { "$ref": "#/$defs/entryId" }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,401 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/mark-brannan/colregs/schema/applicability.schema.json",
4
+ "title": "data/applicability.json",
5
+ "description": "predicate -> lights, per entry, with modality, citation and jurisdiction. Structure only -- see docs/adr/0006-json-schema-and-identifier-diff.md.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["entries"],
9
+ "$defs": {
10
+ "entryId": { "type": "string", "pattern": "^[0-9]+[a-z0-9]*(-[a-z0-9]+)*$" },
11
+ "modality": {
12
+ "type": "string",
13
+ "enum": ["shall", "may", "shall-if-practicable", "conditional", "exempt", "shall-not", "shall-not-impede"]
14
+ },
15
+ "predicateValue": {
16
+ "oneOf": [
17
+ {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "minProperties": 1,
21
+ "properties": {
22
+ "gte": { "type": "number" },
23
+ "gt": { "type": "number" },
24
+ "lte": { "type": "number" },
25
+ "lt": { "type": "number" }
26
+ }
27
+ },
28
+ { "type": "string", "pattern": "^[a-z][a-z0-9_]*:[a-z0-9_]+$" },
29
+ { "type": "boolean" },
30
+ {
31
+ "type": "array",
32
+ "minItems": 1,
33
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9_]*:[a-z0-9_]+$" }
34
+ },
35
+ {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "required": ["not"],
39
+ "properties": {
40
+ "not": { "$ref": "#/$defs/predicateValue" }
41
+ }
42
+ },
43
+ {
44
+ "type": "object",
45
+ "additionalProperties": false,
46
+ "required": ["any_of"],
47
+ "properties": {
48
+ "any_of": {
49
+ "type": "array",
50
+ "minItems": 1,
51
+ "items": { "$ref": "#/$defs/predicateValue" }
52
+ }
53
+ }
54
+ }
55
+ ]
56
+ },
57
+ "when": {
58
+ "type": "object",
59
+ "minProperties": 1,
60
+ "additionalProperties": false,
61
+ "properties": {
62
+ "any_of": {
63
+ "type": "array",
64
+ "minItems": 1,
65
+ "items": { "$ref": "#/$defs/when" }
66
+ }
67
+ },
68
+ "patternProperties": {
69
+ "^fact:[a-z0-9_]+$": { "$ref": "#/$defs/predicateValue" }
70
+ }
71
+ },
72
+ "situationWhen": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "any_of": {
77
+ "type": "array",
78
+ "minItems": 1,
79
+ "items": { "$ref": "#/$defs/situationWhen" }
80
+ }
81
+ },
82
+ "patternProperties": {
83
+ "^fact:[a-z0-9_]+$": { "$ref": "#/$defs/predicateValue" },
84
+ "^(own|other):(fact|kin|geo|hist):[a-z0-9_]+$": { "$ref": "#/$defs/predicateValue" },
85
+ "^pair:(geo|env):[a-z0-9_]+$": { "$ref": "#/$defs/predicateValue" }
86
+ }
87
+ },
88
+ "effectRole": {
89
+ "type": "string",
90
+ "enum": ["give-way", "stand-on", "shall-not-impede", "keep-clear", "none"]
91
+ },
92
+ "effect": {
93
+ "oneOf": [
94
+ {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "required": ["part", "section", "applies_rules"],
98
+ "properties": {
99
+ "part": { "type": "string" },
100
+ "section": { "type": "string" },
101
+ "applies_rules": {
102
+ "type": "array",
103
+ "minItems": 1,
104
+ "items": { "type": "string" }
105
+ }
106
+ }
107
+ },
108
+ {
109
+ "type": "object",
110
+ "additionalProperties": false,
111
+ "required": ["own", "other"],
112
+ "properties": {
113
+ "own": { "$ref": "#/$defs/effectRole" },
114
+ "other": { "$ref": "#/$defs/effectRole" }
115
+ }
116
+ },
117
+ {
118
+ "type": "object",
119
+ "additionalProperties": false,
120
+ "required": ["encounter"],
121
+ "properties": {
122
+ "encounter": {
123
+ "type": "string",
124
+ "enum": ["head-on", "crossing", "overtaking", "none"]
125
+ }
126
+ }
127
+ },
128
+ {
129
+ "type": "object",
130
+ "additionalProperties": false,
131
+ "required": ["risk_of_collision"],
132
+ "properties": {
133
+ "risk_of_collision": { "const": true }
134
+ }
135
+ }
136
+ ]
137
+ },
138
+ "lightRef": {
139
+ "type": "object",
140
+ "additionalProperties": false,
141
+ "required": ["light"],
142
+ "properties": {
143
+ "light": { "type": "string", "pattern": "^light:[a-z_]+$" },
144
+ "position": { "type": "string" },
145
+ "count": { "type": "integer", "minimum": 1 },
146
+ "color": { "type": "string" },
147
+ "character": { "type": "string" },
148
+ "intensity": { "type": "string" },
149
+ "arrangement": { "type": "string", "enum": ["vertical"] },
150
+ "combined": { "type": "boolean" },
151
+ "note": { "type": "string" },
152
+ "modality": { "$ref": "#/$defs/modality" }
153
+ }
154
+ },
155
+ "modalityBy": {
156
+ "type": "array",
157
+ "minItems": 1,
158
+ "items": {
159
+ "type": "object",
160
+ "additionalProperties": false,
161
+ "required": ["when", "modality"],
162
+ "properties": {
163
+ "when": { "$ref": "#/$defs/when" },
164
+ "modality": { "$ref": "#/$defs/modality" }
165
+ }
166
+ }
167
+ },
168
+ "conditionalInclude": {
169
+ "type": "object",
170
+ "additionalProperties": false,
171
+ "minProperties": 1,
172
+ "properties": {
173
+ "when": { "$ref": "#/$defs/when" },
174
+ "one_of": {
175
+ "type": "array",
176
+ "minItems": 2,
177
+ "items": { "$ref": "#/$defs/entryId" }
178
+ },
179
+ "rel:includes": {
180
+ "type": "array",
181
+ "minItems": 1,
182
+ "items": { "$ref": "#/$defs/entryId" }
183
+ },
184
+ "cite": { "type": "string", "minLength": 1 }
185
+ }
186
+ },
187
+ "entryIdList": {
188
+ "type": "array",
189
+ "minItems": 1,
190
+ "items": { "$ref": "#/$defs/entryId" }
191
+ }
192
+ },
193
+ "properties": {
194
+ "conditions": { "type": "string" },
195
+ "relations": {
196
+ "type": "object",
197
+ "additionalProperties": false,
198
+ "required": [
199
+ "rel:includes",
200
+ "rel:conditional_includes",
201
+ "rel:in_lieu_of",
202
+ "rel:excludes",
203
+ "rel:exempts",
204
+ "rel:overrides"
205
+ ],
206
+ "properties": {
207
+ "rel:includes": { "type": "string" },
208
+ "rel:conditional_includes": { "type": "string" },
209
+ "rel:in_lieu_of": { "type": "string" },
210
+ "rel:excludes": { "type": "string" },
211
+ "rel:exempts": { "type": "string" },
212
+ "rel:overrides": { "type": "string" }
213
+ }
214
+ },
215
+ "modalities": {
216
+ "type": "object",
217
+ "additionalProperties": false,
218
+ "required": [
219
+ "shall",
220
+ "may",
221
+ "shall-if-practicable",
222
+ "conditional",
223
+ "exempt",
224
+ "shall-not",
225
+ "shall-not-impede"
226
+ ],
227
+ "properties": {
228
+ "shall": { "type": "string" },
229
+ "may": { "type": "string" },
230
+ "shall-if-practicable": { "type": "string" },
231
+ "conditional": { "type": "string" },
232
+ "exempt": { "type": "string" },
233
+ "shall-not": { "type": "string" },
234
+ "shall-not-impede": { "type": "string" }
235
+ }
236
+ },
237
+ "categories": {
238
+ "type": "object",
239
+ "additionalProperties": false,
240
+ "required": [
241
+ "definition",
242
+ "standard",
243
+ "scope",
244
+ "display",
245
+ "classification",
246
+ "precedence",
247
+ "conduct",
248
+ "care",
249
+ "meta"
250
+ ],
251
+ "properties": {
252
+ "definition": { "type": "string" },
253
+ "standard": { "type": "string" },
254
+ "scope": { "type": "string" },
255
+ "display": { "type": "string" },
256
+ "classification": { "type": "string" },
257
+ "precedence": { "type": "string" },
258
+ "conduct": { "type": "string" },
259
+ "care": { "type": "string" },
260
+ "meta": { "type": "string" }
261
+ }
262
+ },
263
+ "effects": {
264
+ "type": "object",
265
+ "additionalProperties": false,
266
+ "required": ["roles"],
267
+ "properties": {
268
+ "note": { "type": "string" },
269
+ "roles": {
270
+ "type": "object",
271
+ "additionalProperties": false,
272
+ "required": ["give-way", "stand-on", "shall-not-impede", "keep-clear", "none"],
273
+ "properties": {
274
+ "give-way": { "type": "string" },
275
+ "stand-on": { "type": "string" },
276
+ "shall-not-impede": { "type": "string" },
277
+ "keep-clear": { "type": "string" },
278
+ "none": { "type": "string" }
279
+ }
280
+ },
281
+ "encounters": {
282
+ "type": "object",
283
+ "additionalProperties": false,
284
+ "required": ["head-on", "crossing", "overtaking", "none"],
285
+ "properties": {
286
+ "head-on": { "type": "string" },
287
+ "crossing": { "type": "string" },
288
+ "overtaking": { "type": "string" },
289
+ "none": { "type": "string" }
290
+ }
291
+ },
292
+ "classification_shape": { "type": "string" }
293
+ }
294
+ },
295
+ "known_omissions": {
296
+ "type": "array",
297
+ "items": {
298
+ "type": "object",
299
+ "additionalProperties": false,
300
+ "required": ["cite", "what", "why"],
301
+ "properties": {
302
+ "cite": { "type": "string", "minLength": 1 },
303
+ "what": { "type": "string", "minLength": 1 },
304
+ "why": { "type": "string", "minLength": 1 }
305
+ }
306
+ }
307
+ },
308
+ "represented_paragraphs": {
309
+ "type": "array",
310
+ "items": {
311
+ "type": "object",
312
+ "additionalProperties": false,
313
+ "required": ["id", "jurisdiction", "cite", "category", "note"],
314
+ "properties": {
315
+ "id": { "$ref": "#/$defs/entryId" },
316
+ "jurisdiction": { "type": "string", "pattern": "^[a-z]+(/[a-z]+)*$" },
317
+ "cite": { "type": "string", "minLength": 1 },
318
+ "category": { "type": "string", "enum": ["care", "meta"] },
319
+ "note": { "type": "string", "minLength": 1 }
320
+ }
321
+ }
322
+ },
323
+ "retired_entry_ids": {
324
+ "type": "object",
325
+ "additionalProperties": false,
326
+ "required": ["ids"],
327
+ "properties": {
328
+ "note": { "type": "string" },
329
+ "ids": {
330
+ "type": "object",
331
+ "propertyNames": { "$ref": "#/$defs/entryId" },
332
+ "additionalProperties": { "type": "string", "minLength": 1 }
333
+ }
334
+ }
335
+ },
336
+ "entries": {
337
+ "type": "array",
338
+ "minItems": 1,
339
+ "items": {
340
+ "type": "object",
341
+ "additionalProperties": false,
342
+ "required": ["id", "jurisdiction", "cite", "when", "modality"],
343
+ "properties": {
344
+ "id": { "$ref": "#/$defs/entryId" },
345
+ "jurisdiction": { "type": "string", "pattern": "^[a-z]+(/[a-z]+)*$" },
346
+ "cite": { "type": "string", "minLength": 1 },
347
+ "category": {
348
+ "type": "string",
349
+ "enum": ["definition", "standard", "scope", "display", "classification", "precedence", "conduct", "care", "meta"]
350
+ },
351
+ "subjects": { "type": "integer", "const": 2 },
352
+ "when": { "$ref": "#/$defs/situationWhen" },
353
+ "lights": {
354
+ "type": "array",
355
+ "items": { "$ref": "#/$defs/lightRef" }
356
+ },
357
+ "effect": { "$ref": "#/$defs/effect" },
358
+ "modality": { "$ref": "#/$defs/modality" },
359
+ "modality_by": { "$ref": "#/$defs/modalityBy" },
360
+ "images": {
361
+ "type": "array",
362
+ "minItems": 1,
363
+ "items": { "type": "string", "minLength": 1 }
364
+ },
365
+ "notes": { "type": "string" },
366
+ "note": { "type": "string" },
367
+ "gap": { "type": "string", "minLength": 1 },
368
+ "no_gate_note": { "type": "string", "minLength": 1 },
369
+ "rel:includes": { "$ref": "#/$defs/entryIdList" },
370
+ "rel:conditional_includes": {
371
+ "type": "array",
372
+ "minItems": 1,
373
+ "items": { "$ref": "#/$defs/conditionalInclude" }
374
+ },
375
+ "rel:in_lieu_of": { "$ref": "#/$defs/entryIdList" },
376
+ "rel:excludes": { "$ref": "#/$defs/entryIdList" },
377
+ "rel:exempts": { "$ref": "#/$defs/entryIdList" },
378
+ "rel:overrides": { "$ref": "#/$defs/entryIdList" }
379
+ },
380
+ "allOf": [
381
+ {
382
+ "if": {
383
+ "properties": { "subjects": { "const": 2 } },
384
+ "required": ["subjects"]
385
+ },
386
+ "then": {
387
+ "properties": { "category": {}, "effect": {} },
388
+ "required": ["category", "effect"],
389
+ "not": { "properties": { "lights": {} }, "required": ["lights"] }
390
+ },
391
+ "else": {
392
+ "properties": { "lights": {} },
393
+ "required": ["lights"],
394
+ "not": { "properties": { "effect": {} }, "required": ["effect"] }
395
+ }
396
+ }
397
+ ]
398
+ }
399
+ }
400
+ }
401
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/mark-brannan/colregs/schema/deprecated-identifiers.schema.json",
4
+ "title": "data/deprecated-identifiers.json",
5
+ "description": "REQ-MODEL-11's deprecation registry: every retired identifier, what it denoted, the version that deprecated it, and its replacement where one exists. Keys are the same prefixed forms the identifier diff compares (test/data.test.mjs's extractIdentifiers) -- e.g. 'entry:25d2', 'paragraph:27(a)(i)', 'light:masthead', 'fact-key:activity', 'fact-value:activity:nuc', 'rel:includes'. Structure only -- see docs/adr/0006-json-schema-and-identifier-diff.md.",
6
+ "type": "object",
7
+ "additionalProperties": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "required": ["denoted", "deprecated_in"],
11
+ "properties": {
12
+ "denoted": {
13
+ "type": "string",
14
+ "minLength": 1,
15
+ "description": "What the identifier meant, so a consumer pinned to an old version can resolve a stale reference without the identifier itself."
16
+ },
17
+ "deprecated_in": {
18
+ "type": "string",
19
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
20
+ "description": "The released version that deprecated this identifier (REQ-MODEL-10)."
21
+ },
22
+ "replacement": {
23
+ "type": ["string", "null"],
24
+ "minLength": 1,
25
+ "description": "The identifier that replaces this one, in the same prefixed form, or null where nothing replaces it."
26
+ }
27
+ }
28
+ }
29
+ }