@openpond/evals 0.11.20 → 0.11.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/connected-evidence/collector-coverage-contracts.js +160 -0
  2. package/dist/connected-evidence/index.js +1 -0
  3. package/dist/execution-contracts.js +1 -1
  4. package/dist/javascript-isolate-node.js +2 -1
  5. package/dist/javascript-isolate-process-source.js +1 -1
  6. package/dist/javascript-isolate-process.js +2 -1
  7. package/dist/javascript-isolate.js +2 -1
  8. package/dist/javascript-verifier-worker-source.js +1 -1
  9. package/dist/native-conversations/codex-window-inventory.js +97 -0
  10. package/dist/native-conversations/collector-acquisition.js +149 -0
  11. package/dist/native-conversations/collector-branches.js +1 -0
  12. package/dist/native-conversations/collector-calendar-gate.js +19 -0
  13. package/dist/native-conversations/collector-contracts.js +4 -3
  14. package/dist/native-conversations/collector-coverage.js +100 -0
  15. package/dist/native-conversations/collector-cron.js +43 -0
  16. package/dist/native-conversations/collector-schedule.js +61 -0
  17. package/dist/native-conversations/collector-service-files.js +51 -0
  18. package/dist/native-conversations/collector-snapshots.js +70 -0
  19. package/dist/native-conversations/collector-source-cache.js +41 -0
  20. package/dist/native-conversations/collector-store.js +43 -8
  21. package/dist/native-conversations/collector.js +189 -261
  22. package/dist/native-conversations/history.js +9 -0
  23. package/dist/native-conversations/index.js +1 -0
  24. package/dist/native-conversations/location.js +4 -2
  25. package/dist/native-conversations/supervisor.js +131 -81
  26. package/dist/sql-execution-node.js +2 -1
  27. package/dist/tasksets.js +1 -1
  28. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts +98 -0
  29. package/dist/types/connected-evidence/collector-coverage-contracts.d.ts.map +1 -0
  30. package/dist/types/connected-evidence/index.d.ts +1 -0
  31. package/dist/types/connected-evidence/index.d.ts.map +1 -1
  32. package/dist/types/javascript-isolate-node.d.ts.map +1 -1
  33. package/dist/types/javascript-isolate-process.d.ts.map +1 -1
  34. package/dist/types/javascript-isolate.d.ts.map +1 -1
  35. package/dist/types/native-conversations/codex-window-inventory.d.ts +12 -0
  36. package/dist/types/native-conversations/codex-window-inventory.d.ts.map +1 -0
  37. package/dist/types/native-conversations/collector-acquisition.d.ts +17 -0
  38. package/dist/types/native-conversations/collector-acquisition.d.ts.map +1 -0
  39. package/dist/types/native-conversations/collector-branches.d.ts.map +1 -1
  40. package/dist/types/native-conversations/collector-calendar-gate.d.ts +9 -0
  41. package/dist/types/native-conversations/collector-calendar-gate.d.ts.map +1 -0
  42. package/dist/types/native-conversations/collector-contracts.d.ts +41 -5
  43. package/dist/types/native-conversations/collector-contracts.d.ts.map +1 -1
  44. package/dist/types/native-conversations/collector-coverage.d.ts +62 -0
  45. package/dist/types/native-conversations/collector-coverage.d.ts.map +1 -0
  46. package/dist/types/native-conversations/collector-cron.d.ts +20 -0
  47. package/dist/types/native-conversations/collector-cron.d.ts.map +1 -0
  48. package/dist/types/native-conversations/collector-schedule.d.ts +13 -0
  49. package/dist/types/native-conversations/collector-schedule.d.ts.map +1 -0
  50. package/dist/types/native-conversations/collector-service-files.d.ts +20 -0
  51. package/dist/types/native-conversations/collector-service-files.d.ts.map +1 -0
  52. package/dist/types/native-conversations/collector-snapshots.d.ts +25 -0
  53. package/dist/types/native-conversations/collector-snapshots.d.ts.map +1 -0
  54. package/dist/types/native-conversations/collector-source-cache.d.ts +31 -0
  55. package/dist/types/native-conversations/collector-source-cache.d.ts.map +1 -0
  56. package/dist/types/native-conversations/collector-store.d.ts +11 -2
  57. package/dist/types/native-conversations/collector-store.d.ts.map +1 -1
  58. package/dist/types/native-conversations/collector.d.ts +5 -1
  59. package/dist/types/native-conversations/collector.d.ts.map +1 -1
  60. package/dist/types/native-conversations/history.d.ts +7 -0
  61. package/dist/types/native-conversations/history.d.ts.map +1 -1
  62. package/dist/types/native-conversations/index.d.ts +1 -0
  63. package/dist/types/native-conversations/index.d.ts.map +1 -1
  64. package/dist/types/native-conversations/location.d.ts.map +1 -1
  65. package/dist/types/native-conversations/supervisor.d.ts +4 -3
  66. package/dist/types/native-conversations/supervisor.d.ts.map +1 -1
  67. package/dist/types/sql-execution-node.d.ts.map +1 -1
  68. package/package.json +3 -2
  69. package/schemas/learning/v1/package.schema.json +0 -1
