@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.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +598 -0
  3. package/dist/canonical.d.ts +32 -0
  4. package/dist/canonical.d.ts.map +1 -0
  5. package/dist/cli.d.ts +4 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +3419 -0
  8. package/dist/contract.d.ts +33 -0
  9. package/dist/contract.d.ts.map +1 -0
  10. package/dist/graph.d.ts +67 -0
  11. package/dist/graph.d.ts.map +1 -0
  12. package/dist/index.d.ts +9 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +1988 -0
  15. package/dist/libsql.d.ts +57 -0
  16. package/dist/libsql.d.ts.map +1 -0
  17. package/dist/libsql.js +2662 -0
  18. package/dist/memory.d.ts +366 -0
  19. package/dist/memory.d.ts.map +1 -0
  20. package/dist/memory.js +3650 -0
  21. package/dist/ontology.d.ts +242 -0
  22. package/dist/ontology.d.ts.map +1 -0
  23. package/dist/operation.d.ts +24 -0
  24. package/dist/operation.d.ts.map +1 -0
  25. package/dist/projection-public.d.ts +59 -0
  26. package/dist/projection-public.d.ts.map +1 -0
  27. package/dist/projection-public.js +1682 -0
  28. package/dist/projection-suss.d.ts +17 -0
  29. package/dist/projection-suss.d.ts.map +1 -0
  30. package/dist/projection-suss.js +1721 -0
  31. package/dist/projection.d.ts +315 -0
  32. package/dist/projection.d.ts.map +1 -0
  33. package/dist/schema.d.ts +45 -0
  34. package/dist/schema.d.ts.map +1 -0
  35. package/dist/sdk.d.ts +51 -0
  36. package/dist/sdk.d.ts.map +1 -0
  37. package/dist/sdk.js +3072 -0
  38. package/dist/search.d.ts +34 -0
  39. package/dist/search.d.ts.map +1 -0
  40. package/dist/semantic.d.ts +83 -0
  41. package/dist/semantic.d.ts.map +1 -0
  42. package/dist/semantic.js +706 -0
  43. package/dist/sqlite/driver.d.ts +6 -0
  44. package/dist/sqlite/driver.d.ts.map +1 -0
  45. package/dist/sqlite/index.d.ts +5 -0
  46. package/dist/sqlite/index.d.ts.map +1 -0
  47. package/dist/sqlite/index.js +2840 -0
  48. package/dist/sqlite/migrations.d.ts +10 -0
  49. package/dist/sqlite/migrations.d.ts.map +1 -0
  50. package/dist/sqlite/port.d.ts +40 -0
  51. package/dist/sqlite/port.d.ts.map +1 -0
  52. package/dist/sqlite/runtime.d.ts +23 -0
  53. package/dist/sqlite/runtime.d.ts.map +1 -0
  54. package/dist/sqlite/store.d.ts +85 -0
  55. package/dist/sqlite/store.d.ts.map +1 -0
  56. package/dist/store.d.ts +236 -0
  57. package/dist/store.d.ts.map +1 -0
  58. package/dist/store.js +996 -0
  59. package/dist/sync.d.ts +57 -0
  60. package/dist/sync.d.ts.map +1 -0
  61. package/dist/sync.js +1328 -0
  62. package/package.json +121 -0
  63. package/skills/oh/SKILL.md +206 -0
  64. package/skills/oh/agents/openai.yaml +4 -0
  65. package/spec/README.md +74 -0
  66. package/spec/manifest.json +41 -0
  67. package/spec/v1/canonical-json.md +59 -0
  68. package/spec/v1/contract.json +28 -0
  69. package/spec/v1/contract.schema.json +58 -0
  70. package/spec/v1/embedding-profile.json +11 -0
  71. package/spec/v1/embedding.md +56 -0
  72. package/spec/v1/graph.md +87 -0
  73. package/spec/v1/memory.md +193 -0
  74. package/spec/v1/migration.md +92 -0
  75. package/spec/v1/ontology.json +55 -0
  76. package/spec/v1/ontology.md +80 -0
  77. package/spec/v1/operation.schema.json +138 -0
  78. package/spec/v1/projection-identity.schema.json +58 -0
  79. package/spec/v1/projection-query.schema.json +60 -0
  80. package/spec/v1/projection-result.schema.json +452 -0
  81. package/spec/v1/projection-rule-pack.schema.json +182 -0
  82. package/spec/v1/projection.md +165 -0
  83. package/spec/v1/record.schema.json +95 -0
  84. package/spec/v1/schema-evolution.md +51 -0
  85. package/spec/v1/schema-revision.schema.json +178 -0
  86. package/spec/v1/storage.md +88 -0
  87. package/spec/v1/store.md +131 -0
  88. package/spec/v1/sync-bundle.schema.json +51 -0
  89. package/spec/v1/sync.md +67 -0
  90. package/src/canonical.test.ts +46 -0
  91. package/src/canonical.ts +203 -0
  92. package/src/cli.test.ts +103 -0
  93. package/src/cli.ts +308 -0
  94. package/src/contract.ts +87 -0
  95. package/src/contracts.test.ts +147 -0
  96. package/src/graph.ts +248 -0
  97. package/src/index.ts +8 -0
  98. package/src/libsql.test.ts +657 -0
  99. package/src/libsql.ts +1687 -0
  100. package/src/memory.test.ts +783 -0
  101. package/src/memory.ts +1684 -0
  102. package/src/ontology.ts +573 -0
  103. package/src/operation.ts +80 -0
  104. package/src/projection-public.ts +53 -0
  105. package/src/projection-suss.ts +129 -0
  106. package/src/projection.test.ts +418 -0
  107. package/src/projection.ts +1457 -0
  108. package/src/schema.ts +156 -0
  109. package/src/sdk.ts +96 -0
  110. package/src/search.ts +66 -0
  111. package/src/semantic.test.ts +480 -0
  112. package/src/semantic.ts +333 -0
  113. package/src/sqlite/driver.ts +47 -0
  114. package/src/sqlite/index.ts +4 -0
  115. package/src/sqlite/migrations.test.ts +44 -0
  116. package/src/sqlite/migrations.ts +178 -0
  117. package/src/sqlite/port.test.ts +127 -0
  118. package/src/sqlite/port.ts +120 -0
  119. package/src/sqlite/runtime.test.ts +68 -0
  120. package/src/sqlite/runtime.ts +53 -0
  121. package/src/sqlite/store.test.ts +295 -0
  122. package/src/sqlite/store.ts +988 -0
  123. package/src/store.test.ts +121 -0
  124. package/src/store.ts +701 -0
  125. package/src/sync.test.ts +117 -0
  126. 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
+ });