@dsh-enhanced/assistant-evolution 0.1.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 +120 -0
- package/cordis.patch.yml +20 -0
- package/lib/guidance.d.ts +29 -0
- package/lib/guidance.d.ts.map +1 -0
- package/lib/guidance.js +59 -0
- package/lib/guidance.js.map +1 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +12 -0
- package/lib/index.js.map +1 -0
- package/lib/review.d.ts +13 -0
- package/lib/review.d.ts.map +1 -0
- package/lib/review.js +47 -0
- package/lib/review.js.map +1 -0
- package/lib/service.d.ts +148 -0
- package/lib/service.d.ts.map +1 -0
- package/lib/service.js +554 -0
- package/lib/service.js.map +1 -0
- package/lib/sqlite.d.ts +8 -0
- package/lib/sqlite.d.ts.map +1 -0
- package/lib/sqlite.js +253 -0
- package/lib/sqlite.js.map +1 -0
- package/lib/store.d.ts +116 -0
- package/lib/store.d.ts.map +1 -0
- package/lib/store.js +886 -0
- package/lib/store.js.map +1 -0
- package/lib/tools.d.ts +4 -0
- package/lib/tools.d.ts.map +1 -0
- package/lib/tools.js +206 -0
- package/lib/tools.js.map +1 -0
- package/lib/types.d.ts +215 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/lib/version.d.ts +2 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/version.js +2 -0
- package/lib/version.js.map +1 -0
- package/package.json +81 -0
package/lib/sqlite.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { chmodSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute } from 'node:path';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
export const evolutionSchemaVersion = 3;
|
|
5
|
+
export class EvolutionDatabaseError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
constructor(code, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.name = 'EvolutionDatabaseError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function schemaVersion(database) {
|
|
14
|
+
return database.prepare('PRAGMA user_version').get().user_version;
|
|
15
|
+
}
|
|
16
|
+
function assertSupported(version) {
|
|
17
|
+
if (version > evolutionSchemaVersion) {
|
|
18
|
+
throw new EvolutionDatabaseError('schema-too-new', `evolution schema ${version} is newer than supported schema ${evolutionSchemaVersion}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function migrateV1ToV2(database) {
|
|
22
|
+
database.exec(`
|
|
23
|
+
ALTER TABLE evolution_episodes
|
|
24
|
+
ADD COLUMN scope_key TEXT NOT NULL DEFAULT 'legacy:v1';
|
|
25
|
+
ALTER TABLE evolution_episodes
|
|
26
|
+
ADD COLUMN trust TEXT NOT NULL DEFAULT 'legacy'
|
|
27
|
+
CHECK (trust IN ('trusted', 'self-reported', 'legacy'));
|
|
28
|
+
ALTER TABLE evolution_episodes ADD COLUMN claimed_rule_id TEXT;
|
|
29
|
+
UPDATE evolution_episodes SET claimed_rule_id = rule_id, rule_id = NULL;
|
|
30
|
+
|
|
31
|
+
ALTER TABLE evolution_rules
|
|
32
|
+
ADD COLUMN scope_key TEXT NOT NULL DEFAULT 'legacy:v1';
|
|
33
|
+
ALTER TABLE evolution_rules
|
|
34
|
+
ADD COLUMN generation INTEGER NOT NULL DEFAULT 0 CHECK (generation >= 0);
|
|
35
|
+
|
|
36
|
+
ALTER TABLE evolution_proposals
|
|
37
|
+
ADD COLUMN scope_key TEXT NOT NULL DEFAULT 'legacy:v1';
|
|
38
|
+
UPDATE evolution_proposals SET status = 'expired' WHERE status = 'pending';
|
|
39
|
+
|
|
40
|
+
DROP INDEX IF EXISTS evolution_episodes_situation;
|
|
41
|
+
DROP INDEX IF EXISTS evolution_episodes_rule;
|
|
42
|
+
DROP INDEX IF EXISTS evolution_rules_active_situation;
|
|
43
|
+
CREATE INDEX evolution_episodes_adoption
|
|
44
|
+
ON evolution_episodes(scope_key, situation, trust, rule_id, occurred_at DESC, id DESC);
|
|
45
|
+
CREATE INDEX evolution_episodes_evaluation
|
|
46
|
+
ON evolution_episodes(rule_id, trust, occurred_at DESC, id DESC);
|
|
47
|
+
CREATE UNIQUE INDEX evolution_rules_active_scope_situation
|
|
48
|
+
ON evolution_rules(scope_key, situation)
|
|
49
|
+
WHERE status = 'active' AND scope_key <> 'legacy:v1';
|
|
50
|
+
CREATE UNIQUE INDEX evolution_rules_scope_generation
|
|
51
|
+
ON evolution_rules(scope_key, situation, generation)
|
|
52
|
+
WHERE scope_key <> 'legacy:v1';
|
|
53
|
+
|
|
54
|
+
INSERT INTO schema_meta(key, value) VALUES ('schema-version', '2')
|
|
55
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value;
|
|
56
|
+
PRAGMA user_version = 2;
|
|
57
|
+
`);
|
|
58
|
+
}
|
|
59
|
+
function migrateV2ToV3(database) {
|
|
60
|
+
database.exec(`
|
|
61
|
+
ALTER TABLE evolution_episodes ADD COLUMN guidance_version INTEGER
|
|
62
|
+
CHECK (guidance_version IS NULL OR guidance_version >= 1);
|
|
63
|
+
ALTER TABLE evolution_proposals ADD COLUMN creation_intent_json TEXT;
|
|
64
|
+
ALTER TABLE evolution_proposals ADD COLUMN settlement_expectation_json TEXT;
|
|
65
|
+
|
|
66
|
+
-- Early unreleased v2 rows did not freeze the complete Policy tuple. They
|
|
67
|
+
-- cannot be validated or safely replayed after a crash, so quarantine their
|
|
68
|
+
-- pending mutations as durable security conflicts rather than guessing.
|
|
69
|
+
UPDATE evolution_proposals
|
|
70
|
+
SET status = 'conflicted', version = version + 1
|
|
71
|
+
WHERE status = 'pending';
|
|
72
|
+
|
|
73
|
+
CREATE TABLE evolution_guidance_exposures (
|
|
74
|
+
session_id TEXT NOT NULL,
|
|
75
|
+
scope_key TEXT NOT NULL,
|
|
76
|
+
situation TEXT NOT NULL,
|
|
77
|
+
rule_id TEXT NOT NULL,
|
|
78
|
+
guidance_version INTEGER NOT NULL CHECK (guidance_version >= 1),
|
|
79
|
+
exposed_at INTEGER NOT NULL,
|
|
80
|
+
PRIMARY KEY(session_id, scope_key, rule_id, guidance_version)
|
|
81
|
+
) STRICT, WITHOUT ROWID;
|
|
82
|
+
CREATE INDEX evolution_guidance_exposures_lookup
|
|
83
|
+
ON evolution_guidance_exposures(session_id, scope_key, situation, exposed_at, rule_id);
|
|
84
|
+
|
|
85
|
+
INSERT INTO schema_meta(key, value) VALUES ('schema-version', '3')
|
|
86
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value;
|
|
87
|
+
PRAGMA user_version = 3;
|
|
88
|
+
`);
|
|
89
|
+
}
|
|
90
|
+
function createCurrentSchema(database) {
|
|
91
|
+
database.exec(`
|
|
92
|
+
CREATE TABLE schema_meta (
|
|
93
|
+
key TEXT PRIMARY KEY,
|
|
94
|
+
value TEXT NOT NULL
|
|
95
|
+
) STRICT;
|
|
96
|
+
|
|
97
|
+
-- One observed outcome. Episodes are append-only and carry only trusted
|
|
98
|
+
-- attribution proven by a durable session exposure receipt.
|
|
99
|
+
CREATE TABLE evolution_episodes (
|
|
100
|
+
id TEXT PRIMARY KEY,
|
|
101
|
+
idempotency_key TEXT NOT NULL UNIQUE,
|
|
102
|
+
situation TEXT NOT NULL,
|
|
103
|
+
outcome TEXT NOT NULL CHECK (outcome IN ('succeeded', 'failed')),
|
|
104
|
+
detail TEXT NOT NULL,
|
|
105
|
+
source TEXT NOT NULL CHECK (source IN ('automation', 'foreground')),
|
|
106
|
+
scope_key TEXT NOT NULL,
|
|
107
|
+
trust TEXT NOT NULL CHECK (trust IN ('trusted', 'self-reported', 'legacy')),
|
|
108
|
+
rule_id TEXT,
|
|
109
|
+
guidance_version INTEGER CHECK (guidance_version IS NULL OR guidance_version >= 1),
|
|
110
|
+
claimed_rule_id TEXT,
|
|
111
|
+
occurred_at INTEGER NOT NULL
|
|
112
|
+
) STRICT;
|
|
113
|
+
|
|
114
|
+
CREATE INDEX evolution_episodes_adoption
|
|
115
|
+
ON evolution_episodes(scope_key, situation, trust, rule_id, occurred_at DESC, id DESC);
|
|
116
|
+
CREATE INDEX evolution_episodes_evaluation
|
|
117
|
+
ON evolution_episodes(rule_id, trust, occurred_at DESC, id DESC);
|
|
118
|
+
|
|
119
|
+
CREATE TABLE evolution_rules (
|
|
120
|
+
id TEXT PRIMARY KEY,
|
|
121
|
+
scope_key TEXT NOT NULL,
|
|
122
|
+
situation TEXT NOT NULL,
|
|
123
|
+
guidance TEXT NOT NULL,
|
|
124
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'retired')),
|
|
125
|
+
baseline_failures INTEGER NOT NULL CHECK (baseline_failures >= 0),
|
|
126
|
+
baseline_total INTEGER NOT NULL CHECK (baseline_total > 0),
|
|
127
|
+
adopted_at INTEGER NOT NULL,
|
|
128
|
+
updated_at INTEGER NOT NULL,
|
|
129
|
+
retired_reason TEXT,
|
|
130
|
+
version INTEGER NOT NULL DEFAULT 1 CHECK (version >= 1),
|
|
131
|
+
generation INTEGER NOT NULL CHECK (generation >= 1)
|
|
132
|
+
) STRICT;
|
|
133
|
+
|
|
134
|
+
CREATE UNIQUE INDEX evolution_rules_active_scope_situation
|
|
135
|
+
ON evolution_rules(scope_key, situation) WHERE status = 'active';
|
|
136
|
+
CREATE UNIQUE INDEX evolution_rules_scope_generation
|
|
137
|
+
ON evolution_rules(scope_key, situation, generation);
|
|
138
|
+
|
|
139
|
+
CREATE TABLE evolution_proposals (
|
|
140
|
+
id TEXT PRIMARY KEY,
|
|
141
|
+
policy_proposal_id TEXT UNIQUE,
|
|
142
|
+
idempotency_key TEXT NOT NULL UNIQUE,
|
|
143
|
+
requester TEXT NOT NULL,
|
|
144
|
+
principal TEXT NOT NULL,
|
|
145
|
+
scope_key TEXT NOT NULL,
|
|
146
|
+
mutation_hash TEXT NOT NULL,
|
|
147
|
+
mutation_json TEXT NOT NULL,
|
|
148
|
+
creation_intent_json TEXT,
|
|
149
|
+
settlement_expectation_json TEXT,
|
|
150
|
+
status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'rejected', 'expired', 'conflicted')),
|
|
151
|
+
expires_at INTEGER NOT NULL,
|
|
152
|
+
result_rule_id TEXT,
|
|
153
|
+
created_at INTEGER NOT NULL,
|
|
154
|
+
updated_at INTEGER NOT NULL,
|
|
155
|
+
version INTEGER NOT NULL DEFAULT 1
|
|
156
|
+
) STRICT;
|
|
157
|
+
|
|
158
|
+
CREATE TABLE evolution_audit (
|
|
159
|
+
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
160
|
+
idempotency_key TEXT NOT NULL UNIQUE,
|
|
161
|
+
operation TEXT NOT NULL,
|
|
162
|
+
rule_id TEXT NOT NULL,
|
|
163
|
+
result_version INTEGER NOT NULL,
|
|
164
|
+
occurred_at INTEGER NOT NULL
|
|
165
|
+
) STRICT;
|
|
166
|
+
|
|
167
|
+
CREATE TABLE evolution_guidance_exposures (
|
|
168
|
+
session_id TEXT NOT NULL,
|
|
169
|
+
scope_key TEXT NOT NULL,
|
|
170
|
+
situation TEXT NOT NULL,
|
|
171
|
+
rule_id TEXT NOT NULL,
|
|
172
|
+
guidance_version INTEGER NOT NULL CHECK (guidance_version >= 1),
|
|
173
|
+
exposed_at INTEGER NOT NULL,
|
|
174
|
+
PRIMARY KEY(session_id, scope_key, rule_id, guidance_version)
|
|
175
|
+
) STRICT, WITHOUT ROWID;
|
|
176
|
+
CREATE INDEX evolution_guidance_exposures_lookup
|
|
177
|
+
ON evolution_guidance_exposures(session_id, scope_key, situation, exposed_at, rule_id);
|
|
178
|
+
|
|
179
|
+
INSERT INTO schema_meta(key, value) VALUES ('schema-version', '3');
|
|
180
|
+
PRAGMA user_version = 3;
|
|
181
|
+
`);
|
|
182
|
+
}
|
|
183
|
+
/** Serialize every schema transition and re-read the version after the lock. */
|
|
184
|
+
function migrate(database) {
|
|
185
|
+
const initial = schemaVersion(database);
|
|
186
|
+
assertSupported(initial);
|
|
187
|
+
if (initial === evolutionSchemaVersion)
|
|
188
|
+
return;
|
|
189
|
+
database.exec('BEGIN IMMEDIATE');
|
|
190
|
+
try {
|
|
191
|
+
let version = schemaVersion(database);
|
|
192
|
+
assertSupported(version);
|
|
193
|
+
if (version === 0) {
|
|
194
|
+
createCurrentSchema(database);
|
|
195
|
+
version = evolutionSchemaVersion;
|
|
196
|
+
}
|
|
197
|
+
while (version < evolutionSchemaVersion) {
|
|
198
|
+
if (version === 1)
|
|
199
|
+
migrateV1ToV2(database);
|
|
200
|
+
else if (version === 2)
|
|
201
|
+
migrateV2ToV3(database);
|
|
202
|
+
version = schemaVersion(database);
|
|
203
|
+
}
|
|
204
|
+
database.exec('COMMIT');
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
database.exec('ROLLBACK');
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const walRetryWait = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
212
|
+
function enableWal(database) {
|
|
213
|
+
const deadline = Date.now() + 5_000;
|
|
214
|
+
while (true) {
|
|
215
|
+
try {
|
|
216
|
+
const row = database.prepare('PRAGMA journal_mode = WAL').get();
|
|
217
|
+
if (row.journal_mode.toLowerCase() !== 'wal') {
|
|
218
|
+
throw new Error(`evolution database refused WAL mode: ${row.journal_mode}`);
|
|
219
|
+
}
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
const retryable = error instanceof Error && /database is (?:busy|locked)/i.test(error.message);
|
|
224
|
+
if (!retryable || Date.now() >= deadline)
|
|
225
|
+
throw error;
|
|
226
|
+
Atomics.wait(walRetryWait, 0, 0, 10);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
export function openEvolutionDatabase(path) {
|
|
231
|
+
if (path !== ':memory:' && !isAbsolute(path)) {
|
|
232
|
+
throw new EvolutionDatabaseError('invalid-path', 'evolution database path must be absolute');
|
|
233
|
+
}
|
|
234
|
+
if (path !== ':memory:')
|
|
235
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
236
|
+
const database = new DatabaseSync(path);
|
|
237
|
+
try {
|
|
238
|
+
database.exec('PRAGMA foreign_keys = ON');
|
|
239
|
+
database.exec('PRAGMA busy_timeout = 5000');
|
|
240
|
+
database.exec('PRAGMA synchronous = FULL');
|
|
241
|
+
migrate(database);
|
|
242
|
+
if (path !== ':memory:') {
|
|
243
|
+
enableWal(database);
|
|
244
|
+
chmodSync(path, 0o600);
|
|
245
|
+
}
|
|
246
|
+
return database;
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
database.close();
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../src/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAEpC;IADX,YACW,IAAuC,EAChD,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;QAHL,SAAI,GAAJ,IAAI,CAAmC;QAIhD,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAA;IACtC,CAAC;CACF;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,OAAQ,QAAQ,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAA+B,CAAC,YAAY,CAAA;AACjG,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,IAAI,OAAO,GAAG,sBAAsB,EAAE,CAAC;QACrC,MAAM,IAAI,sBAAsB,CAC9B,gBAAgB,EAChB,oBAAoB,OAAO,mCAAmC,sBAAsB,EAAE,CACvF,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCb,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,QAAsB;IAC3C,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4Bb,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,QAAsB;IACjD,QAAQ,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0Fb,CAAC,CAAA;AACJ,CAAC;AAED,gFAAgF;AAChF,SAAS,OAAO,CAAC,QAAsB;IACrC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;IACvC,eAAe,CAAC,OAAO,CAAC,CAAA;IACxB,IAAI,OAAO,KAAK,sBAAsB;QAAE,OAAM;IAE9C,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;IAChC,IAAI,CAAC;QACH,IAAI,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACrC,eAAe,CAAC,OAAO,CAAC,CAAA;QACxB,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;YAClB,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC7B,OAAO,GAAG,sBAAsB,CAAA;QAClC,CAAC;QACD,OAAO,OAAO,GAAG,sBAAsB,EAAE,CAAC;YACxC,IAAI,OAAO,KAAK,CAAC;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;iBACrC,IAAI,OAAO,KAAK,CAAC;gBAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;YAC/C,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QACnC,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACzB,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,YAAY,GAAG,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAExF,SAAS,SAAS,CAAC,QAAsB;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;IACnC,OAAO,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,GAAG,EAA8B,CAAA;YAC3F,IAAI,GAAG,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CAAC,wCAAwC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAA;YAC7E,CAAC;YACD,OAAM;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,KAAK,YAAY,KAAK,IAAI,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAC9F,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,MAAM,KAAK,CAAA;YACrD,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,sBAAsB,CAAC,cAAc,EAAE,0CAA0C,CAAC,CAAA;IAC9F,CAAC;IACD,IAAI,IAAI,KAAK,UAAU;QAAE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACnF,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAA;IACvC,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;QACzC,QAAQ,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;QAC3C,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QAC1C,OAAO,CAAC,QAAQ,CAAC,CAAA;QACjB,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,CAAC,CAAA;YACnB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QACxB,CAAC;QACD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,KAAK,EAAE,CAAA;QAChB,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
|
package/lib/store.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { EpisodeInput, EvolutionCreationIntent, EvolutionMutation, EvolutionSettlementExpectation, GuidanceExposure, ProposalStatus, RuleCandidate, RuleInput, SituationStats, StoredEpisode, StoredProposal, StoredRule } from './types.js';
|
|
2
|
+
export type EvolutionStoreErrorCode = 'idempotency-conflict' | 'invalid-input' | 'invalid-state' | 'not-found' | 'version-conflict';
|
|
3
|
+
export declare class EvolutionStoreError extends Error {
|
|
4
|
+
readonly code: EvolutionStoreErrorCode;
|
|
5
|
+
constructor(code: EvolutionStoreErrorCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
export interface EvolutionStoreOptions {
|
|
8
|
+
path: string;
|
|
9
|
+
now?: () => number;
|
|
10
|
+
maxSituationBytes?: number;
|
|
11
|
+
maxGuidanceBytes?: number;
|
|
12
|
+
maxDetailBytes?: number;
|
|
13
|
+
}
|
|
14
|
+
declare function digest(value: unknown): string;
|
|
15
|
+
/**
|
|
16
|
+
* Durable evidence and rule ledger.
|
|
17
|
+
*
|
|
18
|
+
* Two invariants matter most. First, a rule is data, not authority: nothing here
|
|
19
|
+
* can widen what a tool call may do, because assistant-policy is consulted
|
|
20
|
+
* separately and never reads this database. Second, adoption is never automatic —
|
|
21
|
+
* the store can only *propose* a change, so an owner decision always stands
|
|
22
|
+
* between an observation and a behavioural change.
|
|
23
|
+
*/
|
|
24
|
+
export declare class EvolutionStore {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(options: EvolutionStoreOptions);
|
|
27
|
+
close(): void;
|
|
28
|
+
/** Record one observed outcome. Idempotent on `idempotencyKey`. */
|
|
29
|
+
recordEpisode(input: EpisodeInput): StoredEpisode;
|
|
30
|
+
/** Failure counts for one situation over the most recent `window` episodes. */
|
|
31
|
+
stats(scopeKey: string, situation: string, window: number): SituationStats;
|
|
32
|
+
listRules(scopeKey: string, status?: 'active' | 'retired'): StoredRule[];
|
|
33
|
+
getRule(ruleId: string): StoredRule | undefined;
|
|
34
|
+
activeRule(scopeKey: string, situation: string): StoredRule | undefined;
|
|
35
|
+
nextGeneration(scopeKey: string, situation: string): number;
|
|
36
|
+
/** Persist proof only after the corresponding guidance injection returned. */
|
|
37
|
+
recordGuidanceExposure(input: {
|
|
38
|
+
sessionId: string;
|
|
39
|
+
scopeKey: string;
|
|
40
|
+
situation: string;
|
|
41
|
+
ruleId: string;
|
|
42
|
+
guidanceVersion: number;
|
|
43
|
+
}): GuidanceExposure;
|
|
44
|
+
hasGuidanceExposure(sessionId: string, scopeKey: string, ruleId: string, guidanceVersion: number): boolean;
|
|
45
|
+
/** Return only an unambiguous exact-situation receipt for one session. */
|
|
46
|
+
captureGuidanceExposure(sessionId: string, scopeKey: string, situation: string): GuidanceExposure | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Compute candidate rule changes from recorded evidence.
|
|
49
|
+
*
|
|
50
|
+
* This is the only place learning is inferred, and it deliberately stops at a
|
|
51
|
+
* *candidate*. Two directions are detected:
|
|
52
|
+
*
|
|
53
|
+
* - `adopt`: a situation fails often enough, with a large enough sample, and has
|
|
54
|
+
* no active rule yet.
|
|
55
|
+
* - `retire`: an active rule's situation is not doing better than the baseline
|
|
56
|
+
* it was adopted against, so the rule is not earning its place.
|
|
57
|
+
*
|
|
58
|
+
* A rule is never revised in place. Revision would silently rewrite behaviour
|
|
59
|
+
* under an old approval, so a change is always retire-then-adopt, each with its
|
|
60
|
+
* own decision.
|
|
61
|
+
*/
|
|
62
|
+
candidates(options: {
|
|
63
|
+
scopeKey: string;
|
|
64
|
+
window: number;
|
|
65
|
+
minSample: number;
|
|
66
|
+
adoptFailureRate: number;
|
|
67
|
+
retireFailureRate: number;
|
|
68
|
+
limit: number;
|
|
69
|
+
evidenceSampleLimit?: number;
|
|
70
|
+
}): RuleCandidate[];
|
|
71
|
+
/** Compute the candidate for one exact active rule, independent of list limits. */
|
|
72
|
+
retirementCandidate(options: {
|
|
73
|
+
scopeKey: string;
|
|
74
|
+
ruleId: string;
|
|
75
|
+
window: number;
|
|
76
|
+
minSample: number;
|
|
77
|
+
retireFailureRate: number;
|
|
78
|
+
evidenceSampleLimit?: number;
|
|
79
|
+
}): RuleCandidate | undefined;
|
|
80
|
+
createProposal(input: {
|
|
81
|
+
idempotencyKey: string;
|
|
82
|
+
requester: string;
|
|
83
|
+
principal: string;
|
|
84
|
+
mutation: EvolutionMutation;
|
|
85
|
+
expiresAt: number;
|
|
86
|
+
creationIntent?: EvolutionCreationIntent;
|
|
87
|
+
}): StoredProposal;
|
|
88
|
+
attachPolicy(proposalId: string, policyProposalId: string, expectation?: EvolutionSettlementExpectation): StoredProposal;
|
|
89
|
+
getProposal(proposalId: string): StoredProposal | undefined;
|
|
90
|
+
listPendingProposals(limit: number): StoredProposal[];
|
|
91
|
+
/** Move an inspected-but-still-pending row behind its peers, durably. */
|
|
92
|
+
deferPendingProposal(proposalId: string): void;
|
|
93
|
+
/**
|
|
94
|
+
* Apply one already-terminal policy status inside a single transaction.
|
|
95
|
+
*
|
|
96
|
+
* Both the rule change and the proposal's own settlement commit together, so a
|
|
97
|
+
* crash can never leave an approved-but-unapplied rule or an applied-but-pending
|
|
98
|
+
* proposal. Conflicts downgrade to `conflicted` rather than discarding the
|
|
99
|
+
* owner's decision.
|
|
100
|
+
*/
|
|
101
|
+
settleProposal(input: {
|
|
102
|
+
proposalId: string;
|
|
103
|
+
policyStatus?: Exclude<ProposalStatus, 'pending' | 'conflicted'>;
|
|
104
|
+
policyVersion?: number;
|
|
105
|
+
/** A shared-validator failure; never trust fields from the forged snapshot. */
|
|
106
|
+
securityConflict?: boolean;
|
|
107
|
+
/** Policy tuple already validated by the caller; re-bound under this writer lock. */
|
|
108
|
+
reviewExpectation?: EvolutionSettlementExpectation;
|
|
109
|
+
}): {
|
|
110
|
+
proposal: StoredProposal;
|
|
111
|
+
replayed: boolean;
|
|
112
|
+
rule: StoredRule | undefined;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export { digest as evolutionDigest, type RuleInput };
|
|
116
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EAIZ,uBAAuB,EACvB,iBAAiB,EACjB,8BAA8B,EAC9B,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,aAAa,EACb,cAAc,EACd,UAAU,EACX,MAAM,YAAY,CAAA;AAGnB,MAAM,MAAM,uBAAuB,GAC/B,sBAAsB,GACtB,eAAe,GACf,eAAe,GACf,WAAW,GACX,kBAAkB,CAAA;AAEtB,qBAAa,mBAAoB,SAAQ,KAAK;IAChC,QAAQ,CAAC,IAAI,EAAE,uBAAuB;gBAA7B,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,MAAM;CAIpE;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAyDD,iBAAS,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtC;AAqED;;;;;;;;GAQG;AACH,qBAAa,cAAc;;gBAOb,OAAO,EAAE,qBAAqB;IAQ1C,KAAK,IAAI,IAAI;IAIb,mEAAmE;IACnE,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa;IA4DjD,+EAA+E;IAC/E,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc;IAc1E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,EAAE;IAUxE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAM/C,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAOvE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAQ3D,8EAA8E;IAC9E,sBAAsB,CAAC,KAAK,EAAE;QAC5B,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,eAAe,EAAE,MAAM,CAAA;KACxB,GAAG,gBAAgB;IA+BpB,mBAAmB,CACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,GACtB,OAAO;IAaV,0EAA0E;IAC1E,uBAAuB,CACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,gBAAgB,GAAG,SAAS;IAc/B;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,OAAO,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,gBAAgB,EAAE,MAAM,CAAA;QACxB,iBAAiB,EAAE,MAAM,CAAA;QACzB,KAAK,EAAE,MAAM,CAAA;QACb,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAC7B,GAAG,aAAa,EAAE;IA8DnB,mFAAmF;IACnF,mBAAmB,CAAC,OAAO,EAAE;QAC3B,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,iBAAiB,EAAE,MAAM,CAAA;QACzB,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAC7B,GAAG,aAAa,GAAG,SAAS;IAwI7B,cAAc,CAAC,KAAK,EAAE;QACpB,cAAc,EAAE,MAAM,CAAA;QACtB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,iBAAiB,CAAA;QAC3B,SAAS,EAAE,MAAM,CAAA;QACjB,cAAc,CAAC,EAAE,uBAAuB,CAAA;KACzC,GAAG,cAAc;IAkDlB,YAAY,CACV,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,8BAA8B,GAC3C,cAAc;IA2CjB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAM3D,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,EAAE;IAWrD,yEAAyE;IACzE,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAS9C;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE;QACpB,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,OAAO,CAAC,cAAc,EAAE,SAAS,GAAG,YAAY,CAAC,CAAA;QAChE,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,+EAA+E;QAC/E,gBAAgB,CAAC,EAAE,OAAO,CAAA;QAC1B,qFAAqF;QACrF,iBAAiB,CAAC,EAAE,8BAA8B,CAAA;KACnD,GAAG;QAAE,QAAQ,EAAE,cAAc,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,UAAU,GAAG,SAAS,CAAA;KAAE;CAyXlF;AAED,OAAO,EAAE,MAAM,IAAI,eAAe,EAAE,KAAK,SAAS,EAAE,CAAA"}
|