@@ -0,0 +1,41 @@
1
+ import { contentHash } from "@openpond/harness";
2
+ import { CollectorCoverageSessionSchema } from "../connected-evidence/collector-coverage-contracts.js";
3
+ /** Reuse a settled source read only for the same revision and event-time window.
4
+ * Admission remains owned by the durable queue and boundary checkpoints. */
5
+ export class CollectorSourceCache {
6
+ store;
7
+ constructor(store) {
8
+ this.store = store;
9
+ store.database.exec(`CREATE TABLE IF NOT EXISTS source_read_cache(
10
+ connection_id TEXT NOT NULL,session_key TEXT NOT NULL,selection_hash TEXT NOT NULL,value TEXT NOT NULL,
11
+ PRIMARY KEY(connection_id,session_key));`);
12
+ }
13
+ selection(connection, until, revision) {
14
+ return contentHash([connection.source, connection.projectId, connection.teamId,
15
+ connection.apiBaseUrl, connection.account ?? null, connection.since, until, revision]);
16
+ }
17
+ read(connection, until, sessionKey, revision) {
18
+ const row = this.store.database.prepare("SELECT value FROM source_read_cache WHERE connection_id=? AND session_key=? AND selection_hash=?").get(connection.id, sessionKey, this.selection(connection, until, revision));
19
+ return row ? CollectorCoverageSessionSchema.parse(JSON.parse(String(row.value))) : null;
20
+ }
21
+ retain(connection, until, sessionKey, revision, raw) {
22
+ const value = CollectorCoverageSessionSchema.parse(raw);
23
+ if (value.nativeRevisionHash === null || (value.state !== "admitted"
24
+ && !(value.state === "skipped" && value.reason === "no_eligible_boundaries")))
25
+ return;
26
+ this.store.database.prepare("INSERT INTO source_read_cache VALUES(?,?,?,?) ON CONFLICT(connection_id,session_key) DO UPDATE SET selection_hash=excluded.selection_hash,value=excluded.value").run(connection.id, sessionKey, this.selection(connection, until, revision), JSON.stringify(value));
27
+ }
28
+ /** Earlier collectors retained both scan revisions and settled coverage.
29
+ * Preserve that evidence when upgrading a partially completed import. */
30
+ seed(connection, until, prior) {
31
+ if (!prior || prior.connectionRevision !== connection.revision || prior.from !== connection.since
32
+ || prior.to !== until || prior.sourceInstanceId !== connection.source.instanceId || prior.machineId !== connection.source.machineId)
33
+ return;
34
+ const byKey = new Map(prior.sessions.map(session => [session.sourceKeyHash, session]));
35
+ for (const row of this.store.database.prepare("SELECT session_key,revision FROM source_scans WHERE connection_id=?").all(connection.id)) {
36
+ const key = String(row.session_key), value = byKey.get(contentHash(key));
37
+ if (value)
38
+ this.retain(connection, until, key, String(row.revision), value);
39
+ }
40
+ }
41
+ }
@@ -4,12 +4,19 @@ import { join } from "node:path";
4
4
  import { COLLECTOR_DEFAULTS } from "./collector-contracts.js";
