@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,121 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { canonicalJson, canonicalSha256 } from "./canonical";
|
|
4
|
+
import { OhRecordCodecRegistry } from "./contract";
|
|
5
|
+
import { createKnowledgeGraphRecordV1 } from "./graph";
|
|
6
|
+
import { createOhSqliteStoreAuthorityV1 } from "./sqlite/port";
|
|
7
|
+
import {
|
|
8
|
+
createOhDependencyClosureV1,
|
|
9
|
+
createOhStoreBindingV1,
|
|
10
|
+
createOhStoreProfileV1,
|
|
11
|
+
emptyOhHeadV1,
|
|
12
|
+
OH_WORKING_STORE_PROFILE_V1,
|
|
13
|
+
OhProfileError,
|
|
14
|
+
OhSemanticBundleIngressV1,
|
|
15
|
+
parseOhDependencyClosureV1,
|
|
16
|
+
parseOhStoreBindingV1,
|
|
17
|
+
replayOhOperationsV1,
|
|
18
|
+
transitionOhSnapshotV1,
|
|
19
|
+
verifyOhDependencyClosureV1,
|
|
20
|
+
verifyOhDependencyClosureAgainstV1,
|
|
21
|
+
} from "./store";
|
|
22
|
+
|
|
23
|
+
describe("runtime-neutral Oh store contracts", () => {
|
|
24
|
+
test("binds a host-selected realm and application profile without changing V1 operations", () => {
|
|
25
|
+
const applicationProfileSha256 = canonicalSha256({ application: "fixture", v: 1 });
|
|
26
|
+
const profile = createOhStoreProfileV1({
|
|
27
|
+
applicationProfileSha256,
|
|
28
|
+
capabilities: OH_WORKING_STORE_PROFILE_V1.capabilities,
|
|
29
|
+
profileId: "fixture.working.v1",
|
|
30
|
+
profileKind: "working",
|
|
31
|
+
v: 1,
|
|
32
|
+
});
|
|
33
|
+
const binding = createOhStoreBindingV1({ profile, realmId: "tenant:one/thread:two",
|
|
34
|
+
spaceId: "thread:two", v: 1 });
|
|
35
|
+
expect(parseOhStoreBindingV1(binding)).toEqual(binding);
|
|
36
|
+
expect(binding.profile.applicationProfileSha256).toBe(applicationProfileSha256);
|
|
37
|
+
expect(binding.bindingSha256).toBe(canonicalSha256({ contractSha256: binding.contractSha256,
|
|
38
|
+
profile, realmId: binding.realmId, spaceId: binding.spaceId, v: 1 }));
|
|
39
|
+
expect(() => createOhStoreProfileV1({ applicationProfileSha256: null,
|
|
40
|
+
capabilities: { ...OH_WORKING_STORE_PROFILE_V1.capabilities, operationReplication: true },
|
|
41
|
+
profileId: "unsafe.working.v1", profileKind: "working", v: 1 })).toThrow(OhProfileError);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("exports only an exact dependency closure and detects tampering or smuggled records", () => {
|
|
45
|
+
const parent = createKnowledgeGraphRecordV1({ dependencies: [], key: "entity:parent",
|
|
46
|
+
kind: "entity", v: 1, value: { name: "Parent" } });
|
|
47
|
+
const child = createKnowledgeGraphRecordV1({ dependencies: [parent.key], key: "entity:child",
|
|
48
|
+
kind: "entity", v: 1, value: { name: "Child" } });
|
|
49
|
+
const unrelated = createKnowledgeGraphRecordV1({ dependencies: [], key: "entity:unrelated",
|
|
50
|
+
kind: "entity", v: 1, value: { name: "Unrelated" } });
|
|
51
|
+
const binding = createOhStoreBindingV1({ profile: OH_WORKING_STORE_PROFILE_V1,
|
|
52
|
+
realmId: "realm:test", spaceId: "space:test", v: 1 });
|
|
53
|
+
const first = replayOhOperationsV1(binding.spaceId, []);
|
|
54
|
+
const snapshot = transitionOhSnapshotV1({ actorId: "agent.test", changes: [
|
|
55
|
+
{ kind: "put", record: child, v: 1 }, { kind: "put", record: parent, v: 1 },
|
|
56
|
+
{ kind: "put", record: unrelated, v: 1 },
|
|
57
|
+
], instant: "2026-08-29T12:00:00.000Z", operationId: "op_closure",
|
|
58
|
+
snapshot: first, spaceId: binding.spaceId }).snapshot;
|
|
59
|
+
const closure = createOhDependencyClosureV1({ binding, roots: [child.key],
|
|
60
|
+
snapshot });
|
|
61
|
+
expect(closure.records.map(({ key }) => key)).toEqual([child.key, parent.key].sort());
|
|
62
|
+
expect(parseOhDependencyClosureV1(closure)).toEqual(closure);
|
|
63
|
+
expect(verifyOhDependencyClosureV1(closure)).toEqual({ closure, ok: true });
|
|
64
|
+
expect(verifyOhDependencyClosureAgainstV1(closure, { binding, head: snapshot.head }))
|
|
65
|
+
.toEqual({ closure, ok: true, verification: "expected-authority-and-head" });
|
|
66
|
+
expect(verifyOhDependencyClosureAgainstV1(closure, { binding,
|
|
67
|
+
head: { ...snapshot.head, recordsSha256: "a".repeat(64) as typeof snapshot.head.recordsSha256 } }))
|
|
68
|
+
.toEqual({ ok: false, reason: "head-mismatch" });
|
|
69
|
+
expect(parseOhDependencyClosureV1({ ...closure, records: [...closure.records, unrelated] })).toBeNull();
|
|
70
|
+
expect(parseOhDependencyClosureV1({ ...closure,
|
|
71
|
+
closureSha256: "a".repeat(64) })).toBeNull();
|
|
72
|
+
expect(first.records).toEqual([]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("requires a sealed explicit codec for every semantic put and commits one atomic bundle", async () => {
|
|
76
|
+
const authority = createOhSqliteStoreAuthorityV1({ path: ":memory:",
|
|
77
|
+
profile: OH_WORKING_STORE_PROFILE_V1, realmId: "realm:semantic", spaceId: "semantic" });
|
|
78
|
+
const codecs = new OhRecordCodecRegistry().register({ kind: "entity", parse: (value) => {
|
|
79
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)
|
|
80
|
+
|| Object.keys(value).length !== 1 || typeof (value as { name?: unknown }).name !== "string") return null;
|
|
81
|
+
return { name: (value as { name: string }).name.normalize("NFC") };
|
|
82
|
+
} });
|
|
83
|
+
const ingress = new OhSemanticBundleIngressV1(authority.store, codecs);
|
|
84
|
+
expect(codecs.sealed).toBe(true);
|
|
85
|
+
expect(() => codecs.register({ kind: "statement", parse: () => ({}) })).toThrow("sealed");
|
|
86
|
+
const head = await authority.store.head();
|
|
87
|
+
const operation = await ingress.commit({ actorId: "agent.test", expectedHead: {
|
|
88
|
+
generation: head.generation, operationSha256: head.operationSha256 }, instant: "2026-08-29T12:00:00.000Z",
|
|
89
|
+
operationId: "op_semantic", puts: [{ dependencies: [], key: "entity:ada", kind: "entity",
|
|
90
|
+
v: 1, value: { name: "Ada" } }], tombstones: [], v: 1 });
|
|
91
|
+
expect(operation.changes).toHaveLength(1);
|
|
92
|
+
await expect(ingress.commit({ actorId: "agent.test", expectedHead: {
|
|
93
|
+
generation: 1, operationSha256: operation.operationSha256 }, instant: null,
|
|
94
|
+
operationId: "op_unregistered", puts: [{ dependencies: [], key: "statement:no-codec",
|
|
95
|
+
kind: "statement", v: 1, value: {} }], tombstones: [], v: 1 }))
|
|
96
|
+
.rejects.toThrow("codec rejected");
|
|
97
|
+
expect((await authority.store.head()).sequence).toBe(1);
|
|
98
|
+
await expect(ingress.commit({ actorId: "agent.test", expectedHead: {
|
|
99
|
+
generation: 1, operationSha256: operation.operationSha256 }, instant: null,
|
|
100
|
+
operationId: "op_missing_dependency", puts: [{ dependencies: ["entity:missing"],
|
|
101
|
+
key: "entity:child", kind: "entity", v: 1, value: { name: "Child" } }],
|
|
102
|
+
tombstones: [], v: 1 })).rejects.toThrow("Missing dependency");
|
|
103
|
+
expect((await authority.store.head()).sequence).toBe(1);
|
|
104
|
+
expect(canonicalJson((await authority.store.snapshot()).records[0]?.value)).toBe('{"name":"Ada"}');
|
|
105
|
+
await authority.store.close();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("rejects duplicate operation IDs during generic replay", () => {
|
|
109
|
+
const first = transitionOhSnapshotV1({ actorId: "agent.test",
|
|
110
|
+
changes: [{ kind: "put", record: createKnowledgeGraphRecordV1({ dependencies: [],
|
|
111
|
+
key: "entity:first", kind: "entity", v: 1, value: { name: "First" } }), v: 1 }],
|
|
112
|
+
instant: "2026-08-29T12:00:00.000Z", operationId: "op_duplicate",
|
|
113
|
+
snapshot: { head: emptyOhHeadV1(), records: [], v: 1 }, spaceId: "duplicate" });
|
|
114
|
+
const second = transitionOhSnapshotV1({ actorId: "agent.test",
|
|
115
|
+
changes: [{ kind: "put", record: createKnowledgeGraphRecordV1({ dependencies: [],
|
|
116
|
+
key: "entity:second", kind: "entity", v: 1, value: { name: "Second" } }), v: 1 }],
|
|
117
|
+
instant: "2026-08-29T12:01:00.000Z", operationId: "op_duplicate",
|
|
118
|
+
snapshot: first.snapshot, spaceId: "duplicate" });
|
|
119
|
+
expect(() => replayOhOperationsV1("duplicate", [first.operation, second.operation])).toThrow("replay chain");
|
|
120
|
+
});
|
|
121
|
+
});
|