@tangleai/store 0.21.1 → 0.24.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @tangleai/store
2
2
 
3
+ ## 0.24.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Update the Jaren foundation to 0.86.0 with exact registry and source pins. Qualify supervised Node SQLite execution, outcome replay after native backups, and physical-model authoring through the shared Data editor. Document the available relational, migration, cursor and collection-drag mechanisms and their host boundaries.
8
+ - @tangleai/config@0.24.1
9
+ - @tangleai/core@0.24.1
10
+ - @tangleai/documents@0.24.1
11
+ - @tangleai/mas@0.24.1
12
+ - @tangleai/memory@0.24.1
13
+ - @tangleai/outcomes@0.24.1
14
+
15
+ ## 0.24.0
16
+
17
+ ### Minor Changes
18
+
19
+ - Add the outcomes package for independently evidenced decisions, deterministic scoring, atomic confidence projection, bounded artifact refinement and explicitly approved promotion and rollback. The public operation contract, two-domain adapter kit and keyless example share the same scoped request receipts, one-use held-out gates, full head revision checks and interruption recovery.
20
+
21
+ The store adapter owns outcome records and memory changes in one SQLite transaction. The new pure confidence helper preserves fact fields; existing applyOutcome calls retain their original duplicate-citation and timestamp behavior and do not acquire a durable replay guarantee. No existing persisted memory format changes. Hosts opt into the new lifecycle, provide evidence and approval authority, and use a new artifact key for schema or policy changes. Scripted paired measurements and Node/Bun packed consumers qualify the mechanism; downstream domain integrations and automatic promotion remain separate work.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - @tangleai/outcomes@0.24.0
27
+ - @tangleai/memory@0.24.0
28
+ - @tangleai/config@0.24.0
29
+ - @tangleai/core@0.24.0
30
+ - @tangleai/documents@0.24.0
31
+ - @tangleai/mas@0.24.0
32
+
33
+ ## 0.23.0
34
+
35
+ ### Patch Changes
36
+
37
+ - Updated dependencies
38
+ - @tangleai/memory@0.23.0
39
+ - @tangleai/config@0.23.0
40
+ - @tangleai/core@0.23.0
41
+ - @tangleai/documents@0.23.0
42
+ - @tangleai/mas@0.23.0
43
+
44
+ ## 0.22.0
45
+
46
+ ### Patch Changes
47
+
48
+ - @tangleai/config@0.22.0
49
+ - @tangleai/core@0.22.0
50
+ - @tangleai/documents@0.22.0
51
+ - @tangleai/mas@0.22.0
52
+ - @tangleai/memory@0.22.0
53
+
3
54
  ## 0.21.1
4
55
 
5
56
  ### Patch Changes
package/README.md CHANGED
@@ -5,3 +5,71 @@ Tangle AI persistence — the MemoryStore contract over SQLite via @jarenjs/db,
5
5
  Install with `npm install @tangleai/store`. The npm distribution provides ESM JavaScript, TypeScript declarations, and the documented package subpaths for Node 24 and Bun 1.4 or newer.
6
6
 
