hippo-memory 1.15.0 → 1.17.0
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 +862 -861
- package/dist/audit.d.ts +1 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1244 -3
- package/dist/cli.js.map +1 -1
- package/dist/customer-notes.d.ts +95 -0
- package/dist/customer-notes.d.ts.map +1 -0
- package/dist/customer-notes.js +296 -0
- package/dist/customer-notes.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +731 -1
- package/dist/db.js.map +1 -1
- package/dist/graph-extract.d.ts +55 -0
- package/dist/graph-extract.d.ts.map +1 -0
- package/dist/graph-extract.js +259 -0
- package/dist/graph-extract.js.map +1 -0
- package/dist/graph-recall.d.ts +41 -0
- package/dist/graph-recall.d.ts.map +1 -0
- package/dist/graph-recall.js +246 -0
- package/dist/graph-recall.js.map +1 -0
- package/dist/graph.d.ts +137 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +433 -0
- package/dist/graph.js.map +1 -0
- package/dist/incidents.d.ts +100 -0
- package/dist/incidents.d.ts.map +1 -0
- package/dist/incidents.js +322 -0
- package/dist/incidents.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/memory.d.ts +6 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +6 -0
- package/dist/memory.js.map +1 -1
- package/dist/policies.d.ts +149 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +380 -0
- package/dist/policies.js.map +1 -0
- package/dist/processes.d.ts +104 -0
- package/dist/processes.d.ts.map +1 -0
- package/dist/processes.js +330 -0
- package/dist/processes.js.map +1 -0
- package/dist/project-briefs.d.ts +126 -0
- package/dist/project-briefs.d.ts.map +1 -0
- package/dist/project-briefs.js +453 -0
- package/dist/project-briefs.js.map +1 -0
- package/dist/search.d.ts +7 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1028 -16
- package/dist/server.js.map +1 -1
- package/dist/skills.d.ts +98 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +339 -0
- package/dist/skills.js.map +1 -0
- package/dist/src/audit.js.map +1 -1
- package/dist/src/cli.js +1244 -3
- package/dist/src/cli.js.map +1 -1
- package/dist/src/customer-notes.js +296 -0
- package/dist/src/customer-notes.js.map +1 -0
- package/dist/src/db.js +731 -1
- package/dist/src/db.js.map +1 -1
- package/dist/src/graph-extract.js +259 -0
- package/dist/src/graph-extract.js.map +1 -0
- package/dist/src/graph-recall.js +246 -0
- package/dist/src/graph-recall.js.map +1 -0
- package/dist/src/graph.js +433 -0
- package/dist/src/graph.js.map +1 -0
- package/dist/src/incidents.js +322 -0
- package/dist/src/incidents.js.map +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/memory.js +6 -0
- package/dist/src/memory.js.map +1 -1
- package/dist/src/policies.js +380 -0
- package/dist/src/policies.js.map +1 -0
- package/dist/src/processes.js +330 -0
- package/dist/src/processes.js.map +1 -0
- package/dist/src/project-briefs.js +453 -0
- package/dist/src/project-briefs.js.map +1 -0
- package/dist/src/search.js.map +1 -1
- package/dist/src/server.js +1028 -16
- package/dist/src/server.js.map +1 -1
- package/dist/src/skills.js +339 -0
- package/dist/src/skills.js.map +1 -0
- package/dist/src/version.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2 policy first-class object (docs/plans/2026-05-30-e2-policy-object.md).
|
|
3
|
+
*
|
|
4
|
+
* The "bi-temporal-first" object type: a named rule/statement that is in force
|
|
5
|
+
* over an EFFECTIVE-TIME range and evolves via supersession. Two time axes:
|
|
6
|
+
*
|
|
7
|
+
* - Valid time (effective time): when the policy is in force in the real world,
|
|
8
|
+
* as first-class columns `valid_from` (required; defaults to creation time)
|
|
9
|
+
* and `valid_to` (nullable = open-ended). This is the queryable axis: see
|
|
10
|
+
* `loadPoliciesAsOf` (the active policies in force at a given valid-time).
|
|
11
|
+
* - Transaction time (system time): when the row was recorded / retired, via
|
|
12
|
+
* `created_at` + the supersede chain's `superseded_at`. Present, but
|
|
13
|
+
* time-travel ("what did we BELIEVE was in force at past system time T") is
|
|
14
|
+
* deferred to a future version.
|
|
15
|
+
*
|
|
16
|
+
* The delta lifecycle reuses the process/decision supersede machinery verbatim
|
|
17
|
+
* (superseded_by self-FK + CAS + INSERT-preflight + server-derived version +
|
|
18
|
+
* change_summary + supersede tenant-match trigger). It DROPS process's `steps`
|
|
19
|
+
* (a policy has `policy_text`) and ADDS `valid_from`/`valid_to`.
|
|
20
|
+
*
|
|
21
|
+
* The `policies` table is the source of truth (survives memory decay); the
|
|
22
|
+
* memory mirror is for recall only. memory_id is NULLABLE with ON DELETE SET
|
|
23
|
+
* NULL so forget/consolidate/archive gracefully orphans the policy row.
|
|
24
|
+
*
|
|
25
|
+
* Lifecycle: active -> superseded (a newer version replaces it) or active ->
|
|
26
|
+
* closed (retired with no successor). Superseding leaves the predecessor's
|
|
27
|
+
* valid-time range intact (it WAS effective then); only the status flips.
|
|
28
|
+
*
|
|
29
|
+
* Date handling: every date input (savePolicy's valid_from/valid_to,
|
|
30
|
+
* loadPoliciesAsOf's asOfDate) is normalized to canonical ISO-8601 datetime
|
|
31
|
+
* (`toISOString`) at the store boundary BEFORE any persist or compare, so the
|
|
32
|
+
* fixed-width values sort lexically and the half-open [valid_from, valid_to)
|
|
33
|
+
* comparison is correct (plan-eng-critic round-1 CRIT fix: a date-only asOf vs a
|
|
34
|
+
* datetime valid_from otherwise made a same-day policy invisible).
|
|
35
|
+
*
|
|
36
|
+
* Dual-write atomicity: `savePolicy` writes the memory + policies row (and, on
|
|
37
|
+
* supersede, the predecessor's UPDATE) inside writeEntry's SAVEPOINT.
|
|
38
|
+
*/
|
|
39
|
+
import { openHippoDb, closeHippoDb } from './db.js';
|
|
40
|
+
import { writeEntry, assertTenantId } from './store.js';
|
|
41
|
+
import { createMemory, Layer, POLICY_HALF_LIFE_DAYS } from './memory.js';
|
|
42
|
+
import { appendAuditEvent } from './audit.js';
|
|
43
|
+
export const VALID_POLICY_STATES = new Set([
|
|
44
|
+
'active',
|
|
45
|
+
'superseded',
|
|
46
|
+
'closed',
|
|
47
|
+
]);
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Date normalization + validation (the bi-temporal correctness core)
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
/**
|
|
52
|
+
* Parse + canonicalize a date input to ISO-8601 datetime (`toISOString`). Throws
|
|
53
|
+
* on an unparseable value. Whatever `new Date()` accepts is re-emitted in the
|
|
54
|
+
* single fixed-width canonical form, so date-only and datetime inputs collapse to
|
|
55
|
+
* comparable values and lexical ordering is sound. (Overflow inputs like
|
|
56
|
+
* '2026-02-30' roll forward per JS Date semantics rather than throwing; the
|
|
57
|
+
* stored value is still canonical.)
|
|
58
|
+
*/
|
|
59
|
+
export function normalizePolicyDate(input, label = 'date') {
|
|
60
|
+
const d = new Date(input);
|
|
61
|
+
if (Number.isNaN(d.getTime())) {
|
|
62
|
+
throw new Error(`policy: invalid ${label} "${input}" (expected an ISO-8601 date or datetime)`);
|
|
63
|
+
}
|
|
64
|
+
return d.toISOString();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Normalize valid_from (defaulting to `nowIso` when undefined) + valid_to (null
|
|
68
|
+
* when undefined), then enforce valid_to > valid_from. Returns the canonical pair.
|
|
69
|
+
*/
|
|
70
|
+
export function validatePolicyDates(validFromRaw, validToRaw, nowIso) {
|
|
71
|
+
const validFrom = validFromRaw !== undefined ? normalizePolicyDate(validFromRaw, 'valid_from') : nowIso;
|
|
72
|
+
const validTo = validToRaw !== undefined && validToRaw !== null
|
|
73
|
+
? normalizePolicyDate(validToRaw, 'valid_to')
|
|
74
|
+
: null;
|
|
75
|
+
if (validTo !== null && validTo <= validFrom) {
|
|
76
|
+
throw new Error(`policy: valid_to (${validTo}) must be strictly after valid_from (${validFrom})`);
|
|
77
|
+
}
|
|
78
|
+
return { validFrom, validTo };
|
|
79
|
+
}
|
|
80
|
+
function rowToPolicy(row) {
|
|
81
|
+
return {
|
|
82
|
+
id: row.id,
|
|
83
|
+
memoryId: row.memory_id,
|
|
84
|
+
tenantId: row.tenant_id,
|
|
85
|
+
policyName: row.policy_name,
|
|
86
|
+
policyText: row.policy_text,
|
|
87
|
+
validFrom: row.valid_from,
|
|
88
|
+
validTo: row.valid_to,
|
|
89
|
+
version: row.version,
|
|
90
|
+
status: row.status,
|
|
91
|
+
supersededBy: row.superseded_by,
|
|
92
|
+
supersededAt: row.superseded_at,
|
|
93
|
+
changeSummary: row.change_summary,
|
|
94
|
+
closedAt: row.closed_at,
|
|
95
|
+
createdAt: row.created_at,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const POLICY_COLS = `
|
|
99
|
+
id, memory_id, tenant_id, policy_name, policy_text, valid_from, valid_to,
|
|
100
|
+
version, status, superseded_by, superseded_at, change_summary, closed_at, created_at
|
|
101
|
+
`;
|
|
102
|
+
/** Recall-surface content for the memory mirror: name + rule + effective range. */
|
|
103
|
+
function buildPolicyContent(policyName, policyText, validFrom, validTo) {
|
|
104
|
+
const range = validTo ? `${validFrom} to ${validTo}` : `${validFrom} onward`;
|
|
105
|
+
return `${policyName}\n\n${policyText}\n\nEffective: ${range}`;
|
|
106
|
+
}
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Public API
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
/**
|
|
111
|
+
* Create a policy (or a new version that supersedes an existing one). Writes the
|
|
112
|
+
* memory mirror + the policies row atomically inside writeEntry's SAVEPOINT.
|
|
113
|
+
* valid_from defaults to now; valid_to must be > valid_from (validatePolicyDates).
|
|
114
|
+
* When supersedesPolicyId is given, the referenced ACTIVE row is preflighted
|
|
115
|
+
* (status + version) BEFORE the INSERT, then CAS-UPDATEd -> superseded in the same
|
|
116
|
+
* SAVEPOINT; the new version = predecessor.version + 1 (server-derived).
|
|
117
|
+
*/
|
|
118
|
+
export function savePolicy(hippoRoot, tenantId, opts, actor = 'cli') {
|
|
119
|
+
assertTenantId('savePolicy', tenantId);
|
|
120
|
+
if (!opts.policyName || opts.policyName.trim().length === 0) {
|
|
121
|
+
throw new Error('savePolicy: policyName is required');
|
|
122
|
+
}
|
|
123
|
+
if (!opts.policyText || opts.policyText.trim().length === 0) {
|
|
124
|
+
throw new Error('savePolicy: policyText is required');
|
|
125
|
+
}
|
|
126
|
+
const now = new Date().toISOString();
|
|
127
|
+
// valid_from defaults to the precise creation instant (the honest effective
|
|
128
|
+
// time). The same-day date-only as-of workflow is handled on the READ side
|
|
129
|
+
// (a date-only asOf resolves to end-of-day in loadPoliciesAsOf), NOT by
|
|
130
|
+
// backdating the stored valid_from - backdating to midnight would make an
|
|
131
|
+
// earlier-same-day as-of wrongly report the policy already in force and would
|
|
132
|
+
// hide a superseded predecessor for that earlier time (codex review
|
|
133
|
+
// 2026-05-30 round 2). An explicit --from is honored as-is.
|
|
134
|
+
const { validFrom, validTo } = validatePolicyDates(opts.validFrom, opts.validTo, now);
|
|
135
|
+
const isSupersede = opts.supersedesPolicyId !== undefined;
|
|
136
|
+
const changeSummary = isSupersede ? (opts.changeSummary ?? null) : null;
|
|
137
|
+
const content = buildPolicyContent(opts.policyName, opts.policyText, validFrom, validTo);
|
|
138
|
+
const tags = ['policy', ...(opts.extraTags ?? [])];
|
|
139
|
+
const mem = createMemory(content, {
|
|
140
|
+
tags,
|
|
141
|
+
layer: Layer.Semantic,
|
|
142
|
+
confidence: 'verified',
|
|
143
|
+
source: 'policy',
|
|
144
|
+
tenantId,
|
|
145
|
+
});
|
|
146
|
+
mem.half_life_days = POLICY_HALF_LIFE_DAYS;
|
|
147
|
+
let savedRow;
|
|
148
|
+
writeEntry(hippoRoot, mem, {
|
|
149
|
+
actor,
|
|
150
|
+
afterWrite: (db, memoryId) => {
|
|
151
|
+
// Preflight the supersede target BEFORE inserting the new row (so the new
|
|
152
|
+
// autoincrement id can never be its own supersede target); read the
|
|
153
|
+
// predecessor version in the same SELECT for server-derived versioning.
|
|
154
|
+
// Mirrors saveProcess / saveDecision (codex P1 2026-05-28).
|
|
155
|
+
let version = 1;
|
|
156
|
+
if (opts.supersedesPolicyId !== undefined) {
|
|
157
|
+
const pred = db.prepare(`SELECT status, version FROM policies WHERE id = ? AND tenant_id = ?`).get(opts.supersedesPolicyId, tenantId);
|
|
158
|
+
if (!pred) {
|
|
159
|
+
throw new Error(`savePolicy: policy ${opts.supersedesPolicyId} to supersede not found for tenant ${tenantId}`);
|
|
160
|
+
}
|
|
161
|
+
if (pred.status !== 'active') {
|
|
162
|
+
throw new Error(`savePolicy: policy ${opts.supersedesPolicyId} is not active (status='${pred.status}'); only active policies can be superseded.`);
|
|
163
|
+
}
|
|
164
|
+
version = pred.version + 1;
|
|
165
|
+
}
|
|
166
|
+
const result = db.prepare(`
|
|
167
|
+
INSERT INTO policies(
|
|
168
|
+
memory_id, tenant_id, policy_name, policy_text, valid_from, valid_to,
|
|
169
|
+
version, status, superseded_by, superseded_at, change_summary, closed_at, created_at
|
|
170
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, NULL, ?)
|
|
171
|
+
`).run(memoryId, tenantId, opts.policyName, opts.policyText, validFrom, validTo, version, changeSummary, now);
|
|
172
|
+
const policyId = Number(result.lastInsertRowid ?? 0);
|
|
173
|
+
if (opts.supersedesPolicyId !== undefined) {
|
|
174
|
+
const sup = db.prepare(`
|
|
175
|
+
UPDATE policies
|
|
176
|
+
SET status = 'superseded', superseded_by = ?, superseded_at = ?
|
|
177
|
+
WHERE id = ? AND tenant_id = ? AND status = 'active' AND id != ?
|
|
178
|
+
`).run(policyId, now, opts.supersedesPolicyId, tenantId, policyId);
|
|
179
|
+
if (sup.changes === 0) {
|
|
180
|
+
throw new Error(`savePolicy: policy ${opts.supersedesPolicyId} could not be superseded (no longer active or self-reference).`);
|
|
181
|
+
}
|
|
182
|
+
appendAuditEvent(db, {
|
|
183
|
+
tenantId,
|
|
184
|
+
actor,
|
|
185
|
+
op: 'policy_supersede',
|
|
186
|
+
targetId: String(opts.supersedesPolicyId),
|
|
187
|
+
metadata: {
|
|
188
|
+
policy_id: opts.supersedesPolicyId,
|
|
189
|
+
superseded_by: policyId,
|
|
190
|
+
new_version: version,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const row = db.prepare(`SELECT ${POLICY_COLS} FROM policies WHERE id = ?`)
|
|
195
|
+
.get(policyId);
|
|
196
|
+
if (!row)
|
|
197
|
+
throw new Error('savePolicy: failed to reload saved policy row');
|
|
198
|
+
savedRow = row;
|
|
199
|
+
// GDPR-light metadata: ids + flags only, no policy text.
|
|
200
|
+
appendAuditEvent(db, {
|
|
201
|
+
tenantId,
|
|
202
|
+
actor,
|
|
203
|
+
op: 'policy_create',
|
|
204
|
+
targetId: String(policyId),
|
|
205
|
+
metadata: {
|
|
206
|
+
policy_id: policyId,
|
|
207
|
+
version,
|
|
208
|
+
open_ended: validTo === null,
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
if (!savedRow) {
|
|
214
|
+
throw new Error('savePolicy: afterWrite did not populate the row');
|
|
215
|
+
}
|
|
216
|
+
return rowToPolicy(savedRow);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Close (retire) an active policy with no successor. CAS guard WHERE
|
|
220
|
+
* status='active'; 0 changes distinguishes not-found from not-active. A
|
|
221
|
+
* superseded row is terminal and cannot be closed.
|
|
222
|
+
*/
|
|
223
|
+
export function closePolicy(hippoRoot, tenantId, id, actor = 'cli') {
|
|
224
|
+
assertTenantId('closePolicy', tenantId);
|
|
225
|
+
const now = new Date().toISOString();
|
|
226
|
+
const db = openHippoDb(hippoRoot);
|
|
227
|
+
try {
|
|
228
|
+
db.exec('BEGIN IMMEDIATE');
|
|
229
|
+
try {
|
|
230
|
+
const updateResult = db.prepare(`
|
|
231
|
+
UPDATE policies
|
|
232
|
+
SET status = 'closed', closed_at = ?
|
|
233
|
+
WHERE id = ? AND tenant_id = ? AND status = 'active'
|
|
234
|
+
`).run(now, id, tenantId);
|
|
235
|
+
if (updateResult.changes === 0) {
|
|
236
|
+
const existing = db.prepare(`SELECT status FROM policies WHERE id = ? AND tenant_id = ?`).get(id, tenantId);
|
|
237
|
+
if (!existing) {
|
|
238
|
+
throw new Error(`closePolicy: policy ${id} not found for tenant ${tenantId}`);
|
|
239
|
+
}
|
|
240
|
+
throw new Error(`closePolicy: policy ${id} is not active (status='${existing.status}'); only active policies can be closed.`);
|
|
241
|
+
}
|
|
242
|
+
const row = db.prepare(`SELECT ${POLICY_COLS} FROM policies WHERE id = ? AND tenant_id = ?`)
|
|
243
|
+
.get(id, tenantId);
|
|
244
|
+
if (!row)
|
|
245
|
+
throw new Error(`closePolicy: policy ${id} not found after UPDATE`);
|
|
246
|
+
appendAuditEvent(db, {
|
|
247
|
+
tenantId,
|
|
248
|
+
actor,
|
|
249
|
+
op: 'policy_close',
|
|
250
|
+
targetId: String(id),
|
|
251
|
+
metadata: { policy_id: id },
|
|
252
|
+
});
|
|
253
|
+
db.exec('COMMIT');
|
|
254
|
+
return rowToPolicy(row);
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
try {
|
|
258
|
+
db.exec('ROLLBACK');
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Ignore rollback failures — the throw below is what matters.
|
|
262
|
+
}
|
|
263
|
+
throw e;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
finally {
|
|
267
|
+
closeHippoDb(db);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export function loadPolicyById(hippoRoot, tenantId, id) {
|
|
271
|
+
assertTenantId('loadPolicyById', tenantId);
|
|
272
|
+
const db = openHippoDb(hippoRoot);
|
|
273
|
+
try {
|
|
274
|
+
const row = db.prepare(`SELECT ${POLICY_COLS} FROM policies WHERE id = ? AND tenant_id = ?`)
|
|
275
|
+
.get(id, tenantId);
|
|
276
|
+
return row ? rowToPolicy(row) : null;
|
|
277
|
+
}
|
|
278
|
+
finally {
|
|
279
|
+
closeHippoDb(db);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
export function loadPolicies(hippoRoot, tenantId, opts = {}) {
|
|
283
|
+
assertTenantId('loadPolicies', tenantId);
|
|
284
|
+
const limit = opts.limit ?? 100;
|
|
285
|
+
const db = openHippoDb(hippoRoot);
|
|
286
|
+
try {
|
|
287
|
+
let rows;
|
|
288
|
+
if (opts.status) {
|
|
289
|
+
if (!VALID_POLICY_STATES.has(opts.status)) {
|
|
290
|
+
throw new Error(`loadPolicies: status must be one of ${Array.from(VALID_POLICY_STATES).join('|')}; got ${opts.status}`);
|
|
291
|
+
}
|
|
292
|
+
rows = db.prepare(`
|
|
293
|
+
SELECT ${POLICY_COLS} FROM policies
|
|
294
|
+
WHERE tenant_id = ? AND status = ?
|
|
295
|
+
ORDER BY created_at DESC, id DESC
|
|
296
|
+
LIMIT ?
|
|
297
|
+
`).all(tenantId, opts.status, limit);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
rows = db.prepare(`
|
|
301
|
+
SELECT ${POLICY_COLS} FROM policies
|
|
302
|
+
WHERE tenant_id = ?
|
|
303
|
+
ORDER BY created_at DESC, id DESC
|
|
304
|
+
LIMIT ?
|
|
305
|
+
`).all(tenantId, limit);
|
|
306
|
+
}
|
|
307
|
+
return rows.map(rowToPolicy);
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
closeHippoDb(db);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
export function loadActivePolicies(hippoRoot, tenantId, opts = {}) {
|
|
314
|
+
return loadPolicies(hippoRoot, tenantId, { status: 'active', limit: opts.limit });
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* The bi-temporal as-of query: the policies in force at `asOfDate` (a valid-time)
|
|
318
|
+
* per current knowledge. Half-open interval [valid_from, valid_to): a row covers
|
|
319
|
+
* T when valid_from <= asOf AND (valid_to IS NULL OR asOf < valid_to). asOfDate is
|
|
320
|
+
* normalized to canonical datetime first so the lexical comparison is sound.
|
|
321
|
+
*
|
|
322
|
+
* A row is returned when it covers T AND it is the live answer for T:
|
|
323
|
+
* - `active` rows that cover T, OR
|
|
324
|
+
* - `superseded` rows that cover T BUT whose successor was not yet effective at T
|
|
325
|
+
* (successor.valid_from > asOf) - i.e. an earlier version that was genuinely in
|
|
326
|
+
* force then. This is the core valid-time correctness: a Jan-Jun policy
|
|
327
|
+
* superseded in May is still the answer for `asof March`. (codex review
|
|
328
|
+
* 2026-05-30, P2 #2: filtering on status='active' alone dropped historically-
|
|
329
|
+
* valid superseded versions, conflating transaction-time with valid-time. The
|
|
330
|
+
* successor-aware filter mirrors the existing recall-history.ts asOf pattern.)
|
|
331
|
+
*
|
|
332
|
+
* `closed` rows are EXCLUDED: closing is a deliberate transaction-time retirement,
|
|
333
|
+
* and resurrecting closed policies for a historical valid-time is full
|
|
334
|
+
* transaction-time-travel (deferred). Returns an ARRAY (overlapping same-name
|
|
335
|
+
* ranges are allowed in v1). Optionally filtered to one policy_name.
|
|
336
|
+
*
|
|
337
|
+
* Date-only `asOfDate` (e.g. "2026-05-30", no time component) resolves to the END
|
|
338
|
+
* of that UTC day (23:59:59.999Z), so "as of [day D]" includes a policy that
|
|
339
|
+
* became effective at any instant during D - this is the read-side fix for the
|
|
340
|
+
* common create-then-asof-today workflow, keeping the stored valid_from honest
|
|
341
|
+
* (codex review 2026-05-30). A full datetime asOf is used as the precise instant.
|
|
342
|
+
*/
|
|
343
|
+
export function loadPoliciesAsOf(hippoRoot, tenantId, asOfDate, opts = {}) {
|
|
344
|
+
assertTenantId('loadPoliciesAsOf', tenantId);
|
|
345
|
+
// A bare date means "as of (the whole of) that day" -> end-of-day instant; a
|
|
346
|
+
// datetime is used precisely. normalizePolicyDate validates/canonicalizes both.
|
|
347
|
+
const asOf = /^\d{4}-\d{2}-\d{2}$/.test(asOfDate.trim())
|
|
348
|
+
? normalizePolicyDate(`${asOfDate.trim()}T23:59:59.999Z`, 'asOfDate')
|
|
349
|
+
: normalizePolicyDate(asOfDate, 'asOfDate');
|
|
350
|
+
const limit = opts.limit ?? 100;
|
|
351
|
+
const db = openHippoDb(hippoRoot);
|
|
352
|
+
try {
|
|
353
|
+
// LEFT JOIN the successor so a superseded row is kept only while its
|
|
354
|
+
// successor is not yet effective at asOf. p.status != 'closed' drops retired
|
|
355
|
+
// rows; the OR keeps active heads + still-in-force superseded versions.
|
|
356
|
+
const nameClause = opts.name !== undefined ? 'AND p.policy_name = ?' : '';
|
|
357
|
+
const params = [tenantId, asOf, asOf, asOf];
|
|
358
|
+
if (opts.name !== undefined)
|
|
359
|
+
params.push(opts.name);
|
|
360
|
+
params.push(limit);
|
|
361
|
+
const rows = db.prepare(`
|
|
362
|
+
SELECT p.id, p.memory_id, p.tenant_id, p.policy_name, p.policy_text,
|
|
363
|
+
p.valid_from, p.valid_to, p.version, p.status, p.superseded_by,
|
|
364
|
+
p.superseded_at, p.change_summary, p.closed_at, p.created_at
|
|
365
|
+
FROM policies p
|
|
366
|
+
LEFT JOIN policies s ON s.id = p.superseded_by
|
|
367
|
+
WHERE p.tenant_id = ? AND p.status != 'closed'
|
|
368
|
+
AND p.valid_from <= ? AND (p.valid_to IS NULL OR ? < p.valid_to)
|
|
369
|
+
AND (p.status = 'active' OR (s.id IS NOT NULL AND s.valid_from > ?))
|
|
370
|
+
${nameClause}
|
|
371
|
+
ORDER BY p.valid_from DESC, p.id DESC
|
|
372
|
+
LIMIT ?
|
|
373
|
+
`).all(...params);
|
|
374
|
+
return rows.map(rowToPolicy);
|
|
375
|
+
}
|
|
376
|
+
finally {
|
|
377
|
+
closeHippoDb(db);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=policies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.js","sourceRoot":"","sources":["../../src/policies.ts"],"names":[],"mappings":"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"}
|