@hraness/oh 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -21
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/libsql-semantic-v2.d.ts +160 -0
- package/dist/libsql-semantic-v2.d.ts.map +1 -0
- package/dist/libsql-semantic.d.ts +19 -0
- package/dist/libsql-semantic.d.ts.map +1 -1
- package/dist/semantic-cloud.d.ts +1 -0
- package/dist/semantic-cloud.d.ts.map +1 -1
- package/dist/semantic-cloud.js +1570 -0
- package/package.json +1 -1
- package/skills/oh/SKILL.md +2 -2
- package/spec/README.md +8 -1
- package/spec/manifest.json +5 -1
- package/spec/v1/libsql-semantic-cache-schema-v1.sql +114 -0
- package/spec/v1/libsql-semantic-digest-fixture-v1.json +13 -0
- package/spec/v1/semantic-cloud.md +9 -0
- package/spec/v2/libsql-semantic-cache-schema-v2.sql +175 -0
- package/spec/v2/libsql-semantic-digest-fixture-v2.json +14 -0
- package/spec/v2/manifest.json +11 -0
- package/spec/v2/semantic-cloud.md +106 -0
- package/src/cli.ts +1 -1
- package/src/libsql-semantic-v2.test.ts +1114 -0
- package/src/libsql-semantic-v2.ts +1891 -0
- package/src/libsql-semantic.test.ts +157 -1
- package/src/libsql-semantic.ts +51 -0
- package/src/semantic-cloud.ts +1 -0
package/package.json
CHANGED
package/skills/oh/SKILL.md
CHANGED
|
@@ -30,8 +30,8 @@ oh --help
|
|
|
30
30
|
oh version
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
The supported CLI is the exact npm release `@hraness/oh@0.3.
|
|
34
|
-
tarball and checksum are mirrored by the immutable GitHub Release `v0.3.
|
|
33
|
+
The supported CLI is the exact npm release `@hraness/oh@0.3.2`. Its identical
|
|
34
|
+
tarball and checksum are mirrored by the immutable GitHub Release `v0.3.2`.
|
|
35
35
|
It requires Bun 1.3.14 or newer. The versioned contract is published at
|
|
36
36
|
<https://oh.computer/spec/>.
|
|
37
37
|
|
package/spec/README.md
CHANGED
|
@@ -18,7 +18,8 @@ binds these versions:
|
|
|
18
18
|
| SQLite schema | `2` |
|
|
19
19
|
| Sync protocol | `oh.sync.v1` |
|
|
20
20
|
| Local embedding profile | `1` |
|
|
21
|
-
| Hosted semantic cache | `oh.cloudflare.embeddinggemma.v1` |
|
|
21
|
+
| Hosted semantic cache V1 | `oh.cloudflare.embeddinggemma.v1` |
|
|
22
|
+
| Hosted semantic cache V2 | `oh.semantic-cloud.v2` |
|
|
22
23
|
| Projection semantics | `oh.projection.positive-datalog.v1` |
|
|
23
24
|
| Composite memory | `experimental v1` |
|
|
24
25
|
| Memory page | `oh.memory-page.v1` |
|
|
@@ -34,6 +35,7 @@ binds these versions:
|
|
|
34
35
|
- [Sync protocol](v1/sync.md)
|
|
35
36
|
- [Local embedding profile](v1/embedding.md)
|
|
36
37
|
- [Hosted semantic cache](v1/semantic-cloud.md)
|
|
38
|
+
- [Isolated hosted semantic cache V2](v2/semantic-cloud.md)
|
|
37
39
|
- [Derived projections](v1/projection.md)
|
|
38
40
|
- [Experimental composite agent memory](v1/memory.md)
|
|
39
41
|
- [Memory pages and `.oh.md` interchange](v1/memory-page.md)
|
|
@@ -46,6 +48,11 @@ Machine-readable V1 artifacts:
|
|
|
46
48
|
- [`embedding-profile.json`](v1/embedding-profile.json)
|
|
47
49
|
- [`cloudflare-embedding-profile.json`](v1/cloudflare-embedding-profile.json)
|
|
48
50
|
- [`cloudflare-embedding-renderer.json`](v1/cloudflare-embedding-renderer.json)
|
|
51
|
+
- [`libsql-semantic-cache-schema-v1.sql`](v1/libsql-semantic-cache-schema-v1.sql)
|
|
52
|
+
- [`libsql-semantic-digest-fixture-v1.json`](v1/libsql-semantic-digest-fixture-v1.json)
|
|
53
|
+
- [`semantic-cloud V2 manifest`](v2/manifest.json)
|
|
54
|
+
- [`libsql-semantic-cache-schema-v2.sql`](v2/libsql-semantic-cache-schema-v2.sql)
|
|
55
|
+
- [`libsql-semantic-digest-fixture-v2.json`](v2/libsql-semantic-digest-fixture-v2.json)
|
|
49
56
|
- [`contract.schema.json`](v1/contract.schema.json)
|
|
50
57
|
- [`record.schema.json`](v1/record.schema.json)
|
|
51
58
|
- [`schema-revision.schema.json`](v1/schema-revision.schema.json)
|
package/spec/manifest.json
CHANGED
|
@@ -25,9 +25,13 @@
|
|
|
25
25
|
"specification": "./v1/projection.md"
|
|
26
26
|
},
|
|
27
27
|
"semanticCloud": {
|
|
28
|
+
"cacheSchema": "./v1/libsql-semantic-cache-schema-v1.sql",
|
|
29
|
+
"cacheSchemaSha256": "d9903735e900e08a8c49c9ad36ea8f277b1689117ef88b9a2c6b906456dfbace",
|
|
30
|
+
"digestFixture": "./v1/libsql-semantic-digest-fixture-v1.json",
|
|
28
31
|
"profile": "./v1/cloudflare-embedding-profile.json",
|
|
29
32
|
"renderer": "./v1/cloudflare-embedding-renderer.json",
|
|
30
|
-
"specification": "./v1/semantic-cloud.md"
|
|
33
|
+
"specification": "./v1/semantic-cloud.md",
|
|
34
|
+
"successor": "./v2/manifest.json"
|
|
31
35
|
},
|
|
32
36
|
"schemas": [
|
|
33
37
|
"./v1/contract.schema.json",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_schemas (
|
|
2
|
+
version INTEGER PRIMARY KEY,
|
|
3
|
+
name TEXT NOT NULL UNIQUE,
|
|
4
|
+
schema_sha256 TEXT NOT NULL,
|
|
5
|
+
applied_at TEXT NOT NULL
|
|
6
|
+
) STRICT;
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_vectors (
|
|
9
|
+
profile_sha256 TEXT NOT NULL,
|
|
10
|
+
renderer_sha256 TEXT NOT NULL,
|
|
11
|
+
input_sha256 TEXT NOT NULL,
|
|
12
|
+
vector_sha256 TEXT NOT NULL,
|
|
13
|
+
vector BLOB NOT NULL,
|
|
14
|
+
created_at TEXT NOT NULL,
|
|
15
|
+
PRIMARY KEY(profile_sha256, renderer_sha256, input_sha256)
|
|
16
|
+
) STRICT;
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_generations (
|
|
19
|
+
authority_id TEXT NOT NULL,
|
|
20
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
21
|
+
authority_sha256 TEXT NOT NULL,
|
|
22
|
+
profile_sha256 TEXT NOT NULL,
|
|
23
|
+
renderer_sha256 TEXT NOT NULL,
|
|
24
|
+
membership_sha256 TEXT NOT NULL,
|
|
25
|
+
generation_sha256 TEXT NOT NULL UNIQUE,
|
|
26
|
+
document_count INTEGER NOT NULL CHECK(document_count >= 0),
|
|
27
|
+
chunk_count INTEGER NOT NULL CHECK(chunk_count >= 0),
|
|
28
|
+
created_at TEXT NOT NULL,
|
|
29
|
+
PRIMARY KEY(authority_id, generation)
|
|
30
|
+
) STRICT;
|
|
31
|
+
|
|
32
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_memberships (
|
|
33
|
+
authority_id TEXT NOT NULL,
|
|
34
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
35
|
+
generation_sha256 TEXT NOT NULL,
|
|
36
|
+
record_key TEXT NOT NULL,
|
|
37
|
+
record_sha256 TEXT NOT NULL,
|
|
38
|
+
ordinal INTEGER NOT NULL CHECK(ordinal >= 0),
|
|
39
|
+
input_sha256 TEXT NOT NULL,
|
|
40
|
+
PRIMARY KEY(authority_id, generation, record_key, ordinal)
|
|
41
|
+
) STRICT;
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_heads (
|
|
44
|
+
authority_id TEXT PRIMARY KEY,
|
|
45
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
46
|
+
authority_sha256 TEXT NOT NULL,
|
|
47
|
+
profile_sha256 TEXT NOT NULL,
|
|
48
|
+
renderer_sha256 TEXT NOT NULL,
|
|
49
|
+
membership_sha256 TEXT NOT NULL,
|
|
50
|
+
generation_sha256 TEXT NOT NULL,
|
|
51
|
+
published_at TEXT NOT NULL
|
|
52
|
+
) STRICT;
|
|
53
|
+
|
|
54
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_purges (
|
|
55
|
+
authority_id TEXT PRIMARY KEY,
|
|
56
|
+
purged_at TEXT NOT NULL
|
|
57
|
+
) STRICT;
|
|
58
|
+
|
|
59
|
+
CREATE INDEX IF NOT EXISTS oh_semantic_memberships_generation
|
|
60
|
+
ON oh_semantic_memberships(authority_id, generation, record_key, ordinal);
|
|
61
|
+
|
|
62
|
+
CREATE INDEX IF NOT EXISTS oh_semantic_memberships_input
|
|
63
|
+
ON oh_semantic_memberships(input_sha256);
|
|
64
|
+
|
|
65
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_vectors_no_update
|
|
66
|
+
BEFORE UPDATE ON oh_semantic_vectors
|
|
67
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic vectors are immutable'); END;
|
|
68
|
+
|
|
69
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_generations_no_update
|
|
70
|
+
BEFORE UPDATE ON oh_semantic_generations
|
|
71
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic generations are immutable'); END;
|
|
72
|
+
|
|
73
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_no_update
|
|
74
|
+
BEFORE UPDATE ON oh_semantic_memberships
|
|
75
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic memberships are immutable'); END;
|
|
76
|
+
|
|
77
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_generations_purge_guard
|
|
78
|
+
BEFORE INSERT ON oh_semantic_generations
|
|
79
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
80
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority was purged'); END;
|
|
81
|
+
|
|
82
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_purge_guard
|
|
83
|
+
BEFORE INSERT ON oh_semantic_memberships
|
|
84
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
85
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority was purged'); END;
|
|
86
|
+
|
|
87
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_published_guard
|
|
88
|
+
BEFORE INSERT ON oh_semantic_memberships
|
|
89
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_heads
|
|
90
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation)
|
|
91
|
+
AND NOT EXISTS (SELECT 1 FROM oh_semantic_memberships
|
|
92
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation
|
|
93
|
+
AND generation_sha256 = NEW.generation_sha256
|
|
94
|
+
AND record_key = NEW.record_key AND record_sha256 = NEW.record_sha256
|
|
95
|
+
AND ordinal = NEW.ordinal AND input_sha256 = NEW.input_sha256)
|
|
96
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic generation is published'); END;
|
|
97
|
+
|
|
98
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_heads_insert_purge_guard
|
|
99
|
+
BEFORE INSERT ON oh_semantic_heads
|
|
100
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
101
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority was purged'); END;
|
|
102
|
+
|
|
103
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_heads_update_purge_guard
|
|
104
|
+
BEFORE UPDATE ON oh_semantic_heads
|
|
105
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
106
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority was purged'); END;
|
|
107
|
+
|
|
108
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_purges_no_update
|
|
109
|
+
BEFORE UPDATE ON oh_semantic_purges
|
|
110
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic purge markers are immutable'); END;
|
|
111
|
+
|
|
112
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_purges_no_delete
|
|
113
|
+
BEFORE DELETE ON oh_semantic_purges
|
|
114
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic purge markers are immutable'); END;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"authorityId": "fixture:semantic-authority",
|
|
3
|
+
"authoritySha256": "d1eac8dd93ce6e04cb1316c670008250b98ec32cb0555f21d10b782ddffe03a7",
|
|
4
|
+
"content": "fixture body",
|
|
5
|
+
"generation": 7,
|
|
6
|
+
"generationSha256": "d2beeb0082da8ae3545ade90642a6366ecb209a673dbbbed350a6fec9b1157e3",
|
|
7
|
+
"inputSha256": "b2309e89dd3f903934c7b5f4a4c8c51d5323d84a66928a2f017dd871492ef294",
|
|
8
|
+
"membershipSha256": "34f1d2be0152f5626824a5b62ab75771ee906e3abf6b7159b3dfc348a23bdfbc",
|
|
9
|
+
"recordKey": "memory:fixture",
|
|
10
|
+
"recordSha256": "920d936e47e8f3cc5847017da5975ef73f8d84c04cb113880fb10575eeb614f9",
|
|
11
|
+
"title": "fixture title",
|
|
12
|
+
"v": 1
|
|
13
|
+
}
|
|
@@ -68,6 +68,15 @@ hit is rejoined to a caller-supplied current authority record digest. A stale
|
|
|
68
68
|
head, changed authority digest, changed record digest, concurrent publish, or
|
|
69
69
|
purge returns no stale authority.
|
|
70
70
|
|
|
71
|
+
`publishedHead` returns the current compare-and-swap base or `null` for an
|
|
72
|
+
absent or purged authority. Its bounded projection contains only the authority,
|
|
73
|
+
generation, profile, renderer, membership, generation and publication
|
|
74
|
+
identities already held by the cache; it exposes no vector, record body or
|
|
75
|
+
formatted input. The read verifies that the pointer still matches its immutable
|
|
76
|
+
generation and fails with an integrity error on divergence. A host can read the
|
|
77
|
+
base, stage a later authoritative generation, and pass the returned generation
|
|
78
|
+
to `publish` without keeping a second cache pointer elsewhere.
|
|
79
|
+
|
|
71
80
|
`purgeAuthority` writes a permanent tombstone, removes the head, memberships,
|
|
72
81
|
and staged generations, then deletes vectors no remaining authority uses. The
|
|
73
82
|
tombstone prevents the same authority ID from being staged or published again.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_schemas (
|
|
2
|
+
version INTEGER PRIMARY KEY,
|
|
3
|
+
name TEXT NOT NULL UNIQUE,
|
|
4
|
+
schema_sha256 TEXT NOT NULL,
|
|
5
|
+
applied_at TEXT NOT NULL
|
|
6
|
+
) STRICT;
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_isolations (
|
|
9
|
+
isolation_sha256 TEXT PRIMARY KEY,
|
|
10
|
+
authority_id TEXT NOT NULL,
|
|
11
|
+
created_at TEXT NOT NULL
|
|
12
|
+
) STRICT;
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_vectors (
|
|
15
|
+
isolation_sha256 TEXT NOT NULL,
|
|
16
|
+
profile_sha256 TEXT NOT NULL,
|
|
17
|
+
renderer_sha256 TEXT NOT NULL,
|
|
18
|
+
input_sha256 TEXT NOT NULL,
|
|
19
|
+
vector_sha256 TEXT NOT NULL,
|
|
20
|
+
vector BLOB NOT NULL,
|
|
21
|
+
created_at TEXT NOT NULL,
|
|
22
|
+
PRIMARY KEY(isolation_sha256, profile_sha256, renderer_sha256, input_sha256)
|
|
23
|
+
) STRICT;
|
|
24
|
+
|
|
25
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_generations (
|
|
26
|
+
authority_id TEXT NOT NULL,
|
|
27
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
28
|
+
authority_sha256 TEXT NOT NULL,
|
|
29
|
+
isolation_sha256 TEXT NOT NULL,
|
|
30
|
+
profile_sha256 TEXT NOT NULL,
|
|
31
|
+
renderer_sha256 TEXT NOT NULL,
|
|
32
|
+
membership_sha256 TEXT NOT NULL,
|
|
33
|
+
generation_sha256 TEXT NOT NULL UNIQUE,
|
|
34
|
+
document_count INTEGER NOT NULL CHECK(document_count >= 0),
|
|
35
|
+
chunk_count INTEGER NOT NULL CHECK(chunk_count >= 0),
|
|
36
|
+
created_at TEXT NOT NULL,
|
|
37
|
+
PRIMARY KEY(authority_id, generation)
|
|
38
|
+
) STRICT;
|
|
39
|
+
|
|
40
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_memberships (
|
|
41
|
+
authority_id TEXT NOT NULL,
|
|
42
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
43
|
+
generation_sha256 TEXT NOT NULL,
|
|
44
|
+
isolation_sha256 TEXT NOT NULL,
|
|
45
|
+
record_key TEXT NOT NULL,
|
|
46
|
+
record_sha256 TEXT NOT NULL,
|
|
47
|
+
ordinal INTEGER NOT NULL CHECK(ordinal >= 0),
|
|
48
|
+
input_sha256 TEXT NOT NULL,
|
|
49
|
+
PRIMARY KEY(authority_id, generation, record_key, ordinal)
|
|
50
|
+
) STRICT;
|
|
51
|
+
|
|
52
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_heads (
|
|
53
|
+
authority_id TEXT PRIMARY KEY,
|
|
54
|
+
generation INTEGER NOT NULL CHECK(generation >= 0),
|
|
55
|
+
authority_sha256 TEXT NOT NULL,
|
|
56
|
+
isolation_sha256 TEXT NOT NULL,
|
|
57
|
+
profile_sha256 TEXT NOT NULL,
|
|
58
|
+
renderer_sha256 TEXT NOT NULL,
|
|
59
|
+
membership_sha256 TEXT NOT NULL,
|
|
60
|
+
generation_sha256 TEXT NOT NULL,
|
|
61
|
+
published_at TEXT NOT NULL
|
|
62
|
+
) STRICT;
|
|
63
|
+
|
|
64
|
+
CREATE TABLE IF NOT EXISTS oh_semantic_purges (
|
|
65
|
+
authority_id TEXT PRIMARY KEY,
|
|
66
|
+
isolation_sha256 TEXT NOT NULL,
|
|
67
|
+
profile_sha256 TEXT NOT NULL,
|
|
68
|
+
published_generation INTEGER CHECK(published_generation IS NULL OR published_generation >= 0),
|
|
69
|
+
published_generation_sha256 TEXT,
|
|
70
|
+
purged_at TEXT NOT NULL,
|
|
71
|
+
purge_marker_sha256 TEXT NOT NULL,
|
|
72
|
+
generation_count INTEGER NOT NULL CHECK(generation_count >= 0),
|
|
73
|
+
membership_count INTEGER NOT NULL CHECK(membership_count >= 0),
|
|
74
|
+
orphan_vector_count INTEGER NOT NULL CHECK(orphan_vector_count >= 0),
|
|
75
|
+
isolation_scope_count INTEGER NOT NULL CHECK(isolation_scope_count >= 0),
|
|
76
|
+
counts_recorded INTEGER NOT NULL CHECK(counts_recorded IN (0, 1))
|
|
77
|
+
) STRICT;
|
|
78
|
+
|
|
79
|
+
CREATE INDEX IF NOT EXISTS oh_semantic_isolations_authority
|
|
80
|
+
ON oh_semantic_isolations(authority_id, isolation_sha256);
|
|
81
|
+
|
|
82
|
+
CREATE INDEX IF NOT EXISTS oh_semantic_memberships_generation
|
|
83
|
+
ON oh_semantic_memberships(authority_id, generation, record_key, ordinal);
|
|
84
|
+
|
|
85
|
+
CREATE INDEX IF NOT EXISTS oh_semantic_memberships_input
|
|
86
|
+
ON oh_semantic_memberships(isolation_sha256, input_sha256);
|
|
87
|
+
|
|
88
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_isolations_no_update
|
|
89
|
+
BEFORE UPDATE ON oh_semantic_isolations
|
|
90
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic isolations are immutable'); END;
|
|
91
|
+
|
|
92
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_isolations_no_delete
|
|
93
|
+
BEFORE DELETE ON oh_semantic_isolations
|
|
94
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic isolations are immutable'); END;
|
|
95
|
+
|
|
96
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_isolations_purge_guard
|
|
97
|
+
BEFORE INSERT ON oh_semantic_isolations
|
|
98
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
99
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority was purged'); END;
|
|
100
|
+
|
|
101
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_vectors_no_update
|
|
102
|
+
BEFORE UPDATE ON oh_semantic_vectors
|
|
103
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic vectors are immutable'); END;
|
|
104
|
+
|
|
105
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_vectors_isolation_guard
|
|
106
|
+
BEFORE INSERT ON oh_semantic_vectors
|
|
107
|
+
WHEN NOT EXISTS (SELECT 1 FROM oh_semantic_isolations
|
|
108
|
+
WHERE isolation_sha256 = NEW.isolation_sha256)
|
|
109
|
+
OR EXISTS (SELECT 1 FROM oh_semantic_purges AS purge
|
|
110
|
+
JOIN oh_semantic_isolations AS isolation
|
|
111
|
+
ON isolation.authority_id = purge.authority_id
|
|
112
|
+
WHERE isolation.isolation_sha256 = NEW.isolation_sha256)
|
|
113
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic vector isolation is unavailable'); END;
|
|
114
|
+
|
|
115
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_generations_no_update
|
|
116
|
+
BEFORE UPDATE ON oh_semantic_generations
|
|
117
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic generations are immutable'); END;
|
|
118
|
+
|
|
119
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_no_update
|
|
120
|
+
BEFORE UPDATE ON oh_semantic_memberships
|
|
121
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic memberships are immutable'); END;
|
|
122
|
+
|
|
123
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_generations_purge_guard
|
|
124
|
+
BEFORE INSERT ON oh_semantic_generations
|
|
125
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
126
|
+
OR NOT EXISTS (SELECT 1 FROM oh_semantic_isolations
|
|
127
|
+
WHERE isolation_sha256 = NEW.isolation_sha256 AND authority_id = NEW.authority_id)
|
|
128
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority or isolation is unavailable'); END;
|
|
129
|
+
|
|
130
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_purge_guard
|
|
131
|
+
BEFORE INSERT ON oh_semantic_memberships
|
|
132
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
133
|
+
OR NOT EXISTS (SELECT 1 FROM oh_semantic_generations
|
|
134
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation
|
|
135
|
+
AND generation_sha256 = NEW.generation_sha256
|
|
136
|
+
AND isolation_sha256 = NEW.isolation_sha256)
|
|
137
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority or isolation is unavailable'); END;
|
|
138
|
+
|
|
139
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_memberships_published_guard
|
|
140
|
+
BEFORE INSERT ON oh_semantic_memberships
|
|
141
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_heads
|
|
142
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation)
|
|
143
|
+
AND NOT EXISTS (SELECT 1 FROM oh_semantic_memberships
|
|
144
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation
|
|
145
|
+
AND generation_sha256 = NEW.generation_sha256
|
|
146
|
+
AND isolation_sha256 = NEW.isolation_sha256
|
|
147
|
+
AND record_key = NEW.record_key AND record_sha256 = NEW.record_sha256
|
|
148
|
+
AND ordinal = NEW.ordinal AND input_sha256 = NEW.input_sha256)
|
|
149
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic generation is published'); END;
|
|
150
|
+
|
|
151
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_heads_insert_purge_guard
|
|
152
|
+
BEFORE INSERT ON oh_semantic_heads
|
|
153
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
154
|
+
OR NOT EXISTS (SELECT 1 FROM oh_semantic_generations
|
|
155
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation
|
|
156
|
+
AND generation_sha256 = NEW.generation_sha256
|
|
157
|
+
AND isolation_sha256 = NEW.isolation_sha256)
|
|
158
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority or isolation is unavailable'); END;
|
|
159
|
+
|
|
160
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_heads_update_purge_guard
|
|
161
|
+
BEFORE UPDATE ON oh_semantic_heads
|
|
162
|
+
WHEN EXISTS (SELECT 1 FROM oh_semantic_purges WHERE authority_id = NEW.authority_id)
|
|
163
|
+
OR NOT EXISTS (SELECT 1 FROM oh_semantic_generations
|
|
164
|
+
WHERE authority_id = NEW.authority_id AND generation = NEW.generation
|
|
165
|
+
AND generation_sha256 = NEW.generation_sha256
|
|
166
|
+
AND isolation_sha256 = NEW.isolation_sha256)
|
|
167
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic authority or isolation is unavailable'); END;
|
|
168
|
+
|
|
169
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_purges_no_update
|
|
170
|
+
BEFORE UPDATE ON oh_semantic_purges
|
|
171
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic purge markers are immutable'); END;
|
|
172
|
+
|
|
173
|
+
CREATE TRIGGER IF NOT EXISTS oh_semantic_purges_no_delete
|
|
174
|
+
BEFORE DELETE ON oh_semantic_purges
|
|
175
|
+
BEGIN SELECT RAISE(ABORT, 'Oh semantic purge markers are immutable'); END;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"authorityId": "fixture:semantic-authority",
|
|
3
|
+
"authoritySha256": "d1eac8dd93ce6e04cb1316c670008250b98ec32cb0555f21d10b782ddffe03a7",
|
|
4
|
+
"content": "fixture body",
|
|
5
|
+
"generation": 7,
|
|
6
|
+
"generationSha256": "5d848fcd482ca72781af87da7b2ff3f68cd5b9ef571495bc734a5a2582c719d1",
|
|
7
|
+
"inputSha256": "b2309e89dd3f903934c7b5f4a4c8c51d5323d84a66928a2f017dd871492ef294",
|
|
8
|
+
"isolationSha256": "217df103dc50da7d3ba2883d9c1cbad01014b2b9eb20e4f94f737291c583d9a5",
|
|
9
|
+
"membershipSha256": "73ec3fcf8af17d99e2ae84878329c834e044bb47ff08ecd0dca6a596504b26b8",
|
|
10
|
+
"recordKey": "memory:fixture",
|
|
11
|
+
"recordSha256": "920d936e47e8f3cc5847017da5975ef73f8d84c04cb113880fb10575eeb614f9",
|
|
12
|
+
"title": "fixture title",
|
|
13
|
+
"v": 2
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cacheSchema": "./libsql-semantic-cache-schema-v2.sql",
|
|
3
|
+
"cacheSchemaSha256": "679edfc3cb02dc768843976093f90d5879d53e84b797ac60d77956a634facae9",
|
|
4
|
+
"digestFixture": "./libsql-semantic-digest-fixture-v2.json",
|
|
5
|
+
"id": "oh.semantic-cloud.v2",
|
|
6
|
+
"legacyCacheSchema": "../v1/libsql-semantic-cache-schema-v1.sql",
|
|
7
|
+
"profile": "../v1/cloudflare-embedding-profile.json",
|
|
8
|
+
"renderer": "../v1/cloudflare-embedding-renderer.json",
|
|
9
|
+
"specification": "./semantic-cloud.md",
|
|
10
|
+
"v": 2
|
|
11
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Hosted semantic cache V2
|
|
2
|
+
|
|
3
|
+
Hosted semantic-cache V2 is the isolated successor to the immutable
|
|
4
|
+
[semantic-cache V1 contract](../v1/semantic-cloud.md). It keeps the same fixed
|
|
5
|
+
Cloudflare EmbeddingGemma profile and renderer, but changes only the rebuildable
|
|
6
|
+
libSQL cache protocol. It does not change an Oh graph, record, operation, local
|
|
7
|
+
embedding, or provider contract.
|
|
8
|
+
|
|
9
|
+
Applications use `bootstrapOhLibSqlSemanticCacheV2` and
|
|
10
|
+
`openOhLibSqlSemanticCacheV2`. The parallel
|
|
11
|
+
`bootstrapOhLibSqlSemanticCacheV1`, `openOhLibSqlSemanticCacheV1`, V1 types,
|
|
12
|
+
V1 result values, and V1 digest preimages remain the released V1 behavior. V1
|
|
13
|
+
and V2 use the same physical table names and therefore cannot be open in one
|
|
14
|
+
database simultaneously. A V1 database can be upgraded to V2; a V2 database
|
|
15
|
+
cannot be opened as V1 or downgraded.
|
|
16
|
+
|
|
17
|
+
The host MUST quiesce V1 stage, publish, head, and search traffic before
|
|
18
|
+
upgrade. An already-open V1 object is not a V2 runtime capability. Bootstrap
|
|
19
|
+
does, however, arbitrate a racing V1 purge: a purge committed before transition
|
|
20
|
+
custody is copied, while a purge that reaches the changed schema cannot report
|
|
21
|
+
success.
|
|
22
|
+
|
|
23
|
+
## Isolation and identity
|
|
24
|
+
|
|
25
|
+
Every V2 authority reference and every stage, publish, head, search, receipt,
|
|
26
|
+
and purge operation binds an `isolationSha256`. It is a validated opaque
|
|
27
|
+
SHA-256 supplied by the host. Private hosts SHOULD derive it from their private
|
|
28
|
+
authority handle, cache epoch, and exact cache profile. When omitted, Oh derives:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{"authorityId":"<authority>","kind":"oh.semantic-authority-isolation.v2","v":2}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
and hashes the canonical JSON. One isolation belongs immutably to one authority,
|
|
35
|
+
while one authority may reserve multiple isolation epochs. The digest never
|
|
36
|
+
enters renderer or provider text.
|
|
37
|
+
|
|
38
|
+
Vector primary identity is
|
|
39
|
+
`(isolation_sha256, profile_sha256, renderer_sha256, input_sha256)`.
|
|
40
|
+
Generations, memberships, and published heads retain the isolation explicitly.
|
|
41
|
+
The membership digest hashes a canonical
|
|
42
|
+
`oh.semantic-membership.v2` envelope; the generation digest hashes an
|
|
43
|
+
`oh.semantic-generation.v2` envelope. Consequently identical rendered text in
|
|
44
|
+
different authorities or epochs is embedded and stored independently. Isolation
|
|
45
|
+
prevents reuse and deletion coupling; it is not encryption and a database holder
|
|
46
|
+
can still observe equal raw input digests or vector bytes.
|
|
47
|
+
|
|
48
|
+
All public V2 values use `v: 2`. Provider and renderer values remain V1 because
|
|
49
|
+
those fixed contracts did not change.
|
|
50
|
+
|
|
51
|
+
## Published reads and purge custody
|
|
52
|
+
|
|
53
|
+
`publishedHead` returns `null` for an isolation mismatch. Search checks the
|
|
54
|
+
same isolation before sending a query to the provider and again while reading
|
|
55
|
+
memberships. Publish requires the staged generation's exact isolation.
|
|
56
|
+
|
|
57
|
+
`purgeAuthority` accepts the current published isolation, writes the permanent
|
|
58
|
+
authority tombstone, deletes every generation and membership for the authority,
|
|
59
|
+
and deletes every vector in every isolation reserved by it. A mismatched current
|
|
60
|
+
isolation is a conflict and authorizes no deletion. The receipt records the
|
|
61
|
+
first execution's counts and returns them unchanged on replay. It contains
|
|
62
|
+
`purgeMarkerSha256`, the canonical
|
|
63
|
+
`oh.semantic-purge-receipt.v2` `purgeReceiptSha256`, and zero
|
|
64
|
+
`residualGenerations`, `residualMemberships`, and
|
|
65
|
+
`residualScopedVectors`. `purgeReceipt` replays the same content-free proof
|
|
66
|
+
without issuing deletes.
|
|
67
|
+
|
|
68
|
+
## V1-to-V2 transition
|
|
69
|
+
|
|
70
|
+
Bootstrap recognizes only the exact published V1 inventory or the exact V2
|
|
71
|
+
inventory. An upgrade first starts one atomic write transaction that:
|
|
72
|
+
|
|
73
|
+
1. creates `oh_semantic_v1_purge_transition`;
|
|
74
|
+
2. copies every V1 authority tombstone into it with one database-side
|
|
75
|
+
`INSERT ... SELECT`;
|
|
76
|
+
3. only after that copy, drops the unsafe globally deduplicated V1 derived rows;
|
|
77
|
+
and
|
|
78
|
+
4. creates the V2 schema without a V2 schema marker.
|
|
79
|
+
|
|
80
|
+
The copy has no lifetime tombstone cap and returns no unbounded row set to the
|
|
81
|
+
host. A concurrent V1 purge either commits before this transaction and is copied,
|
|
82
|
+
or runs afterward against a non-V1 schema and cannot report success. Concurrent
|
|
83
|
+
V2 bootstraps converge on the one transition table.
|
|
84
|
+
|
|
85
|
+
While the transition table exists, `openOhLibSqlSemanticCacheV2` fails closed.
|
|
86
|
+
Bootstrap reads transition rows in fixed pages. Each page atomically creates the
|
|
87
|
+
V2 isolation and receipt for every legacy tombstone and deletes a transition row
|
|
88
|
+
only when the complete computed V2 custody record exists. A crash before a page
|
|
89
|
+
commit changes nothing; a crash after commit can replay safely. Live V1 heads,
|
|
90
|
+
generations, memberships, and vectors are deliberately invalidated because their
|
|
91
|
+
global vector identity cannot be assigned a private owner after the fact.
|
|
92
|
+
|
|
93
|
+
Finalization inserts the exact V2 schema marker only when the transition table
|
|
94
|
+
is empty, then drops that table in the same transaction. Until that commit,
|
|
95
|
+
neither a partially projected database nor a V2 runtime is accepted. Legacy
|
|
96
|
+
receipts use `countsRecorded: false`; new V2 purges use
|
|
97
|
+
`countsRecorded: true`.
|
|
98
|
+
|
|
99
|
+
The exact standalone schemas are
|
|
100
|
+
[revision 1](../v1/libsql-semantic-cache-schema-v1.sql) and
|
|
101
|
+
[revision 2](libsql-semantic-cache-schema-v2.sql). Fixed
|
|
102
|
+
[V1](../v1/libsql-semantic-digest-fixture-v1.json) and
|
|
103
|
+
[V2](libsql-semantic-digest-fixture-v2.json) fixtures make the incompatible
|
|
104
|
+
digest domains explicit. Hosted failure remains a
|
|
105
|
+
missing derived retrieval lane and MUST NOT weaken exact graph or Datalog
|
|
106
|
+
operations.
|
package/src/cli.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { Oh } from "./sdk";
|
|
|
9
9
|
import { OH_SQLITE_SCHEMA_VERSION } from "./sqlite/migrations";
|
|
10
10
|
import { createOhSyncBundleV1, parseOhSyncBundleV1 } from "./sync";
|
|
11
11
|
|
|
12
|
-
export const OH_PACKAGE_VERSION = "0.3.
|
|
12
|
+
export const OH_PACKAGE_VERSION = "0.3.2" as const;
|
|
13
13
|
|
|
14
14
|
type ParsedArguments = { options: Map<string, string[]>; positionals: string[] };
|
|
15
15
|
type ValidatedInvocation = Readonly<{
|