7
7
  See the [Tangle documentation](https://github.com/jklarenbeek/tangleai#readme) for architecture, examples, and runtime requirements. All public Tangle packages use one coordinated version.
8
+
9
+ ## Execution hosts and backups
10
+
11
+ `openTangleDb` accepts the published Jaren `OpenStoreOptions`, with an optional
12
+ driver. Its default selects the synchronous Node or Bun SQLite driver. Injected
13
+ drivers use the same Store, transactions, memory, outcome and MAS adapters.
14
+
15
+ Jaren 0.86.0 adds `nodeProcessDriver` from `@jarenjs/db/node-process`. Retain the
16
+ opened owner and pass it through a driver adapter to `openTangleDb`; supervise
17
+ ordinary store/service calls with `owner.supervise`. The
18
+ [runnable Node example](../../examples/supervised-store.ts) exercises both outcome
19
+ domains, waits for owner exit, reopens and proves zero-effect replay:
20
+
21
+ ```sh
22
+ npm run store:supervised:smoke
23
+ node examples/supervised-store.ts --db /tmp/supervised-outcomes.sqlite
24
+ ```
25
+
26
+ Share one process driver per host ownership domain. A response deadline fences
27
+ the owner; `settled()` separately reports OS exit and replacement eligibility.
28
+ Reopen and inspect durable receipts before retrying an uncertain write. No
29
+ automatic replay or restart is added. This host has no synchronous/live-query
30
+ surface; importing it on Bun works, while opening refuses with `JD0003`.
31
+
32
+ `db.backupTo(path)` retains the ordinary Jaren maintenance contract, including
33
+ atomic destination replacement. Node uses online backup; Bun uses disk-backed
34
+ VACUUM INTO without materializing the database in JavaScript. A Bun copy remains
35
+ synchronous native work, without incremental native cancellation. Tests restore
36
+ WAL-backed outcome receipts on both runtimes and verify zero-effect replay.
37
+
38
+ Native physical schemas and migrations remain direct Jaren operations; this
39
+ package does not convert existing collections or grant raw SQL callers outcome
40
+ service authority. See the [integration audit](../../docs/JARENJS_INTEGRATION.md)
41
+ for ownership, compatibility and available mechanisms.
42
+
43
+ ## Atomic outcome storage
44
+
45
+ `createOutcomeStore(db)` implements `@tangleai/outcomes`' atomic owner over Jaren
46
+ immediate transactions, with `outcome_records`, `outcome_keys`, `outcome_heads`
47
+ and `outcome_operations` alongside the existing `memories` collection. Immutable
48
+ records carry per-scope sequence values. Head activation compares version and
49
+ revision; projection changes current memory confidence and its terminal receipt
50
+ in the same transaction. Its `memories` property is that same owner's memory
51
+ view, not a separately attached store.
52
+
53
+ ```ts
54
+ import { openTangleDb, createOutcomeStore } from '@tangleai/store';
55
+ const db = await openTangleDb({ path: '/tmp/outcomes.sqlite' });
56
+ const store = createOutcomeStore(db);
57
+ // Pass store to createOutcomeService with the host's scope, adapters and resolver.
58
+ // Close db when the host is finished.
59
+ ```
60
+
61
+ Node and Bun use the installed Jaren SQLite drivers. Tests cover independent
62
+ handles, rollback faults, abrupt process exit, reopening, and zero-effect
63
+ completed replay. A driver busy refusal can require an explicit retry after
64
+ contention. Unknown external completion remains uncertain until host
65
+ reconciliation; SQLite does not make remote effects transactional. A reservation
66
+ is audited before external work, and no-dispatch reconciliation fences the old
67
+ worker. Do not combine this receipt store with unrelated nontransactional memory
68
+ and claim atomic projection.
69
+
70
+ History filtering and pagination execute as indexed scope/sequence SQL queries
71
+ with LIMIT. That bounds returned records; it is not a driver-wide CPU or scan
72
+ budget. The service caps ancestry traversal and detects corrupt immutable bytes.
73
+ Raw database writes remain trusted-host administration, outside supported API
74
+ authority guarantees. See [the outcome kit](../outcomes/docs/ADAPTERS.md) and the
75
+ [measured replay](../../docs/OUTCOME_BENCHMARK.md).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangleai/store",
3
- "version": "0.21.1",
3
+ "version": "0.24.1",
4
4
  "description": "Tangle AI persistence — the MemoryStore contract over SQLite via @jarenjs/db, plus the run/event log the DAG surface reads",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -46,6 +46,11 @@
46
46
  "types": "./src/ledger-storage.d.ts",
47
47
  "import": "./src/ledger-storage.js",
48
48
  "default": "./src/ledger-storage.js"
49
+ },
50
+ "./outcome-store": {
51
+ "types": "./src/outcome-store.d.ts",
52
+ "import": "./src/outcome-store.js",
53
+ "default": "./src/outcome-store.js"
49
54
  }
50
55
  },
51
56
  "engines": {
@@ -53,14 +58,15 @@
53
58
  },
54
59
  "sideEffects": false,
55
60
  "dependencies": {
56
- "@tangleai/documents": "^0.21.1",
57
- "@tangleai/core": "^0.21.1",
58
- "@tangleai/config": "^0.21.1",
59
- "@jarenjs/db": "0.84.3",
60
- "@jarenjs/validate": "0.84.3",
61
- "@tangleai/mas": "^0.21.1",
62
- "@jarenjs/core": "0.84.3",
63
- "@tangleai/memory": "^0.21.1"
61
+ "@tangleai/documents": "^0.24.1",
62
+ "@tangleai/core": "^0.24.1",
63
+ "@tangleai/config": "^0.24.1",
64
+ "@jarenjs/db": "0.86.0",
65
+ "@jarenjs/validate": "0.86.0",
66
+ "@tangleai/mas": "^0.24.1",
67
+ "@jarenjs/core": "0.86.0",
68
+ "@tangleai/memory": "^0.24.1",
69
+ "@tangleai/outcomes": "^0.24.1"
64
70
  },
65
71
  "private": false,
66
72
  "types": "./src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { TANGLE_DB_MODEL } from './model.ts';
