@hraness/oh 0.2.3
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/LICENSE +21 -0
- package/README.md +598 -0
- package/dist/canonical.d.ts +32 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3419 -0
- package/dist/contract.d.ts +33 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/graph.d.ts +67 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1988 -0
- package/dist/libsql.d.ts +57 -0
- package/dist/libsql.d.ts.map +1 -0
- package/dist/libsql.js +2662 -0
- package/dist/memory.d.ts +366 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +3650 -0
- package/dist/ontology.d.ts +242 -0
- package/dist/ontology.d.ts.map +1 -0
- package/dist/operation.d.ts +24 -0
- package/dist/operation.d.ts.map +1 -0
- package/dist/projection-public.d.ts +59 -0
- package/dist/projection-public.d.ts.map +1 -0
- package/dist/projection-public.js +1682 -0
- package/dist/projection-suss.d.ts +17 -0
- package/dist/projection-suss.d.ts.map +1 -0
- package/dist/projection-suss.js +1721 -0
- package/dist/projection.d.ts +315 -0
- package/dist/projection.d.ts.map +1 -0
- package/dist/schema.d.ts +45 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/sdk.d.ts +51 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +3072 -0
- package/dist/search.d.ts +34 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/semantic.d.ts +83 -0
- package/dist/semantic.d.ts.map +1 -0
- package/dist/semantic.js +706 -0
- package/dist/sqlite/driver.d.ts +6 -0
- package/dist/sqlite/driver.d.ts.map +1 -0
- package/dist/sqlite/index.d.ts +5 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +2840 -0
- package/dist/sqlite/migrations.d.ts +10 -0
- package/dist/sqlite/migrations.d.ts.map +1 -0
- package/dist/sqlite/port.d.ts +40 -0
- package/dist/sqlite/port.d.ts.map +1 -0
- package/dist/sqlite/runtime.d.ts +23 -0
- package/dist/sqlite/runtime.d.ts.map +1 -0
- package/dist/sqlite/store.d.ts +85 -0
- package/dist/sqlite/store.d.ts.map +1 -0
- package/dist/store.d.ts +236 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +996 -0
- package/dist/sync.d.ts +57 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +1328 -0
- package/package.json +121 -0
- package/skills/oh/SKILL.md +206 -0
- package/skills/oh/agents/openai.yaml +4 -0
- package/spec/README.md +74 -0
- package/spec/manifest.json +41 -0
- package/spec/v1/canonical-json.md +59 -0
- package/spec/v1/contract.json +28 -0
- package/spec/v1/contract.schema.json +58 -0
- package/spec/v1/embedding-profile.json +11 -0
- package/spec/v1/embedding.md +56 -0
- package/spec/v1/graph.md +87 -0
- package/spec/v1/memory.md +193 -0
- package/spec/v1/migration.md +92 -0
- package/spec/v1/ontology.json +55 -0
- package/spec/v1/ontology.md +80 -0
- package/spec/v1/operation.schema.json +138 -0
- package/spec/v1/projection-identity.schema.json +58 -0
- package/spec/v1/projection-query.schema.json +60 -0
- package/spec/v1/projection-result.schema.json +452 -0
- package/spec/v1/projection-rule-pack.schema.json +182 -0
- package/spec/v1/projection.md +165 -0
- package/spec/v1/record.schema.json +95 -0
- package/spec/v1/schema-evolution.md +51 -0
- package/spec/v1/schema-revision.schema.json +178 -0
- package/spec/v1/storage.md +88 -0
- package/spec/v1/store.md +131 -0
- package/spec/v1/sync-bundle.schema.json +51 -0
- package/spec/v1/sync.md +67 -0
- package/src/canonical.test.ts +46 -0
- package/src/canonical.ts +203 -0
- package/src/cli.test.ts +103 -0
- package/src/cli.ts +308 -0
- package/src/contract.ts +87 -0
- package/src/contracts.test.ts +147 -0
- package/src/graph.ts +248 -0
- package/src/index.ts +8 -0
- package/src/libsql.test.ts +657 -0
- package/src/libsql.ts +1687 -0
- package/src/memory.test.ts +783 -0
- package/src/memory.ts +1684 -0
- package/src/ontology.ts +573 -0
- package/src/operation.ts +80 -0
- package/src/projection-public.ts +53 -0
- package/src/projection-suss.ts +129 -0
- package/src/projection.test.ts +418 -0
- package/src/projection.ts +1457 -0
- package/src/schema.ts +156 -0
- package/src/sdk.ts +96 -0
- package/src/search.ts +66 -0
- package/src/semantic.test.ts +480 -0
- package/src/semantic.ts +333 -0
- package/src/sqlite/driver.ts +47 -0
- package/src/sqlite/index.ts +4 -0
- package/src/sqlite/migrations.test.ts +44 -0
- package/src/sqlite/migrations.ts +178 -0
- package/src/sqlite/port.test.ts +127 -0
- package/src/sqlite/port.ts +120 -0
- package/src/sqlite/runtime.test.ts +68 -0
- package/src/sqlite/runtime.ts +53 -0
- package/src/sqlite/store.test.ts +295 -0
- package/src/sqlite/store.ts +988 -0
- package/src/store.test.ts +121 -0
- package/src/store.ts +701 -0
- package/src/sync.test.ts +117 -0
- package/src/sync.ts +227 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$defs": {
|
|
3
|
+
"atom": {
|
|
4
|
+
"oneOf": [
|
|
5
|
+
{
|
|
6
|
+
"type": "boolean"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"type": "null"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "number"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"maxLength": 16382,
|
|
16
|
+
"type": "string"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"constantTerm": {
|
|
21
|
+
"additionalProperties": false,
|
|
22
|
+
"properties": {
|
|
23
|
+
"kind": {
|
|
24
|
+
"const": "constant"
|
|
25
|
+
},
|
|
26
|
+
"v": {
|
|
27
|
+
"const": 1
|
|
28
|
+
},
|
|
29
|
+
"value": {
|
|
30
|
+
"$ref": "#/$defs/atom"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"required": [
|
|
34
|
+
"kind",
|
|
35
|
+
"v",
|
|
36
|
+
"value"
|
|
37
|
+
],
|
|
38
|
+
"type": "object"
|
|
39
|
+
},
|
|
40
|
+
"literal": {
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"properties": {
|
|
43
|
+
"relation": {
|
|
44
|
+
"$ref": "#/$defs/safeCode"
|
|
45
|
+
},
|
|
46
|
+
"terms": {
|
|
47
|
+
"items": {
|
|
48
|
+
"$ref": "#/$defs/term"
|
|
49
|
+
},
|
|
50
|
+
"maxItems": 32,
|
|
51
|
+
"minItems": 1,
|
|
52
|
+
"type": "array"
|
|
53
|
+
},
|
|
54
|
+
"v": {
|
|
55
|
+
"const": 1
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"required": [
|
|
59
|
+
"relation",
|
|
60
|
+
"terms",
|
|
61
|
+
"v"
|
|
62
|
+
],
|
|
63
|
+
"type": "object"
|
|
64
|
+
},
|
|
65
|
+
"rule": {
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"properties": {
|
|
68
|
+
"body": {
|
|
69
|
+
"items": {
|
|
70
|
+
"$ref": "#/$defs/literal"
|
|
71
|
+
},
|
|
72
|
+
"maxItems": 64,
|
|
73
|
+
"minItems": 1,
|
|
74
|
+
"type": "array"
|
|
75
|
+
},
|
|
76
|
+
"head": {
|
|
77
|
+
"$ref": "#/$defs/literal"
|
|
78
|
+
},
|
|
79
|
+
"ruleId": {
|
|
80
|
+
"$ref": "#/$defs/safeCode"
|
|
81
|
+
},
|
|
82
|
+
"ruleSha256": {
|
|
83
|
+
"$ref": "#/$defs/sha256"
|
|
84
|
+
},
|
|
85
|
+
"v": {
|
|
86
|
+
"const": 1
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"required": [
|
|
90
|
+
"body",
|
|
91
|
+
"head",
|
|
92
|
+
"ruleId",
|
|
93
|
+
"ruleSha256",
|
|
94
|
+
"v"
|
|
95
|
+
],
|
|
96
|
+
"type": "object"
|
|
97
|
+
},
|
|
98
|
+
"safeCode": {
|
|
99
|
+
"maxLength": 128,
|
|
100
|
+
"pattern": "^[a-z][a-z0-9]*(?:[._:/-][a-z0-9]+)*$",
|
|
101
|
+
"type": "string"
|
|
102
|
+
},
|
|
103
|
+
"sha256": {
|
|
104
|
+
"pattern": "^[a-f0-9]{64}$",
|
|
105
|
+
"type": "string"
|
|
106
|
+
},
|
|
107
|
+
"term": {
|
|
108
|
+
"oneOf": [
|
|
109
|
+
{
|
|
110
|
+
"$ref": "#/$defs/constantTerm"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"$ref": "#/$defs/variableTerm"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
"variableTerm": {
|
|
118
|
+
"additionalProperties": false,
|
|
119
|
+
"properties": {
|
|
120
|
+
"kind": {
|
|
121
|
+
"const": "variable"
|
|
122
|
+
},
|
|
123
|
+
"name": {
|
|
124
|
+
"$ref": "#/$defs/safeCode"
|
|
125
|
+
},
|
|
126
|
+
"v": {
|
|
127
|
+
"const": 1
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"required": [
|
|
131
|
+
"kind",
|
|
132
|
+
"name",
|
|
133
|
+
"v"
|
|
134
|
+
],
|
|
135
|
+
"type": "object"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"$id": "https://oh.computer/spec/v1/projection-rule-pack.schema.json",
|
|
139
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
140
|
+
"$comment": "Runtime conformance additionally measures each atom's exact 16 KiB canonical-JSON byte ceiling, requires safe head variables, canonical rule ordering, unique rule IDs, and recomputed rule and pack digests.",
|
|
141
|
+
"additionalProperties": false,
|
|
142
|
+
"properties": {
|
|
143
|
+
"rulePackId": {
|
|
144
|
+
"$ref": "#/$defs/safeCode"
|
|
145
|
+
},
|
|
146
|
+
"rulePackRevision": {
|
|
147
|
+
"minimum": 1,
|
|
148
|
+
"type": "integer"
|
|
149
|
+
},
|
|
150
|
+
"rulePackSha256": {
|
|
151
|
+
"$ref": "#/$defs/sha256"
|
|
152
|
+
},
|
|
153
|
+
"rules": {
|
|
154
|
+
"items": {
|
|
155
|
+
"$ref": "#/$defs/rule"
|
|
156
|
+
},
|
|
157
|
+
"maxItems": 1024,
|
|
158
|
+
"minItems": 1,
|
|
159
|
+
"type": "array"
|
|
160
|
+
},
|
|
161
|
+
"rulesSha256": {
|
|
162
|
+
"$ref": "#/$defs/sha256"
|
|
163
|
+
},
|
|
164
|
+
"semantics": {
|
|
165
|
+
"const": "oh.projection.positive-datalog.v1"
|
|
166
|
+
},
|
|
167
|
+
"v": {
|
|
168
|
+
"const": 1
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"required": [
|
|
172
|
+
"rulePackId",
|
|
173
|
+
"rulePackRevision",
|
|
174
|
+
"rulePackSha256",
|
|
175
|
+
"rules",
|
|
176
|
+
"rulesSha256",
|
|
177
|
+
"semantics",
|
|
178
|
+
"v"
|
|
179
|
+
],
|
|
180
|
+
"title": "Oh projection rule pack V1",
|
|
181
|
+
"type": "object"
|
|
182
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Derived projections
|
|
2
|
+
|
|
3
|
+
Oh projections are reproducible, non-authoritative views over one exact graph
|
|
4
|
+
snapshot. The runtime exposes the same typed rule, query, identity, and result
|
|
5
|
+
contract through `@hraness/oh/projection` without changing the V1 graph record,
|
|
6
|
+
operation, canonical JSON, or SQLite formats.
|
|
7
|
+
|
|
8
|
+
## Authority boundary
|
|
9
|
+
|
|
10
|
+
A projection result has `authority: "derived"`. Its tuples and proof trees are
|
|
11
|
+
cache output. They MUST NOT be interpreted as graph assertions, review
|
|
12
|
+
decisions, accepted knowledge, or operation history. An application that wants
|
|
13
|
+
to retain a conclusion MUST create and review new graph records through its
|
|
14
|
+
ordinary authority path.
|
|
15
|
+
|
|
16
|
+
The projection module imports no SQLite runtime. A caller supplies an exact
|
|
17
|
+
snapshot assembled from the authority it selected. This keeps the same contract
|
|
18
|
+
usable in a Node 24 serverless process, a local agent, or an application-owned
|
|
19
|
+
remote-store adapter.
|
|
20
|
+
|
|
21
|
+
## Exact input identity
|
|
22
|
+
|
|
23
|
+
`createOhProjectionSnapshotV1` accepts a space ID, current head, and complete
|
|
24
|
+
record snapshot. It:
|
|
25
|
+
|
|
26
|
+
1. parses every record under the unchanged V1 graph contract;
|
|
27
|
+
2. sorts record references by logical key;
|
|
28
|
+
3. recomputes `recordsSha256` and requires it to equal the head;
|
|
29
|
+
4. checks dependency closure; and
|
|
30
|
+
5. hashes the contract digest, space, head, and record references into
|
|
31
|
+
`snapshotSha256`.
|
|
32
|
+
|
|
33
|
+
A fact is one relation tuple plus one or more exact source record keys and
|
|
34
|
+
digests. A dataset rejects a source that is not current at its snapshot.
|
|
35
|
+
Duplicate relation tuples are coalesced and retain the union of their source
|
|
36
|
+
records. The dataset identity binds:
|
|
37
|
+
|
|
38
|
+
- the snapshot digest;
|
|
39
|
+
- a fact-pack ID and revision;
|
|
40
|
+
- the SHA-256 digest of the application-owned extractor implementation; and
|
|
41
|
+
- the canonical ordered fact set.
|
|
42
|
+
|
|
43
|
+
Oh supplies structural `oh.record(key, kind, digest)` and
|
|
44
|
+
`oh.dependency(key, dependency)` facts. Domain packs may emit richer relations,
|
|
45
|
+
but their extractor digest and every source record remain explicit. The
|
|
46
|
+
package-owned structural extractor profile is published as
|
|
47
|
+
`OH_PROJECTION_RECORD_FACT_EXTRACTOR_V1`.
|
|
48
|
+
|
|
49
|
+
## Positive rule semantics
|
|
50
|
+
|
|
51
|
+
A term is a variable or a JSON primitive constant. A literal names one relation
|
|
52
|
+
and an ordered term list. A rule has one head and a nonempty conjunction of
|
|
53
|
+
positive body literals. Every head variable MUST occur in its body. Relation
|
|
54
|
+
arity MUST be consistent across base facts, rule heads, rule bodies, and the
|
|
55
|
+
query.
|
|
56
|
+
|
|
57
|
+
The V1 projection evaluator implements finite, positive Datalog with set
|
|
58
|
+
semantics and synchronous naïve fixpoint rounds. It supports recursive rules.
|
|
59
|
+
It does not support negation, aggregation, arithmetic, function symbols, or
|
|
60
|
+
callbacks inside rules. Unknown objects are parsed with exact keys, so an
|
|
61
|
+
unsupported operator fails rather than being ignored.
|
|
62
|
+
|
|
63
|
+
Rule packs are sorted by rule ID and content-addressed. A query declares an
|
|
64
|
+
ordered `find` variable list, a nonempty positive body, and an output limit.
|
|
65
|
+
Query results use set semantics and sort tuples by canonical JSON. Declaration,
|
|
66
|
+
fact, and insertion order do not affect rule-pack identity or output bytes.
|
|
67
|
+
The projection identity also binds the selected engine and resolved evaluation
|
|
68
|
+
limits, so results created with different engines, proof budgets, or work
|
|
69
|
+
budgets cannot share a cache identity.
|
|
70
|
+
|
|
71
|
+
## Evaluation limits
|
|
72
|
+
|
|
73
|
+
The implementation checks hard ceilings before or during work:
|
|
74
|
+
|
|
75
|
+
| Item | Maximum |
|
|
76
|
+
| --- | ---: |
|
|
77
|
+
| Tuple arity | 32 |
|
|
78
|
+
| Canonical bytes per atom | 16 KiB |
|
|
79
|
+
| Base facts | 262,144 |
|
|
80
|
+
| Derived tuples | 262,144 |
|
|
81
|
+
| Rules | 1,024 |
|
|
82
|
+
| Body literals per rule | 64 |
|
|
83
|
+
| Evaluation rounds | 1,024 |
|
|
84
|
+
| Join matches per rule or query body | 262,144 |
|
|
85
|
+
| Tuple-unification work units per evaluation | 16,777,216 |
|
|
86
|
+
| Returned query rows | 65,536 |
|
|
87
|
+
| Proof depth | 128 |
|
|
88
|
+
| Proof nodes per row | 4,096 |
|
|
89
|
+
| Proof nodes across returned rows | 65,536 |
|
|
90
|
+
| Canonical result bytes | 16 MiB |
|
|
91
|
+
|
|
92
|
+
A caller may request smaller derived-tuple, round, proof-depth, proof-node, and
|
|
93
|
+
global tuple-unification work bounds. The global work counter spans every rule,
|
|
94
|
+
round, and the final query, including unsuccessful candidate matches. Exceeding
|
|
95
|
+
a work bound fails closed. Result construction additionally stops before the
|
|
96
|
+
aggregate proof-node or canonical-byte ceilings. A query's declared output
|
|
97
|
+
limit or the result-byte ceiling returns a canonical prefix, sets
|
|
98
|
+
`stats.truncated: true`, and lists `query-limit` or `result-bytes` in
|
|
99
|
+
`stats.truncationReasons`.
|
|
100
|
+
|
|
101
|
+
## Proofs
|
|
102
|
+
|
|
103
|
+
Each returned row carries one proof for each literal in one canonical supporting
|
|
104
|
+
query-body match. `supportCount` reports how many complete matches produced the
|
|
105
|
+
same projected value tuple; V1 deliberately does not serialize every alternate
|
|
106
|
+
witness. A fact leaf names its relation, tuple, and exact source record
|
|
107
|
+
references. A derived node names the rule ID and digest and recursively contains
|
|
108
|
+
its premises. Depth and cycle guards emit an explicit `truncated` node. If a
|
|
109
|
+
node or byte budget ends between sibling premises, the enclosing derived node
|
|
110
|
+
sets `premisesTruncated: true`; if it ends between query-body proofs, the row
|
|
111
|
+
sets `proofsTruncated: true`.
|
|
112
|
+
`stats.proofsTruncated` reports either form across all returned rows. A proof
|
|
113
|
+
establishes how the bounded evaluator derived a tuple from the supplied bytes;
|
|
114
|
+
it does not establish that a proposition is true.
|
|
115
|
+
|
|
116
|
+
## Safe cached ingress
|
|
117
|
+
|
|
118
|
+
Projection declarations and cache output are untrusted exchange data. The
|
|
119
|
+
`parseOhProjectionRulePackV1`, `parseOhProjectionQueryV1`, and
|
|
120
|
+
`parseOhProjectionIdentityV1` parsers reject unknown keys and invalid digest
|
|
121
|
+
preimages. `parseOhProjectionProofV1` additionally applies the public proof
|
|
122
|
+
depth, node, tuple, source, atom-byte, and aggregate-byte ceilings before
|
|
123
|
+
returning a proof tree.
|
|
124
|
+
|
|
125
|
+
`parseOhProjectionResultV1` is the cache-ingress boundary. It verifies the
|
|
126
|
+
result digest; canonical row and source order; `supportCount`; proof-node,
|
|
127
|
+
work-unit, relation, match, round, and byte totals; every proof and result
|
|
128
|
+
truncation marker; and all declared evaluation ceilings. It also recomputes the
|
|
129
|
+
engine and evaluation digests and requires them to match the projection
|
|
130
|
+
identity. A valid SHA-256 string by itself is not enough to make an envelope
|
|
131
|
+
acceptable. Cache readers SHOULD pass the projection digest they requested as
|
|
132
|
+
the parser's second argument; an internally consistent envelope does not prove
|
|
133
|
+
that a cache returned the requested identity.
|
|
134
|
+
|
|
135
|
+
The discovery manifest publishes machine-readable schemas for rule packs,
|
|
136
|
+
queries, identities, and result envelopes. JSON Schema describes the exchange
|
|
137
|
+
shape and static maxima. The runtime parsers remain normative for canonical
|
|
138
|
+
ordering, digest preimages, aggregate budgets, and cross-field consistency that
|
|
139
|
+
the schemas cannot express.
|
|
140
|
+
|
|
141
|
+
## Cache invalidation
|
|
142
|
+
|
|
143
|
+
`projectionSha256` binds the current contract, snapshot, dataset, rule pack,
|
|
144
|
+
query, engine, resolved evaluation limits, and positive-Datalog semantics. A cached
|
|
145
|
+
result is reusable only when that digest is unchanged. Any snapshot, dataset,
|
|
146
|
+
rule-pack, query, engine, or evaluation-limit change has `kind: "full-rebuild"` and
|
|
147
|
+
lists the changed identities. V1 does not claim incremental deletion or
|
|
148
|
+
cross-snapshot maintenance.
|
|
149
|
+
|
|
150
|
+
## Optional Suss equivalence lane
|
|
151
|
+
|
|
152
|
+
`@hraness/oh/experimental/projection-suss` supports exactly
|
|
153
|
+
`@suss/datalog@0.20.0` as an optional peer. It encodes every JSON primitive atom
|
|
154
|
+
into canonical JSON text, evaluates the positive rules with Suss, and compares
|
|
155
|
+
every complete relation to the Oh reference semantics. It returns only after
|
|
156
|
+
exact set agreement.
|
|
157
|
+
|
|
158
|
+
Suss's public evaluator does not expose an execution-budget hook. Before calling
|
|
159
|
+
it, the adapter first runs the bounded reference evaluator, then computes a
|
|
160
|
+
conservative finite-domain upper bound on new tuples in rule-head relations and
|
|
161
|
+
refuses a program it cannot prove will remain under the requested derived-tuple
|
|
162
|
+
ceiling. It compares Suss's complete result to the reference materialization and
|
|
163
|
+
uses the reference witnesses for canonical proof construction. This lane
|
|
164
|
+
evaluates compatibility, not performance. Refusal does not disable the built-in
|
|
165
|
+
evaluator.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$defs": {
|
|
3
|
+
"jsonValue": {
|
|
4
|
+
"oneOf": [
|
|
5
|
+
{
|
|
6
|
+
"type": [
|
|
7
|
+
"null",
|
|
8
|
+
"boolean",
|
|
9
|
+
"number",
|
|
10
|
+
"string"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"items": {
|
|
15
|
+
"$ref": "#/$defs/jsonValue"
|
|
16
|
+
},
|
|
17
|
+
"type": "array"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"additionalProperties": {
|
|
21
|
+
"$ref": "#/$defs/jsonValue"
|
|
22
|
+
},
|
|
23
|
+
"type": "object"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"recordKey": {
|
|
28
|
+
"maxLength": 512,
|
|
29
|
+
"pattern": "^[a-z][a-z0-9]*(?:[._:/-][a-z0-9]+)*$",
|
|
30
|
+
"type": "string"
|
|
31
|
+
},
|
|
32
|
+
"sha256": {
|
|
33
|
+
"pattern": "^[a-f0-9]{64}$",
|
|
34
|
+
"type": "string"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"$id": "https://oh.computer/spec/v1/record.schema.json",
|
|
38
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
39
|
+
"$comment": "Runtime conformance additionally requires canonical UTF-8 JSON, strictly ordered unique dependencies, a non-reflexive dependency set, the 1 MiB value bound, and a recomputed recordSha256.",
|
|
40
|
+
"additionalProperties": false,
|
|
41
|
+
"properties": {
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"items": {
|
|
44
|
+
"$ref": "#/$defs/recordKey"
|
|
45
|
+
},
|
|
46
|
+
"maxItems": 4096,
|
|
47
|
+
"type": "array",
|
|
48
|
+
"uniqueItems": true
|
|
49
|
+
},
|
|
50
|
+
"key": {
|
|
51
|
+
"$ref": "#/$defs/recordKey"
|
|
52
|
+
},
|
|
53
|
+
"kind": {
|
|
54
|
+
"enum": [
|
|
55
|
+
"activity",
|
|
56
|
+
"assertion",
|
|
57
|
+
"context",
|
|
58
|
+
"dependency-manifest",
|
|
59
|
+
"edition",
|
|
60
|
+
"entity",
|
|
61
|
+
"evidence",
|
|
62
|
+
"identity-operation",
|
|
63
|
+
"inquiry",
|
|
64
|
+
"inquiry-event",
|
|
65
|
+
"review-decision",
|
|
66
|
+
"rights-decision",
|
|
67
|
+
"schema",
|
|
68
|
+
"shape",
|
|
69
|
+
"statement",
|
|
70
|
+
"type-membership",
|
|
71
|
+
"view",
|
|
72
|
+
"vocabulary"
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
"recordSha256": {
|
|
76
|
+
"$ref": "#/$defs/sha256"
|
|
77
|
+
},
|
|
78
|
+
"v": {
|
|
79
|
+
"const": 1
|
|
80
|
+
},
|
|
81
|
+
"value": {
|
|
82
|
+
"$ref": "#/$defs/jsonValue"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"required": [
|
|
86
|
+
"dependencies",
|
|
87
|
+
"key",
|
|
88
|
+
"kind",
|
|
89
|
+
"recordSha256",
|
|
90
|
+
"v",
|
|
91
|
+
"value"
|
|
92
|
+
],
|
|
93
|
+
"title": "Oh knowledge graph record V1",
|
|
94
|
+
"type": "object"
|
|
95
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Schema evolution V1
|
|
2
|
+
|
|
3
|
+
Oh stores product meaning as content-addressed schema and vocabulary records.
|
|
4
|
+
The envelope remains generic while each namespace owns the interpretation of
|
|
5
|
+
its concepts, predicates, shapes, mappings, units, and vocabularies.
|
|
6
|
+
|
|
7
|
+
## Schema identity
|
|
8
|
+
|
|
9
|
+
A schema revision has a stable `namespace`, `code`, and `kind`. V1 kinds are
|
|
10
|
+
`concept`, `mapping`, `predicate`, `shape`, `unit`, and `vocabulary`. A positive
|
|
11
|
+
revision and `schemaSha256` identify one immutable body.
|
|
12
|
+
|
|
13
|
+
The revision also includes:
|
|
14
|
+
|
|
15
|
+
- `body`, a canonical JSON object owned by the schema;
|
|
16
|
+
- nonempty, canonically ordered localized `labels` and `description` entries;
|
|
17
|
+
- `compatibility`, either `additive` or `breaking`; and
|
|
18
|
+
- `previousSchemaSha256`, which is null only for revision one.
|
|
19
|
+
|
|
20
|
+
Revision one MUST declare `additive`. Later revisions MUST advance by exactly
|
|
21
|
+
one and bind the immediately prior digest.
|
|
22
|
+
|
|
23
|
+
## Additive claims
|
|
24
|
+
|
|
25
|
+
An additive revision MUST retain every top-level key from the prior body with
|
|
26
|
+
the exact same canonical JSON value. It may add new top-level keys. Changing or
|
|
27
|
+
removing a prior value requires `breaking`.
|
|
28
|
+
|
|
29
|
+
This law is deliberately mechanical. It prevents a schema author from labeling
|
|
30
|
+
an incompatible byte change as additive. A domain may impose stricter semantic
|
|
31
|
+
compatibility rules in its codec.
|
|
32
|
+
|
|
33
|
+
## Vocabulary revisions
|
|
34
|
+
|
|
35
|
+
A vocabulary revision binds one namespace, positive revision, and no more than
|
|
36
|
+
65,536 schema references from that same namespace. References MUST be in
|
|
37
|
+
strict canonical order and unique. `vocabularySha256` hashes the payload
|
|
38
|
+
without the digest field.
|
|
39
|
+
|
|
40
|
+
## Evolution procedure
|
|
41
|
+
|
|
42
|
+
1. Parse and verify the prior immutable revision.
|
|
43
|
+
2. Create the next revision with the prior digest and the correct compatibility
|
|
44
|
+
classification.
|
|
45
|
+
3. Run the mechanical evolution check.
|
|
46
|
+
4. Publish the new schema record without rewriting the prior record.
|
|
47
|
+
5. Update dependent graph records explicitly when they adopt the new schema.
|
|
48
|
+
|
|
49
|
+
Schema revision is separate from Oh's envelope version. A breaking product
|
|
50
|
+
schema does not automatically require a new graph format, while a changed
|
|
51
|
+
graph field always does.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$defs": {
|
|
3
|
+
"jsonValue": {
|
|
4
|
+
"oneOf": [
|
|
5
|
+
{
|
|
6
|
+
"type": [
|
|
7
|
+
"null",
|
|
8
|
+
"boolean",
|
|
9
|
+
"number",
|
|
10
|
+
"string"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"items": {
|
|
15
|
+
"$ref": "#/$defs/jsonValue"
|
|
16
|
+
},
|
|
17
|
+
"type": "array"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"additionalProperties": {
|
|
21
|
+
"$ref": "#/$defs/jsonValue"
|
|
22
|
+
},
|
|
23
|
+
"type": "object"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"localizedText": {
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"properties": {
|
|
30
|
+
"language": {
|
|
31
|
+
"maxLength": 64,
|
|
32
|
+
"pattern": "^(?:und|[a-z]{2,3}(?:-[a-z0-9]{2,8})*)$",
|
|
33
|
+
"type": "string"
|
|
34
|
+
},
|
|
35
|
+
"text": {
|
|
36
|
+
"minLength": 1,
|
|
37
|
+
"type": "string"
|
|
38
|
+
},
|
|
39
|
+
"v": {
|
|
40
|
+
"const": 1
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"required": [
|
|
44
|
+
"language",
|
|
45
|
+
"text",
|
|
46
|
+
"v"
|
|
47
|
+
],
|
|
48
|
+
"type": "object"
|
|
49
|
+
},
|
|
50
|
+
"safeCode": {
|
|
51
|
+
"maxLength": 128,
|
|
52
|
+
"pattern": "^[a-z][a-z0-9]*(?:[._:/-][a-z0-9]+)*$",
|
|
53
|
+
"type": "string"
|
|
54
|
+
},
|
|
55
|
+
"sha256": {
|
|
56
|
+
"pattern": "^[a-f0-9]{64}$",
|
|
57
|
+
"type": "string"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"$id": "https://oh.computer/spec/v1/schema-revision.schema.json",
|
|
61
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
62
|
+
"$comment": "Runtime conformance additionally requires NFC bounded text, canonical ordering, unique localized values, canonical body JSON, and a recomputed schemaSha256.",
|
|
63
|
+
"additionalProperties": false,
|
|
64
|
+
"allOf": [
|
|
65
|
+
{
|
|
66
|
+
"else": {
|
|
67
|
+
"properties": {
|
|
68
|
+
"previousSchemaSha256": {
|
|
69
|
+
"$ref": "#/$defs/sha256"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"if": {
|
|
74
|
+
"properties": {
|
|
75
|
+
"revision": {
|
|
76
|
+
"const": 1
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"required": [
|
|
80
|
+
"revision"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"then": {
|
|
84
|
+
"properties": {
|
|
85
|
+
"compatibility": {
|
|
86
|
+
"const": "additive"
|
|
87
|
+
},
|
|
88
|
+
"previousSchemaSha256": {
|
|
89
|
+
"const": null
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"properties": {
|
|
96
|
+
"body": {
|
|
97
|
+
"additionalProperties": {
|
|
98
|
+
"$ref": "#/$defs/jsonValue"
|
|
99
|
+
},
|
|
100
|
+
"type": "object"
|
|
101
|
+
},
|
|
102
|
+
"code": {
|
|
103
|
+
"$ref": "#/$defs/safeCode"
|
|
104
|
+
},
|
|
105
|
+
"compatibility": {
|
|
106
|
+
"enum": [
|
|
107
|
+
"additive",
|
|
108
|
+
"breaking"
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
"description": {
|
|
112
|
+
"items": {
|
|
113
|
+
"$ref": "#/$defs/localizedText"
|
|
114
|
+
},
|
|
115
|
+
"maxItems": 128,
|
|
116
|
+
"minItems": 1,
|
|
117
|
+
"type": "array",
|
|
118
|
+
"uniqueItems": true
|
|
119
|
+
},
|
|
120
|
+
"kind": {
|
|
121
|
+
"enum": [
|
|
122
|
+
"concept",
|
|
123
|
+
"mapping",
|
|
124
|
+
"predicate",
|
|
125
|
+
"shape",
|
|
126
|
+
"unit",
|
|
127
|
+
"vocabulary"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"labels": {
|
|
131
|
+
"items": {
|
|
132
|
+
"$ref": "#/$defs/localizedText"
|
|
133
|
+
},
|
|
134
|
+
"maxItems": 128,
|
|
135
|
+
"minItems": 1,
|
|
136
|
+
"type": "array",
|
|
137
|
+
"uniqueItems": true
|
|
138
|
+
},
|
|
139
|
+
"namespace": {
|
|
140
|
+
"$ref": "#/$defs/safeCode"
|
|
141
|
+
},
|
|
142
|
+
"previousSchemaSha256": {
|
|
143
|
+
"anyOf": [
|
|
144
|
+
{
|
|
145
|
+
"type": "null"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"$ref": "#/$defs/sha256"
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
"revision": {
|
|
153
|
+
"minimum": 1,
|
|
154
|
+
"type": "integer"
|
|
155
|
+
},
|
|
156
|
+
"schemaSha256": {
|
|
157
|
+
"$ref": "#/$defs/sha256"
|
|
158
|
+
},
|
|
159
|
+
"v": {
|
|
160
|
+
"const": 1
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"required": [
|
|
164
|
+
"body",
|
|
165
|
+
"code",
|
|
166
|
+
"compatibility",
|
|
167
|
+
"description",
|
|
168
|
+
"kind",
|
|
169
|
+
"labels",
|
|
170
|
+
"namespace",
|
|
171
|
+
"previousSchemaSha256",
|
|
172
|
+
"revision",
|
|
173
|
+
"schemaSha256",
|
|
174
|
+
"v"
|
|
175
|
+
],
|
|
176
|
+
"title": "Oh knowledge schema revision V1",
|
|
177
|
+
"type": "object"
|
|
178
|
+
}
|