@mailwoman/geographic-model 0.0.0
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 +155 -0
- package/artifact.ts +198 -0
- package/compile.ts +350 -0
- package/data/geographic-model.json +172 -0
- package/data/model/concepts.json +114 -0
- package/data/model/mappings.json +18 -0
- package/data/model/model.json +3 -0
- package/data/model/relations.json +14 -0
- package/index.ts +51 -0
- package/load.ts +396 -0
- package/lookup.ts +129 -0
- package/out/artifact.d.ts +106 -0
- package/out/artifact.d.ts.map +1 -0
- package/out/artifact.js +135 -0
- package/out/artifact.js.map +1 -0
- package/out/compile.d.ts +84 -0
- package/out/compile.d.ts.map +1 -0
- package/out/compile.js +259 -0
- package/out/compile.js.map +1 -0
- package/out/index.d.ts +51 -0
- package/out/index.d.ts.map +1 -0
- package/out/index.js +51 -0
- package/out/index.js.map +1 -0
- package/out/load.d.ts +122 -0
- package/out/load.d.ts.map +1 -0
- package/out/load.js +269 -0
- package/out/load.js.map +1 -0
- package/out/lookup.d.ts +64 -0
- package/out/lookup.d.ts.map +1 -0
- package/out/lookup.js +68 -0
- package/out/lookup.js.map +1 -0
- package/out/schema.d.ts +366 -0
- package/out/schema.d.ts.map +1 -0
- package/out/schema.js +166 -0
- package/out/schema.js.map +1 -0
- package/out/scripts/build-artifact.d.ts +51 -0
- package/out/scripts/build-artifact.d.ts.map +1 -0
- package/out/scripts/build-artifact.js +78 -0
- package/out/scripts/build-artifact.js.map +1 -0
- package/out/validate.d.ts +67 -0
- package/out/validate.d.ts.map +1 -0
- package/out/validate.js +465 -0
- package/out/validate.js.map +1 -0
- package/out/validation-issues.d.ts +84 -0
- package/out/validation-issues.d.ts.map +1 -0
- package/out/validation-issues.js +190 -0
- package/out/validation-issues.js.map +1 -0
- package/package.json +120 -0
- package/schema.ts +399 -0
- package/validate.ts +845 -0
- package/validation-issues.ts +305 -0
package/out/artifact.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* The compiled runtime artifact: its shape, its canonical bytes, and the reader that turns those
|
|
7
|
+
* bytes back into a typed value.
|
|
8
|
+
*
|
|
9
|
+
* A runtime consumer reads THIS and never the authored records. That is the whole point of the
|
|
10
|
+
* artifact, and it is why the shape carries every table plus the materialized `isA` closure: a
|
|
11
|
+
* consumer that had to walk `concepts[].isA` to answer a question about one concept would be doing
|
|
12
|
+
* query-time traversal, which the boundary record excludes.
|
|
13
|
+
*
|
|
14
|
+
* Two determinism rules define the bytes, and both are stated so a reader can check them:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Every object's keys are emitted in code-point order**, at every depth. A rule that
|
|
17
|
+
* canonicalizes by itself beats a hand-kept field order, which drifts the first time the schema
|
|
18
|
+
* gains a field.
|
|
19
|
+
* 2. **Every table is ordered by identifier**, under {@link compareIdentifiers} — code point, never
|
|
20
|
+
* `localeCompare`, whose answer depends on the machine's collation. Arrays INSIDE a record keep
|
|
21
|
+
* the order they were authored in; the compiler writes the tables, so it orders those.
|
|
22
|
+
*
|
|
23
|
+
* Nothing here records when compilation ran. `modelVersion` is the authored document's own version,
|
|
24
|
+
* so two builds of one document are byte-identical, and a clock in the artifact would make every
|
|
25
|
+
* regenerate a diff.
|
|
26
|
+
*
|
|
27
|
+
* Boundary record: `docs/superpowers/specs/2026-08-26-geographic-model-boundaries.md` (#1917).
|
|
28
|
+
*/
|
|
29
|
+
import { isPlainObject } from "./validation-issues.js";
|
|
30
|
+
/**
|
|
31
|
+
* The artifact FORMAT version — incremented by hand when the compiled shape changes, so a reader meeting an artifact it
|
|
32
|
+
* was not written for says so instead of quietly reading fields that moved.
|
|
33
|
+
*
|
|
34
|
+
* It is not data about the world, which is why a number is allowed here and nowhere in `./schema.ts`.
|
|
35
|
+
*/
|
|
36
|
+
export const ARTIFACT_SCHEMA_VERSION = 1;
|
|
37
|
+
/**
|
|
38
|
+
* The artifact's stated order: UTF-16 code point, ascending.
|
|
39
|
+
*
|
|
40
|
+
* `String.prototype.localeCompare` is the trap this exists to avoid — its answer depends on the machine's collation, so
|
|
41
|
+
* an artifact ordered with it is reproducible only on the machine that built it.
|
|
42
|
+
*/
|
|
43
|
+
export function compareIdentifiers(left, right) {
|
|
44
|
+
if (left < right)
|
|
45
|
+
return -1;
|
|
46
|
+
if (left > right)
|
|
47
|
+
return 1;
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Rebuild `value` with every object's keys in code-point order, at every depth. Arrays keep their order — ordering
|
|
52
|
+
* those is the compiler's job, and doing it here would silently reorder authored data.
|
|
53
|
+
*/
|
|
54
|
+
function canonicalize(value) {
|
|
55
|
+
if (Array.isArray(value))
|
|
56
|
+
return value.map(canonicalize);
|
|
57
|
+
if (!isPlainObject(value))
|
|
58
|
+
return value;
|
|
59
|
+
const canonical = {};
|
|
60
|
+
for (const key of Object.keys(value).toSorted(compareIdentifiers)) {
|
|
61
|
+
const entry = value[key];
|
|
62
|
+
if (entry === undefined)
|
|
63
|
+
continue;
|
|
64
|
+
canonical[key] = canonicalize(entry);
|
|
65
|
+
}
|
|
66
|
+
return canonical;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The artifact's canonical bytes: tab-indented, one trailing newline, keys in code-point order.
|
|
70
|
+
*
|
|
71
|
+
* Tab indentation and the trailing newline match the repository's other committed JSON tables (`taxonomy.json`,
|
|
72
|
+
* `brands.json`). A committed copy of these bytes is the generator's output run through `oxfmt`, which inlines short
|
|
73
|
+
* arrays — so a freshness check compares the PARSED artifact against a fresh compile, and a byte comparison compares
|
|
74
|
+
* two compiles.
|
|
75
|
+
*/
|
|
76
|
+
export function serializeCompiledModel(model) {
|
|
77
|
+
return `${JSON.stringify(canonicalize(model), null, "\t")}\n`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Thrown when a value cannot be read as a compiled artifact.
|
|
81
|
+
*/
|
|
82
|
+
export class GeographicModelArtifactError extends Error {
|
|
83
|
+
constructor(message) {
|
|
84
|
+
super(message);
|
|
85
|
+
this.name = "GeographicModelArtifactError";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The tables every artifact carries. A reader that finds one missing refuses rather than answering every question about
|
|
90
|
+
* that table with an empty list.
|
|
91
|
+
*/
|
|
92
|
+
const ARTIFACT_TABLES = [
|
|
93
|
+
"concepts",
|
|
94
|
+
"derivedFacts",
|
|
95
|
+
"inheritanceClosure",
|
|
96
|
+
"mappings",
|
|
97
|
+
"observations",
|
|
98
|
+
"relations",
|
|
99
|
+
];
|
|
100
|
+
/**
|
|
101
|
+
* Why `value` is not a compiled artifact, or nothing when it is one.
|
|
102
|
+
*
|
|
103
|
+
* Kept separate from {@link parseCompiledGeographicModel} so the reader casts the value it was HANDED, still typed
|
|
104
|
+
* `unknown`, rather than a narrowed shape it would have to launder through a second cast to widen again.
|
|
105
|
+
*/
|
|
106
|
+
function artifactProblem(value) {
|
|
107
|
+
if (!isPlainObject(value))
|
|
108
|
+
return "a compiled geographic model must be an object";
|
|
109
|
+
if (value.schemaVersion !== ARTIFACT_SCHEMA_VERSION) {
|
|
110
|
+
return `this reader understands artifact schema version ${ARTIFACT_SCHEMA_VERSION}; the artifact declares ${JSON.stringify(value.schemaVersion)}`;
|
|
111
|
+
}
|
|
112
|
+
if (typeof value.modelVersion !== "string" || !value.modelVersion.trim().length) {
|
|
113
|
+
return "`modelVersion` must be a non-blank string";
|
|
114
|
+
}
|
|
115
|
+
const missing = ARTIFACT_TABLES.filter((table) => !Array.isArray(value[table]));
|
|
116
|
+
if (!missing.length)
|
|
117
|
+
return undefined;
|
|
118
|
+
return `the artifact is missing ${missing.map((table) => `\`${table}\``).join(", ")}`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Read a parsed artifact — the value `JSON.parse` produced from the compiled bytes — as a
|
|
122
|
+
* {@link CompiledGeographicModel}.
|
|
123
|
+
*
|
|
124
|
+
* It checks the format version and the presence of every table, and does NOT re-validate the records. An artifact is
|
|
125
|
+
* generated from a document that `parseGeographicModelDocument` already accepted; re-checking every record here would
|
|
126
|
+
* be a second validator, and the version check is what catches the failure this reader can actually meet — an artifact
|
|
127
|
+
* written by a different compiler.
|
|
128
|
+
*/
|
|
129
|
+
export function parseCompiledGeographicModel(input) {
|
|
130
|
+
const problem = artifactProblem(input);
|
|
131
|
+
if (problem)
|
|
132
|
+
throw new GeographicModelArtifactError(problem);
|
|
133
|
+
return input;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact.js","sourceRoot":"","sources":["../artifact.ts"],"names":[],"mappings":"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"}
|
package/out/compile.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Deterministic compilation of a validated {@link GeographicModelDocument} into the runtime artifact.
|
|
7
|
+
*
|
|
8
|
+
* The compiler validates by DELEGATION: `parseGeographicModelDocument` is the only thing that
|
|
9
|
+
* decides whether a document is well formed, and it throws with every violation before a single byte
|
|
10
|
+
* is computed. There is no second validator here, and no partial artifact on failure — a compile
|
|
11
|
+
* either produces the whole artifact or produces nothing.
|
|
12
|
+
*
|
|
13
|
+
* **`isA` alone defines semantic inheritance.** Two things follow from it, and they are the whole
|
|
14
|
+
* derivation surface:
|
|
15
|
+
*
|
|
16
|
+
* 1. The transitive `isA` closure is materialized per concept, so a consumer asks "what is this a
|
|
17
|
+
* kind of" with one lookup rather than by walking the graph at query time.
|
|
18
|
+
* 2. Every assertion an ancestor carries is materialized onto its descendants as a
|
|
19
|
+
* {@link DerivedFactRecord}, naming {@link DERIVATION_ISA_INHERITANCE} and every record the
|
|
20
|
+
* derivation read. Without this a consumer would still be traversing — the closure alone tells it
|
|
21
|
+
* which concepts to go and read, which is the traversal it was supposed to be spared.
|
|
22
|
+
*
|
|
23
|
+
* A relation declaring `transitive` or `inverse` is NOT closed over. Those fields are vocabulary
|
|
24
|
+
* describing what the relation means; materializing them is a reasoning step no executable need has
|
|
25
|
+
* asked for, and the boundary record excludes general reasoning from this package. The day one is
|
|
26
|
+
* needed it arrives as its own named derivation beside this one.
|
|
27
|
+
*
|
|
28
|
+
* Cycles never reach the derivations: `parseGeographicModelDocument` refuses a direct or indirect
|
|
29
|
+
* `isA` cycle and names the trail it followed, so a cyclic document fails as a validation error
|
|
30
|
+
* rather than as a hang. The walk below is breadth-first over a visited set regardless, which makes
|
|
31
|
+
* it total for any graph rather than for the graphs the validator happens to admit.
|
|
32
|
+
*/
|
|
33
|
+
import { type CompiledGeographicModel } from "./artifact.ts";
|
|
34
|
+
/**
|
|
35
|
+
* The name a fact derived by `isA` inheritance carries in its `derivation` field. A consumer branches on this rather
|
|
36
|
+
* than on where the record sits.
|
|
37
|
+
*/
|
|
38
|
+
export declare const DERIVATION_ISA_INHERITANCE = "isa-assertion-inheritance";
|
|
39
|
+
/**
|
|
40
|
+
* Every way compilation can refuse a document the validator accepted.
|
|
41
|
+
*
|
|
42
|
+
* Both are discovered while writing derived records, which is why the validator cannot report them: they are properties
|
|
43
|
+
* of what the compiler is about to write, not of what the author wrote.
|
|
44
|
+
*/
|
|
45
|
+
export declare const CompileIssueCode: {
|
|
46
|
+
/**
|
|
47
|
+
* An inherited assertion would land on a concept whose kind the relation does not accept on the asserting side.
|
|
48
|
+
* Emitting it would put a record in the artifact that the document validator would reject if it were authored.
|
|
49
|
+
*/
|
|
50
|
+
readonly InheritedDomainKindMismatch: "inherited_domain_kind_mismatch";
|
|
51
|
+
/**
|
|
52
|
+
* Two derived facts claim one identifier. Reachable when an authored derived fact takes an identifier a derivation
|
|
53
|
+
* also produces, or when authored identifiers carry the separators the derived form is built from.
|
|
54
|
+
*/
|
|
55
|
+
readonly DuplicateDerivedFactID: "duplicate_derived_fact_id";
|
|
56
|
+
};
|
|
57
|
+
export type CompileIssueCode = (typeof CompileIssueCode)[keyof typeof CompileIssueCode];
|
|
58
|
+
/**
|
|
59
|
+
* One reason a document that validates does not compile.
|
|
60
|
+
*/
|
|
61
|
+
export interface CompileIssue {
|
|
62
|
+
code: CompileIssueCode;
|
|
63
|
+
message: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Thrown by {@link compileGeographicModel}. Carries every reason at once, and states them all in its message, so a
|
|
67
|
+
* caller that only prints `error.message` still sees the whole list.
|
|
68
|
+
*/
|
|
69
|
+
export declare class GeographicModelCompileError extends Error {
|
|
70
|
+
readonly issues: readonly CompileIssue[];
|
|
71
|
+
constructor(issues: readonly CompileIssue[]);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compile an authored geographic-model document into its runtime artifact.
|
|
75
|
+
*
|
|
76
|
+
* Throws `GeographicModelValidationError` with every violation if the input is not a valid document, and
|
|
77
|
+
* {@link GeographicModelCompileError} with every reason if it validates but its derivations cannot be written. Nothing
|
|
78
|
+
* partial is ever returned.
|
|
79
|
+
*
|
|
80
|
+
* The document is read, never rewritten: the artifact's tables are new arrays holding the authored records themselves,
|
|
81
|
+
* ordered by identifier, and the derived tables are new records built beside them.
|
|
82
|
+
*/
|
|
83
|
+
export declare function compileGeographicModel(input: unknown): CompiledGeographicModel;
|
|
84
|
+
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../compile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAEN,KAAK,uBAAuB,EAG5B,MAAM,eAAe,CAAA;AAetB;;;GAGG;AACH,eAAO,MAAM,0BAA0B,8BAA8B,CAAA;AAErE;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;IAC5B;;;OAGG;;IAEH;;;OAGG;;CAEM,CAAA;AAEV,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAA;AAEvF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,gBAAgB,CAAA;IACtB,OAAO,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAA;gBAE5B,MAAM,EAAE,SAAS,YAAY,EAAE;CAQ3C;AA+MD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,uBAAuB,CA6B9E"}
|
package/out/compile.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* Deterministic compilation of a validated {@link GeographicModelDocument} into the runtime artifact.
|
|
7
|
+
*
|
|
8
|
+
* The compiler validates by DELEGATION: `parseGeographicModelDocument` is the only thing that
|
|
9
|
+
* decides whether a document is well formed, and it throws with every violation before a single byte
|
|
10
|
+
* is computed. There is no second validator here, and no partial artifact on failure — a compile
|
|
11
|
+
* either produces the whole artifact or produces nothing.
|
|
12
|
+
*
|
|
13
|
+
* **`isA` alone defines semantic inheritance.** Two things follow from it, and they are the whole
|
|
14
|
+
* derivation surface:
|
|
15
|
+
*
|
|
16
|
+
* 1. The transitive `isA` closure is materialized per concept, so a consumer asks "what is this a
|
|
17
|
+
* kind of" with one lookup rather than by walking the graph at query time.
|
|
18
|
+
* 2. Every assertion an ancestor carries is materialized onto its descendants as a
|
|
19
|
+
* {@link DerivedFactRecord}, naming {@link DERIVATION_ISA_INHERITANCE} and every record the
|
|
20
|
+
* derivation read. Without this a consumer would still be traversing — the closure alone tells it
|
|
21
|
+
* which concepts to go and read, which is the traversal it was supposed to be spared.
|
|
22
|
+
*
|
|
23
|
+
* A relation declaring `transitive` or `inverse` is NOT closed over. Those fields are vocabulary
|
|
24
|
+
* describing what the relation means; materializing them is a reasoning step no executable need has
|
|
25
|
+
* asked for, and the boundary record excludes general reasoning from this package. The day one is
|
|
26
|
+
* needed it arrives as its own named derivation beside this one.
|
|
27
|
+
*
|
|
28
|
+
* Cycles never reach the derivations: `parseGeographicModelDocument` refuses a direct or indirect
|
|
29
|
+
* `isA` cycle and names the trail it followed, so a cyclic document fails as a validation error
|
|
30
|
+
* rather than as a hang. The walk below is breadth-first over a visited set regardless, which makes
|
|
31
|
+
* it total for any graph rather than for the graphs the validator happens to admit.
|
|
32
|
+
*/
|
|
33
|
+
import { ARTIFACT_SCHEMA_VERSION, compareIdentifiers, } from "./artifact.js";
|
|
34
|
+
import { DerivationInputKind, toConceptID, toDerivedFactID, } from "./schema.js";
|
|
35
|
+
import { parseGeographicModelDocument } from "./validate.js";
|
|
36
|
+
/**
|
|
37
|
+
* The name a fact derived by `isA` inheritance carries in its `derivation` field. A consumer branches on this rather
|
|
38
|
+
* than on where the record sits.
|
|
39
|
+
*/
|
|
40
|
+
export const DERIVATION_ISA_INHERITANCE = "isa-assertion-inheritance";
|
|
41
|
+
/**
|
|
42
|
+
* Every way compilation can refuse a document the validator accepted.
|
|
43
|
+
*
|
|
44
|
+
* Both are discovered while writing derived records, which is why the validator cannot report them: they are properties
|
|
45
|
+
* of what the compiler is about to write, not of what the author wrote.
|
|
46
|
+
*/
|
|
47
|
+
export const CompileIssueCode = {
|
|
48
|
+
/**
|
|
49
|
+
* An inherited assertion would land on a concept whose kind the relation does not accept on the asserting side.
|
|
50
|
+
* Emitting it would put a record in the artifact that the document validator would reject if it were authored.
|
|
51
|
+
*/
|
|
52
|
+
InheritedDomainKindMismatch: "inherited_domain_kind_mismatch",
|
|
53
|
+
/**
|
|
54
|
+
* Two derived facts claim one identifier. Reachable when an authored derived fact takes an identifier a derivation
|
|
55
|
+
* also produces, or when authored identifiers carry the separators the derived form is built from.
|
|
56
|
+
*/
|
|
57
|
+
DuplicateDerivedFactID: "duplicate_derived_fact_id",
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Thrown by {@link compileGeographicModel}. Carries every reason at once, and states them all in its message, so a
|
|
61
|
+
* caller that only prints `error.message` still sees the whole list.
|
|
62
|
+
*/
|
|
63
|
+
export class GeographicModelCompileError extends Error {
|
|
64
|
+
issues;
|
|
65
|
+
constructor(issues) {
|
|
66
|
+
const detail = issues.map((issue) => `${issue.message} [${issue.code}]`).join("\n");
|
|
67
|
+
super(`geographic-model document does not compile (${issues.length} issues)\n${detail}`);
|
|
68
|
+
this.name = "GeographicModelCompileError";
|
|
69
|
+
this.issues = issues;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The order derivation inputs are listed in. Grouping by table first keeps a long input list readable; the identifier
|
|
74
|
+
* breaks ties inside a table.
|
|
75
|
+
*/
|
|
76
|
+
const DERIVATION_INPUT_ORDER = [
|
|
77
|
+
DerivationInputKind.Concept,
|
|
78
|
+
DerivationInputKind.Relation,
|
|
79
|
+
DerivationInputKind.Assertion,
|
|
80
|
+
DerivationInputKind.Mapping,
|
|
81
|
+
DerivationInputKind.Observation,
|
|
82
|
+
DerivationInputKind.DerivedFact,
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* The separator for the compound keys this module groups by. `U+0000` cannot appear in a readable identifier without
|
|
86
|
+
* being visible in it, so two different key tuples cannot collapse onto one string. The derived IDENTIFIERS written
|
|
87
|
+
* into the artifact use readable separators instead, and are checked for collisions once they are all built.
|
|
88
|
+
*/
|
|
89
|
+
const KEY_SEPARATOR = "\u0000";
|
|
90
|
+
/**
|
|
91
|
+
* The separator between country codes inside a derived identifier.
|
|
92
|
+
*/
|
|
93
|
+
const COUNTRY_SEPARATOR = "+";
|
|
94
|
+
function compareByID(left, right) {
|
|
95
|
+
return compareIdentifiers(left.id, right.id);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Walk `isA` upward from one concept and return every concept reachable, in code-point order.
|
|
99
|
+
*
|
|
100
|
+
* Breadth-first over a visited set: each concept is expanded once, so the walk terminates on any graph and the answer
|
|
101
|
+
* does not depend on how the parents were authored. The concept itself is never in its own list — it could only get
|
|
102
|
+
* there around a cycle, and the validator refuses those before the compiler runs.
|
|
103
|
+
*/
|
|
104
|
+
function ancestorsOfConcept(conceptID, parents) {
|
|
105
|
+
const visited = new Set();
|
|
106
|
+
const frontier = [...(parents.get(conceptID) ?? [])];
|
|
107
|
+
// An array iterator reads entries appended during the walk, which is what makes this breadth-first rather than a
|
|
108
|
+
// pass over the direct parents.
|
|
109
|
+
for (const next of frontier) {
|
|
110
|
+
if (next === conceptID || visited.has(next))
|
|
111
|
+
continue;
|
|
112
|
+
visited.add(next);
|
|
113
|
+
frontier.push(...(parents.get(next) ?? []));
|
|
114
|
+
}
|
|
115
|
+
const reachable = [...visited].toSorted(compareIdentifiers);
|
|
116
|
+
return reachable.map(toConceptID);
|
|
117
|
+
}
|
|
118
|
+
function addInput(draft, input) {
|
|
119
|
+
draft.inputs.set(`${input.kind}${KEY_SEPARATOR}${input.id}`, input);
|
|
120
|
+
}
|
|
121
|
+
function draftInputs(draft) {
|
|
122
|
+
const inputs = [...draft.inputs.values()];
|
|
123
|
+
return inputs.toSorted((left, right) => {
|
|
124
|
+
const byKind = DERIVATION_INPUT_ORDER.indexOf(left.kind) - DERIVATION_INPUT_ORDER.indexOf(right.kind);
|
|
125
|
+
return byKind === 0 ? compareIdentifiers(left.id, right.id) : byKind;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The identifier a derived fact carries. Built from the proposition it states, so it is stable across edits elsewhere
|
|
130
|
+
* in the document, and readable, so a reader meeting one in a diff can tell what it says.
|
|
131
|
+
*/
|
|
132
|
+
function derivedFactID(draft) {
|
|
133
|
+
const scope = draft.countries?.length ? `:${draft.countries.join(COUNTRY_SEPARATOR)}` : "";
|
|
134
|
+
const { relation, target, modality } = draft.assertion;
|
|
135
|
+
return `${DERIVATION_ISA_INHERITANCE}:${draft.subject}:${relation}:${target}:${modality}${scope}`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The relation and target one assertion is about — the pair a descendant's own assertion speaks for.
|
|
139
|
+
*/
|
|
140
|
+
function edgeKey(assertion) {
|
|
141
|
+
return `${assertion.relation}${KEY_SEPARATOR}${assertion.target}`;
|
|
142
|
+
}
|
|
143
|
+
function draftKey(subject, assertion, countries) {
|
|
144
|
+
const scope = countries?.join(COUNTRY_SEPARATOR) ?? "";
|
|
145
|
+
return `${subject}${KEY_SEPARATOR}${edgeKey(assertion)}${KEY_SEPARATOR}${assertion.modality}${KEY_SEPARATOR}${scope}`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Materialize every ancestor's assertions onto their descendants.
|
|
149
|
+
*
|
|
150
|
+
* A concept that authors its own assertion for the same relation and target inherits nothing for that pair. The
|
|
151
|
+
* authored record is the more specific one, which is what `isA` means, and re-stating the pair would put two modalities
|
|
152
|
+
* for one proposition into the artifact with no rule saying which of them holds.
|
|
153
|
+
*/
|
|
154
|
+
function deriveInheritedFacts(concepts, closure, relations, issues) {
|
|
155
|
+
const conceptByID = new Map(concepts.map((concept) => [String(concept.id), concept]));
|
|
156
|
+
const relationByID = new Map(relations.map((relation) => [String(relation.id), relation]));
|
|
157
|
+
const drafts = new Map();
|
|
158
|
+
for (const entry of closure) {
|
|
159
|
+
const concept = conceptByID.get(String(entry.concept));
|
|
160
|
+
if (!concept)
|
|
161
|
+
continue;
|
|
162
|
+
const authored = new Set(concept.assertions.map(edgeKey));
|
|
163
|
+
for (const ancestorID of entry.ancestors) {
|
|
164
|
+
const ancestor = conceptByID.get(String(ancestorID));
|
|
165
|
+
// Validation refuses an `isA` naming an undeclared concept, and an assertion naming an undeclared relation,
|
|
166
|
+
// so both resolve for any document that reached the compiler. The guards keep the walk total; they do not
|
|
167
|
+
// describe a state the artifact can hold.
|
|
168
|
+
if (!ancestor)
|
|
169
|
+
continue;
|
|
170
|
+
for (const assertion of ancestor.assertions) {
|
|
171
|
+
if (authored.has(edgeKey(assertion)))
|
|
172
|
+
continue;
|
|
173
|
+
const relation = relationByID.get(String(assertion.relation));
|
|
174
|
+
if (!relation)
|
|
175
|
+
continue;
|
|
176
|
+
if (!relation.domainKinds.includes(concept.kind)) {
|
|
177
|
+
const accepted = relation.domainKinds.map((kind) => `\`${kind}\``).join(", ");
|
|
178
|
+
issues.push({
|
|
179
|
+
code: CompileIssueCode.InheritedDomainKindMismatch,
|
|
180
|
+
message: `\`${concept.id}\` is a \`${concept.kind}\` and is a kind of \`${ancestor.id}\`, whose assertion \`${assertion.id}\` uses relation \`${relation.id}\` — which accepts ${accepted} on the asserting side`,
|
|
181
|
+
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
const countries = assertion.countries?.length ? assertion.countries.toSorted(compareIdentifiers) : undefined;
|
|
185
|
+
const key = draftKey(concept.id, assertion, countries);
|
|
186
|
+
const existing = drafts.get(key);
|
|
187
|
+
const draft = existing ?? { subject: concept.id, assertion, countries, inputs: new Map() };
|
|
188
|
+
addInput(draft, { kind: DerivationInputKind.Concept, id: concept.id });
|
|
189
|
+
addInput(draft, { kind: DerivationInputKind.Concept, id: ancestor.id });
|
|
190
|
+
addInput(draft, { kind: DerivationInputKind.Relation, id: relation.id });
|
|
191
|
+
addInput(draft, { kind: DerivationInputKind.Assertion, id: assertion.id });
|
|
192
|
+
if (!existing) {
|
|
193
|
+
drafts.set(key, draft);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return [...drafts.values()].map((draft) => ({
|
|
199
|
+
id: toDerivedFactID(derivedFactID(draft)),
|
|
200
|
+
derivation: DERIVATION_ISA_INHERITANCE,
|
|
201
|
+
inputs: draftInputs(draft),
|
|
202
|
+
subject: draft.subject,
|
|
203
|
+
relation: draft.assertion.relation,
|
|
204
|
+
object: draft.assertion.target,
|
|
205
|
+
modality: draft.assertion.modality,
|
|
206
|
+
...(draft.countries ? { countries: [...draft.countries] } : {}),
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
function checkDerivedIdentifiers(facts, issues) {
|
|
210
|
+
const seen = new Set();
|
|
211
|
+
for (const fact of facts) {
|
|
212
|
+
const id = String(fact.id);
|
|
213
|
+
if (seen.has(id)) {
|
|
214
|
+
issues.push({
|
|
215
|
+
code: CompileIssueCode.DuplicateDerivedFactID,
|
|
216
|
+
message: `two derived facts claim \`${id}\` — an authored derived fact and a derivation cannot share an identifier`,
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
seen.add(id);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Compile an authored geographic-model document into its runtime artifact.
|
|
225
|
+
*
|
|
226
|
+
* Throws `GeographicModelValidationError` with every violation if the input is not a valid document, and
|
|
227
|
+
* {@link GeographicModelCompileError} with every reason if it validates but its derivations cannot be written. Nothing
|
|
228
|
+
* partial is ever returned.
|
|
229
|
+
*
|
|
230
|
+
* The document is read, never rewritten: the artifact's tables are new arrays holding the authored records themselves,
|
|
231
|
+
* ordered by identifier, and the derived tables are new records built beside them.
|
|
232
|
+
*/
|
|
233
|
+
export function compileGeographicModel(input) {
|
|
234
|
+
const document = parseGeographicModelDocument(input);
|
|
235
|
+
const concepts = document.concepts.toSorted(compareByID);
|
|
236
|
+
const relations = document.relations.toSorted(compareByID);
|
|
237
|
+
const parents = new Map(concepts.map((concept) => [String(concept.id), concept.isA]));
|
|
238
|
+
const inheritanceClosure = concepts.map((concept) => ({
|
|
239
|
+
concept: concept.id,
|
|
240
|
+
ancestors: ancestorsOfConcept(concept.id, parents),
|
|
241
|
+
}));
|
|
242
|
+
const issues = [];
|
|
243
|
+
const derived = deriveInheritedFacts(concepts, inheritanceClosure, relations, issues);
|
|
244
|
+
const derivedFacts = [...document.derivedFacts, ...derived].toSorted(compareByID);
|
|
245
|
+
checkDerivedIdentifiers(derivedFacts, issues);
|
|
246
|
+
if (issues.length)
|
|
247
|
+
throw new GeographicModelCompileError(issues);
|
|
248
|
+
return {
|
|
249
|
+
schemaVersion: ARTIFACT_SCHEMA_VERSION,
|
|
250
|
+
modelVersion: document.version,
|
|
251
|
+
relations,
|
|
252
|
+
concepts,
|
|
253
|
+
mappings: document.mappings.toSorted(compareByID),
|
|
254
|
+
observations: document.observations.toSorted(compareByID),
|
|
255
|
+
inheritanceClosure,
|
|
256
|
+
derivedFacts,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=compile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../compile.ts"],"names":[],"mappings":"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"}
|
package/out/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/geographic-model` — the world-semantic layer: stable concepts beyond the POI
|
|
7
|
+
* vocabulary, relation definitions, activities and affordances, rule modality, source
|
|
8
|
+
* observations, derived facts, derivation provenance, deterministic compilation and validation,
|
|
9
|
+
* and mappings from external vocabularies into world concepts.
|
|
10
|
+
*
|
|
11
|
+
* The public surface is the authored-record schema (`./schema.ts`), its deterministic validator
|
|
12
|
+
* (`./validate.ts`), the compiler that turns a validated document into the runtime artifact
|
|
13
|
+
* (`./compile.ts`), the artifact's shape and canonical bytes (`./artifact.ts`), and the lookups a
|
|
14
|
+
* runtime consumer reads it through (`./lookup.ts`). All five are re-exported here and all five are
|
|
15
|
+
* reachable as curated subpaths.
|
|
16
|
+
*
|
|
17
|
+
* The authoring loader (`./load.ts`, the `./load` subpath) is deliberately NOT re-exported here. It
|
|
18
|
+
* is the only module in the package that touches a filesystem, and it belongs to the build step that
|
|
19
|
+
* produces an artifact rather than to the consumers that read one. The first authored document
|
|
20
|
+
* arrives with #1927; this entry point carries no data.
|
|
21
|
+
*
|
|
22
|
+
* Four things this package must never hold, each owned elsewhere and each a rule the review
|
|
23
|
+
* applies rather than a preference:
|
|
24
|
+
*
|
|
25
|
+
* 1. **Ranking policy.** No weights, boosts, penalties, or candidate-ordering API — not as a
|
|
26
|
+
* function, not as a type. Candidate ordering belongs to `@mailwoman/resolver`, and the decode
|
|
27
|
+
* objective to `@mailwoman/neural` plus `@mailwoman/core/decoder`. Knowledge here creates
|
|
28
|
+
* observations; it never overrides learned interpretation.
|
|
29
|
+
* 2. **A second POI vocabulary.** External and curated POI categories, their containment
|
|
30
|
+
* hierarchy, the Overture-leaf translation, the query-phrase lexicon and the brand table all
|
|
31
|
+
* belong to `@mailwoman/poi-taxonomy`. This package maps INTO those identifiers.
|
|
32
|
+
* 3. **A second coverage register.** Dataset identity and coverage epistemics belong to
|
|
33
|
+
* `@mailwoman/core/layers`. An expected-but-absent observation becomes negative evidence only
|
|
34
|
+
* where `supportsExclusion` permits it there.
|
|
35
|
+
* 4. **Empirical affordance statistics.** #1683 fits those. This package owns the stable
|
|
36
|
+
* activity and affordance identifiers they are fitted against, and nothing numeric about them.
|
|
37
|
+
*
|
|
38
|
+
* `@mailwoman/core` must not depend on this package. Core ships the pipeline contract and roughly
|
|
39
|
+
* 9 MB of reference data to every consumer, so a world-semantics dependency there is one every
|
|
40
|
+
* drop-in API inherits without asking for it. Reversing that direction is an explicit amendment to
|
|
41
|
+
* the boundary record, not a convenience during implementation.
|
|
42
|
+
*
|
|
43
|
+
* Boundary record: `docs/superpowers/specs/2026-08-26-geographic-model-boundaries.md` (#1917).
|
|
44
|
+
* Program parent: #1916.
|
|
45
|
+
*/
|
|
46
|
+
export * from "./artifact.ts";
|
|
47
|
+
export * from "./compile.ts";
|
|
48
|
+
export * from "./lookup.ts";
|
|
49
|
+
export * from "./schema.ts";
|
|
50
|
+
export * from "./validate.ts";
|
|
51
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|
package/out/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Sister Software
|
|
3
|
+
* @license AGPL-3.0
|
|
4
|
+
* @author Teffen Ellis, et al.
|
|
5
|
+
*
|
|
6
|
+
* `@mailwoman/geographic-model` — the world-semantic layer: stable concepts beyond the POI
|
|
7
|
+
* vocabulary, relation definitions, activities and affordances, rule modality, source
|
|
8
|
+
* observations, derived facts, derivation provenance, deterministic compilation and validation,
|
|
9
|
+
* and mappings from external vocabularies into world concepts.
|
|
10
|
+
*
|
|
11
|
+
* The public surface is the authored-record schema (`./schema.ts`), its deterministic validator
|
|
12
|
+
* (`./validate.ts`), the compiler that turns a validated document into the runtime artifact
|
|
13
|
+
* (`./compile.ts`), the artifact's shape and canonical bytes (`./artifact.ts`), and the lookups a
|
|
14
|
+
* runtime consumer reads it through (`./lookup.ts`). All five are re-exported here and all five are
|
|
15
|
+
* reachable as curated subpaths.
|
|
16
|
+
*
|
|
17
|
+
* The authoring loader (`./load.ts`, the `./load` subpath) is deliberately NOT re-exported here. It
|
|
18
|
+
* is the only module in the package that touches a filesystem, and it belongs to the build step that
|
|
19
|
+
* produces an artifact rather than to the consumers that read one. The first authored document
|
|
20
|
+
* arrives with #1927; this entry point carries no data.
|
|
21
|
+
*
|
|
22
|
+
* Four things this package must never hold, each owned elsewhere and each a rule the review
|
|
23
|
+
* applies rather than a preference:
|
|
24
|
+
*
|
|
25
|
+
* 1. **Ranking policy.** No weights, boosts, penalties, or candidate-ordering API — not as a
|
|
26
|
+
* function, not as a type. Candidate ordering belongs to `@mailwoman/resolver`, and the decode
|
|
27
|
+
* objective to `@mailwoman/neural` plus `@mailwoman/core/decoder`. Knowledge here creates
|
|
28
|
+
* observations; it never overrides learned interpretation.
|
|
29
|
+
* 2. **A second POI vocabulary.** External and curated POI categories, their containment
|
|
30
|
+
* hierarchy, the Overture-leaf translation, the query-phrase lexicon and the brand table all
|
|
31
|
+
* belong to `@mailwoman/poi-taxonomy`. This package maps INTO those identifiers.
|
|
32
|
+
* 3. **A second coverage register.** Dataset identity and coverage epistemics belong to
|
|
33
|
+
* `@mailwoman/core/layers`. An expected-but-absent observation becomes negative evidence only
|
|
34
|
+
* where `supportsExclusion` permits it there.
|
|
35
|
+
* 4. **Empirical affordance statistics.** #1683 fits those. This package owns the stable
|
|
36
|
+
* activity and affordance identifiers they are fitted against, and nothing numeric about them.
|
|
37
|
+
*
|
|
38
|
+
* `@mailwoman/core` must not depend on this package. Core ships the pipeline contract and roughly
|
|
39
|
+
* 9 MB of reference data to every consumer, so a world-semantics dependency there is one every
|
|
40
|
+
* drop-in API inherits without asking for it. Reversing that direction is an explicit amendment to
|
|
41
|
+
* the boundary record, not a convenience during implementation.
|
|
42
|
+
*
|
|
43
|
+
* Boundary record: `docs/superpowers/specs/2026-08-26-geographic-model-boundaries.md` (#1917).
|
|
44
|
+
* Program parent: #1916.
|
|
45
|
+
*/
|
|
46
|
+
export * from "./artifact.js";
|
|
47
|
+
export * from "./compile.js";
|
|
48
|
+
export * from "./lookup.js";
|
|
49
|
+
export * from "./schema.js";
|
|
50
|
+
export * from "./validate.js";
|
|
51
|
+
//# sourceMappingURL=index.js.map
|
package/out/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA"}
|