Files
goodbuddy/scripts/supervision-navigation-replay.ts
mesalogo d80d42b032 feat(storage): move desktop SQLite ownership into a storage utility process
Main no longer opens desktop business SQLite. A single utility-process
storage owner holds the Assistant, Knowledge, attachment, document-result,
remote-binding and native model-ledger databases and runs whole domain
transactions; Main and Runtime callers use explicit async domain operations.

- Remove the Main readWithFallback path and the supervision worker's
  separate business write connection; manifests are scanned read-only and
  committed by the sole writer.
- Remote events are ACKed only after commit; process loss reports
  unconfirmed writes instead of replaying them.
- Use native utilityProcess messaging with one in-flight bound (32) and
  ordered waiting instead of capacity rejection and retries.
- Start the storage process before the window so startup overlaps.
- Keep short tool output in memory and store full output once in owned
  storage; paging, branching, restart and deletion reuse that copy.
- Put required runtime launch files under goodbuddy-prefixed owned temp
  directories and reclaim confirmed stale ones; stop writing duplicate
  parsed.md.
- Add lint guards for SQLite ownership and architecture, concurrency
  acceptance fixtures, and maintenance/architecture documentation.

Validation: typecheck and lint pass. Alternating baseline (edf019aa) vs
candidate runs show no regression on single-session, C01, C02, C04 and a
5-minute C06; Main p99 drops from ~21 ms to ~16.7 ms under concurrency.
Fresh portable copy (1.75M events) upgrade content unchanged; real-model
output paging passes with 4 external requests. Full npm test runs had
1-9 different timing-sensitive failures per run that pass when rerun.
Not covered: C03 review publication, C07 source body, app-level C05.
2026-10-06 15:40:18 +08:00

55 lines
3.4 KiB
TypeScript

// Offline production-factory replay. The source is read-only; only a new backup is initialized.
import assert from 'node:assert/strict'
import { DatabaseSync, backup } from 'node:sqlite'
import { cpSync, existsSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'node:path'
import { AssistantDatabase } from '../src/main/assistant/assistant-database'
import { createProductionSupervisorService } from '../src/main/assistant/supervision-production'
import { SupervisionModelPool } from '../src/main/assistant/supervision-model-pool'
import type { AgentRuntime } from '../src/main/agent/runtime'
import { asyncSupervisionStorage } from '../tests/support/async-supervision-storage'
async function main() {
const [sourcePath, destinationPath, runId] = process.argv.slice(2)
assert(sourcePath && destinationPath && runId)
assert(resolve(sourcePath) !== resolve(destinationPath) && !existsSync(destinationPath))
const source = new DatabaseSync(sourcePath, { readOnly: true })
const before = source.prepare('SELECT * FROM supervision_runs WHERE id = ?').get(runId)
assert(before)
const cached = source.prepare('SELECT output_json FROM supervision_review_navigation WHERE run_id = ? LIMIT 1').get(runId)
assert(cached, 'Replay requires a saved navigation response')
const { summary, changeDigest, openItems } = JSON.parse(String(cached.output_json))
await backup(source, destinationPath)
const notes = join(dirname(sourcePath), 'notes')
const copiedNotes = join(dirname(destinationPath), 'notes')
if (existsSync(notes) && !existsSync(copiedNotes)) cpSync(notes, copiedNotes, { recursive: true })
const db = new AssistantDatabase(destinationPath)
const pool = new SupervisionModelPool()
let calls = 0
const run: AgentRuntime['run'] = async function* (input) {
assert(input.prompt.includes('These inputs are navigation summaries'), 'No successful leaf may be replayed')
calls++
yield { type: 'text', requestId: input.requestId, delta: JSON.stringify({ summary, changeDigest, openItems }) }
yield { type: 'done', requestId: input.requestId }
}
try {
db.initialize(dirname(destinationPath))
const store = db.supervisionReviewStore()
const leaves = store.batches(runId, 20)
assert.equal(leaves.length, 6)
assert.equal(store.progress(runId).remainingSources, 0)
const service = createProductionSupervisorService(asyncSupervisionStorage(db).supervision, async () => ({ supervisorModelConcurrency: 1 }),
async () => ({ runtimeId: 'offline-replay', capability: 'chat', run } as AgentRuntime), pool)
const result = await service.resume(runId)
assert.equal(result.status, 'completed')
assert.deepEqual(store.batches(runId, 20), leaves)
assert.equal(calls, 4)
assert.deepEqual(source.prepare('SELECT * FROM supervision_runs WHERE id = ?').get(runId), before)
const report = { runId, status: result.status, retainedLeaves: leaves.length, offlineResponses: calls, paidCalls: 0,
originalUnchanged: true, progress: store.progress(runId), limitation: 'Saved successful navigation text replayed with optional arrays omitted; failed raw response was not persisted.' }
writeFileSync(`${destinationPath}.report.json`, JSON.stringify(report, null, 2))
console.log(JSON.stringify(report))
} finally { db.close(); pool.dispose(); source.close() }
}
void main().catch(error => { console.error(error); process.exitCode = 1 })