3
3
  export { openTangleDb, pickDriver } from './db.ts';
4
4
  export type { TangleDb, DbCollection, OpenTangleDbOptions } from './db.ts';
5
5
  export { createDbMemoryStore, asRows } from './memory-store.ts';
6
+ export { createOutcomeStore } from './outcome-store.ts';
7
+ export type { OutcomeStoreOptions } from './outcome-store.ts';
6
8
  export type { DbMemoryStoreOptions } from './memory-store.ts';
7
9
  export { createRunLog } from './runs.ts';
8
10
  export type { RunLog, RunRecord, RunEvent, RunLogOptions, RunIdentityStatus, RunView } from './runs.ts';
package/src/index.js CHANGED
@@ -2,6 +2,7 @@
2
2
  export { TANGLE_DB_MODEL } from "./model.js";
3
3
  export { openTangleDb, pickDriver } from "./db.js";
4
4
  export { createDbMemoryStore, asRows } from "./memory-store.js";
5
+ export { createOutcomeStore } from "./outcome-store.js";
5
6
  export { createRunLog } from "./runs.js";
6
7
  export { createIdentityRepository } from "./identities.js";
7
8
  export { createDocumentStore } from "./document-store.js";
package/src/model.d.ts CHANGED
@@ -29,6 +29,89 @@ import type { JsonSchema } from '@tangleai/core/schemas/memory';
29
29
  export declare const TANGLE_DB_MODEL: {
30
30
  readonly $model: "0.1";
31
31
  readonly collections: {
32
+ readonly outcome_records: {
33
+ readonly schema: {
34
+ readonly type: "object";
35
+ readonly required: readonly ["id", "scopeId"];
36
+ readonly properties: {
37
+ readonly id: JsonSchema;
38
+ readonly scopeId: JsonSchema;
39
+ readonly artifactKey: JsonSchema;
40
+ readonly kind: JsonSchema;
41
+ readonly seq: {
42
+ readonly type: "integer";
43
+ };
44
+ };
45
+ };
46
+ readonly key: "/id";
47
+ readonly indexes: readonly [{
48
+ readonly name: "by_scope_sequence";
49
+ readonly path: readonly ["$.scopeId", "$.seq"];
50
+ }, {
51
+ readonly name: "by_artifact_kind";
52
+ readonly path: readonly ["$.scopeId", "$.artifactKey", "$.kind"];
53
+ }];
54
+ };
55
+ readonly outcome_keys: {
56
+ readonly schema: {
57
+ readonly type: "object";
58
+ readonly required: readonly ["id", "scopeId"];
59
+ readonly properties: {
60
+ readonly id: JsonSchema;
61
+ readonly scopeId: JsonSchema;
62
+ readonly artifactKey: JsonSchema;
63
+ readonly kind: JsonSchema;
64
+ readonly seq: {
65
+ readonly type: "integer";
66
+ };
67
+ };
68
+ };
69
+ readonly key: "/id";
70
+ readonly indexes: readonly [{
71
+ readonly name: "by_scope";
72
+ readonly path: "$.scopeId";
73
+ }];
74
+ };
75
+ readonly outcome_heads: {
76
+ readonly schema: {
77
+ readonly type: "object";
78
+ readonly required: readonly ["id", "scopeId"];
79
+ readonly properties: {
80
+ readonly id: JsonSchema;
81
+ readonly scopeId: JsonSchema;
82
+ readonly artifactKey: JsonSchema;
83
+ readonly kind: JsonSchema;
84
+ readonly seq: {
85
+ readonly type: "integer";
86
+ };
87
+ };
88
+ };
89
+ readonly key: "/id";
90
+ readonly indexes: readonly [{
91
+ readonly name: "by_scope";
92
+ readonly path: "$.scopeId";
93
+ }];
94
+ };
95
+ readonly outcome_operations: {
96
+ readonly schema: {
97
+ readonly type: "object";
98
+ readonly required: readonly ["id", "scopeId"];
99
+ readonly properties: {
100
+ readonly id: JsonSchema;
101
+ readonly scopeId: JsonSchema;
102
+ readonly artifactKey: JsonSchema;
103
+ readonly kind: JsonSchema;
104
+ readonly seq: {
105
+ readonly type: "integer";
106
+ };
107
+ };
108
+ };
109
+ readonly key: "/id";
110
+ readonly indexes: readonly [{
111
+ readonly name: "by_artifact";
112
+ readonly path: readonly ["$.scopeId", "$.artifactKey"];
113
+ }];
114
+ };
32
115
  readonly memories: {
33
116
  readonly schema: {
34
117
  readonly type: "object";
package/src/model.js CHANGED
@@ -29,6 +29,26 @@ const ID = { type: 'string', minLength: 1 };
29
29
  export const TANGLE_DB_MODEL = {
30
30
  $model: '0.1',
31
31
  collections: {
32
+ outcome_records: {
33
+ schema: { type: 'object', required: ['id', 'scopeId'], properties: { id: ID, scopeId: ID, artifactKey: ID, kind: ID, seq: { type: 'integer' } } },
34
+ key: '/id',
35
+ indexes: [{ name: 'by_scope_sequence', path: ['$.scopeId', '$.seq'] }, { name: 'by_artifact_kind', path: ['$.scopeId', '$.artifactKey', '$.kind'] }],
36
+ },
37
+ outcome_keys: {
38
+ schema: { type: 'object', required: ['id', 'scopeId'], properties: { id: ID, scopeId: ID, artifactKey: ID, kind: ID, seq: { type: 'integer' } } },
39
+ key: '/id',
40
+ indexes: [{ name: 'by_scope', path: '$.scopeId' }],
41
+ },
42
+ outcome_heads: {
43
+ schema: { type: 'object', required: ['id', 'scopeId'], properties: { id: ID, scopeId: ID, artifactKey: ID, kind: ID, seq: { type: 'integer' } } },
44
+ key: '/id',
45
+ indexes: [{ name: 'by_scope', path: '$.scopeId' }],
46
+ },
47
+ outcome_operations: {
48
+ schema: { type: 'object', required: ['id', 'scopeId'], properties: { id: ID, scopeId: ID, artifactKey: ID, kind: ID, seq: { type: 'integer' } } },
49
+ key: '/id',
50
+ indexes: [{ name: 'by_artifact', path: ['$.scopeId', '$.artifactKey'] }],
51
+ },
32
52
  memories: {
33
53
  schema: { type: 'object', required: ['id'], properties: { id: ID } },
34
54
  key: '/id',
@@ -0,0 +1,7 @@
1
+ /** Outcomes use the database's transaction owner, including memory projection. */
2
+ import { type OutcomeStore } from '@tangleai/outcomes';
3
+ import type { TangleDb } from './db.ts';
4
+ export interface OutcomeStoreOptions {
5
+ applyProbe?: (step: string) => void;
6
+ }
7
+ export declare function createOutcomeStore(db: TangleDb, options?: OutcomeStoreOptions): OutcomeStore;
@@ -0,0 +1,32 @@
1
+ /** Outcomes use the database's transaction owner, including memory projection. */
2
+ import { createOutcomeStoreAdapter } from '@tangleai/outcomes';
3
+ import { asRows } from "./memory-store.js";
4
+ const names = { records: 'outcome_records', keys: 'outcome_keys', heads: 'outcome_heads', operations: 'outcome_operations', memories: 'memories' };
5
+ export function createOutcomeStore(db, options = {}) {
6
+ const persistence = { transaction: (task) => db.transaction(async (tx) => {
7
+ const view = {
8
+ async get(table, id) { return tx.collection(names[table]).get(id); },
9
+ async put(table, value) { await tx.collection(names[table]).put(value); options.applyProbe?.(`put:${table}`); },
10
+ async delete(table, id) { await tx.collection(names[table]).delete(id); options.applyProbe?.(`delete:${table}`); },
11
+ async query(table, q) {
12
+ const where = [];
13
+ for (const field of ['scopeId', 'artifactKey', 'kind'])
14
+ if (q[field] !== undefined)
15
+ where.push({ $eq: [`$r.${field}`, { $const: q[field] }] });
16
+ if (q.reservedOnly)
17
+ where.push({ $eq: ['$r.capacityReserved', true] });
18
+ if (q.after !== undefined)
19
+ where.push({ $gt: ['$r.seq', q.after] });
20
+ if (q.upper !== undefined)
21
+ where.push({ $le: ['$r.seq', q.upper] });
22
+ const query = { $for: { r: '$[*]' }, ...(where.length ? { $where: { $and: where } } : {}), $orderby: table === 'records' ? ['$r.seq', '$r.id'] : ['$r.id'], $return: '$r' };
23
+ const bounded = q.limit === undefined ? query : { $subsequence: [query, 0, q.limit] };
24
+ return asRows(await tx.collection(names[table]).execute(bounded));
25
+ },
26
+ };
27
+ const result = await task(view);
28
+ options.applyProbe?.('commit');
29
+ return result;
30
+ }, { mode: 'immediate' }) };
31
+ return createOutcomeStoreAdapter(persistence);
32
+ }