5
5
  import { collectorDestinationLinks } from "./collector-destinations.js";
6
6
  import { CollectorProgress } from "./collector-progress.js";
7
+ import { CollectorCoverage } from "./collector-coverage.js";
8
+ import { CollectorSnapshots, CollectorQueueFullError } from "./collector-snapshots.js";
9
+ import { nextScheduledSync, validateCollectorSchedule } from "./collector-schedule.js";
7
10
  export class CollectorStore {
8
11
  database;
9
12
  progress;
13
+ snapshots;
14
+ coverage;
10
15
  constructor(database) {
11
16
  this.database = database;
12
17
  this.progress = new CollectorProgress(database);
18
+ this.snapshots = new CollectorSnapshots(database);
19
+ this.coverage = new CollectorCoverage(this);
13
20
  }
14
21
  static async open(directory) {
15
22
  await mkdir(directory, { recursive: true, mode: 0o700 });
@@ -63,6 +70,8 @@ export class CollectorStore {
63
70
  if (identityChanged)
64
71
  connection = { ...connection, destinations: undefined };
65
72
  if (prior && (identityChanged || prior.since !== connection.since)) {
73
+ this.database.prepare("DELETE FROM settings WHERE key=?").run(`coverage:${connection.id}`);
74
+ this.database.prepare("DELETE FROM coverage_sessions WHERE connection_id=?").run(connection.id);
66
75
  // Scope changes fence queued evidence too: do not upload a wider old
67
76
  // selection under newly narrowed consent. Reacquire the approved scope.
68
77
  this.progress.reset(connection.id);
@@ -76,6 +85,7 @@ export class CollectorStore {
76
85
  this.database
77
86
  .prepare(`DELETE FROM ${table} WHERE connection_id=?`)
78
87
  .run(connection.id);
88
+ this.snapshots.collect();
79
89
  if (identityChanged) {
80
90
  this.database
81
91
  .prepare("DELETE FROM admitted_boundaries WHERE connection_id=?")
@@ -134,16 +144,22 @@ export class CollectorStore {
134
144
  .prepare("SELECT revision FROM checkpoints WHERE connection_id=? AND session_key=? AND boundary_id=?")
135
145
  .get(connectionId, sessionKey, boundaryId)?.revision !== revision);
136
146
  }
137
- enqueue(entry, revisions, progressSessionKey) {
138
- const payload = JSON.stringify(entry), bytes = Buffer.byteLength(payload);
147
+ enqueue(entry, revisions, progressSessionKey, snapshot = this.snapshots.prepare(entry.files)) {
148
+ const { files: _files, ...metadata } = entry;
149
+ const payload = JSON.stringify(metadata), bytes = Buffer.byteLength(payload);
139
150
  this.database.exec("BEGIN IMMEDIATE");
140
151
  try {
152
+ if (this.database.prepare("SELECT 1 FROM pending WHERE id=?").get(entry.operationId)) {
153
+ this.database.exec("COMMIT");
154
+ return;
155
+ }
141
156
  const usage = this.database
142
157
  .prepare("SELECT COUNT(*) AS count,COALESCE(SUM(bytes),0) AS bytes FROM pending")
143
158
  .get();
144
159
  if (Number(usage.count) >= COLLECTOR_DEFAULTS.maxPending ||
145
- Number(usage.bytes) + bytes > COLLECTOR_DEFAULTS.maxBytes)
146
- throw new Error("Buffer full. Restore connectivity before acquiring more history.");
160
+ Number(usage.bytes) + this.snapshots.bytes() + bytes + (this.snapshots.exists(snapshot.hash) ? 0 : snapshot.bytes) > COLLECTOR_DEFAULTS.maxBytes)
161
+ throw new CollectorQueueFullError();
162
+ this.snapshots.retain(entry.operationId, snapshot);
147
163
  this.database
148
164
  .prepare("INSERT OR IGNORE INTO pending(id,connection_id,payload,bytes,created_at) VALUES(?,?,?,?,?)")
149
165
  .run(entry.operationId, entry.connectionId, payload, bytes, Date.now());
@@ -161,11 +177,11 @@ export class CollectorStore {
161
177
  }
162
178
  next(connectionId) {
163
179
  const row = this.database
164
- .prepare("SELECT payload,attempts FROM pending WHERE connection_id=? AND retry_at <= ? ORDER BY created_at,id LIMIT 1")
165
- .get(connectionId, Date.now());
180
+ .prepare("SELECT id,payload,attempts FROM pending WHERE connection_id=? ORDER BY created_at,id LIMIT 1")
181
+ .get(connectionId);
166
182
  return row
167
183
  ? {
168
- entry: JSON.parse(String(row.payload)),
184
+ entry: { ...JSON.parse(String(row.payload)), files: this.snapshots.files(String(row.id)) },
169
185
  attempts: Number(row.attempts),
170
186
  }
171
187
  : null;
@@ -177,6 +193,7 @@ export class CollectorStore {
177
193
  .prepare("DELETE FROM pending WHERE id=?")
178
194
  .run(entry.operationId);
179
195
  if (Number(removed.changes) > 0) {
196
+ this.snapshots.collect();
180
197
  this.progress.acknowledge(entry.operationId);
181
198
  this.set(`lastAdmission:${entry.connectionId}`, new Date().toISOString());
182
199
  let admitted = 0;
@@ -200,6 +217,10 @@ export class CollectorStore {
200
217
  .prepare("UPDATE pending SET attempts=?,retry_at=? WHERE id=?")
201
218
  .run(attempts + 1, Date.now() + delay + Math.floor(Math.random() * Math.max(1, delay / 5)), id);
202
219
  }
220
+ schedule(id) {
221
+ const stored = this.setting(`schedule:${id}`);
222
+ return stored ? validateCollectorSchedule(JSON.parse(stored)) : null;
223
+ }
203
224
  status() {
204
225
  const heartbeatAt = this.setting("heartbeatAt"), pid = Number(this.setting("pid")) || null;
205
226
  let alive = false;
@@ -218,11 +239,19 @@ export class CollectorStore {
218
239
  desiredState: this.setting("desiredState") === "running" ? "running" : "stopped",
219
240
  pid,
220
241
  heartbeatAt,
242
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
221
243
  connections: this.database
222
244
  .prepare("SELECT id,config,admitted,error FROM connections ORDER BY id")
223
245
  .all()
224
246
  .map((row) => {
225
247
  const config = JSON.parse(String(row.config));
248
+ const schedule = this.schedule(String(row.id));
249
+ const retainedRun = this.setting(`run:${row.id}`);
250
+ const run = retainedRun ? JSON.parse(retainedRun) : null;
251
+ if (run?.state === "running" && !alive) {
252
+ run.state = "failed";
253
+ run.error = "The import was interrupted before completion. Run Sync now to resume.";
254
+ }
226
255
  return {
227
256
  id: String(row.id),
228
257
  state: config.state,
@@ -236,10 +265,16 @@ export class CollectorStore {
236
265
  admitted: Number(row.admitted),
237
266
  error: typeof row.error === "string" ? row.error : null,
238
267
  backfill: this.progress.status(String(row.id)),
239
- pendingBytes: Number(this.database
268
+ pendingBytes: this.snapshots.bytes(String(row.id)) + Number(this.database
240
269
  .prepare("SELECT COALESCE(SUM(bytes),0) AS bytes FROM pending WHERE connection_id=?")
241
270
  .get(String(row.id))?.bytes ?? 0),
242
271
  lastAdmissionAt: this.setting(`lastAdmission:${row.id}`),
272
+ since: config.since,
273
+ schedule,
274
+ nextRunAt: schedule && config.state === "active" ? nextScheduledSync(schedule) : null,
275
+ lastSuccessfulSyncAt: this.setting(`lastSuccess:${row.id}`),
276
+ run,
277
+ coverage: this.coverage.summary(String(row.id)),
243
278
  requestedSyncRevision: config.requestedSyncRevision ?? 0,
244
279
  completedSyncRevision: config.completedSyncRevision ?? 0,
245
280
  acknowledgedSyncRevision: Number(this.setting(`syncAcknowledged:${row.id}`)) || 0,