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.
This commit is contained in:
mesalogo
2026-10-06 15:40:18 +08:00
parent bc677a3718
commit d80d42b032
229 changed files with 13632 additions and 3800 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ import { dirname, join } from 'node:path'
import { DatabaseSync } from 'node:sqlite'
import { parseEnv } from 'node:util'
import { AssistantDatabase } from '../src/main/assistant/assistant-database.ts'
import { extractExperiences } from '../src/main/assistant/supervision-experiences.ts'
import { extractExperiences } from '../src/main/assistant/experience-extraction-service.ts'
const [prepared, envPath, directory, maxCallsArg] = process.argv.slice(2)
const config = parseEnv(readFileSync(envPath, 'utf8'))
+145
View File
@@ -0,0 +1,145 @@
/* global process, console, setTimeout, clearTimeout */
import { spawn, spawnSync } from 'node:child_process'
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const script = fileURLToPath(import.meta.url)
const root = resolve(dirname(script), '..')
const base = join(root, 'temp', 'goodbuddy-final-tests-final')
const stateFile = join(base, 'status.json')
const lockFile = join(base, 'runner.lock')
const npm = join(root, 'node_modules', 'npm', 'bin', 'npm-cli.js')
const [mode = 'status', selection = 'all', ...filters] = process.argv.slice(2)
const alive = (pid) => {
try { process.kill(pid, 0); return true } catch { return false }
}
const readState = () => JSON.parse(readFileSync(stateFile, 'utf8'))
const killTree = (pid) => {
if (!pid || !alive(pid)) return
if (process.platform === 'win32') {
spawnSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true, timeout: 15000 })
} else {
try { process.kill(-pid, 'SIGKILL') } catch { /* Already exited. */ }
}
}
if (mode === 'start') {
if (!['all', 'test', 'typecheck', 'lint'].includes(selection)) throw new Error('Unknown validation selection')
if (!statSync(join(root, 'temp')).isDirectory()) throw new Error('Repository temp directory is required')
mkdirSync(base, { recursive: true })
if (existsSync(lockFile)) {
const pid = Number(readFileSync(lockFile, 'utf8'))
if (alive(pid)) throw new Error(`Validation runner already active: ${pid}`)
rmSync(lockFile)
}
const lock = openSync(lockFile, 'wx')
writeFileSync(lock, String(process.pid))
closeSync(lock)
const log = openSync(join(base, 'runner.log'), 'a')
try {
const child = spawn(process.execPath, [script, 'worker', selection, ...filters], {
cwd: root, detached: true, windowsHide: true, stdio: ['ignore', log, log]
})
await new Promise((resolveSpawn, reject) => {
child.once('spawn', resolveSpawn)
child.once('error', reject)
})
writeFileSync(lockFile, String(child.pid))
child.unref()
console.log(JSON.stringify({ runnerPid: child.pid, selection, logs: base }))
} catch (error) {
rmSync(lockFile, { force: true })
throw error
} finally { closeSync(log) }
} else if (mode === 'status') {
const state = readState()
console.log(JSON.stringify({ ...state, runnerAlive: alive(state.pid) }, null, 2))
} else if (mode === 'stop') {
const state = readState()
if (state.status === 'running') {
killTree(state.childPid)
killTree(state.pid)
state.status = 'stopped'
state.endedAt = new Date().toISOString()
writeFileSync(stateFile, JSON.stringify(state, null, 2))
rmSync(lockFile, { force: true })
}
} else if (mode === 'worker') {
const run = join(base, new Date().toISOString().replace(/[:.]/g, '-'))
const tmp = join(run, 'tmp')
mkdirSync(tmp, { recursive: true })
if (!statSync(tmp).isDirectory()) throw new Error('Child temp directory was not created')
const state = { pid: process.pid, status: 'running', startedAt: new Date().toISOString(), run, results: [] }
const save = () => writeFileSync(stateFile, JSON.stringify(state, null, 2))
let child
let interrupted = false
const interrupt = (reason) => {
interrupted = true
state.reason = reason
killTree(child?.pid)
}
process.on('SIGINT', () => interrupt('SIGINT'))
process.on('SIGTERM', () => interrupt('SIGTERM'))
process.on('exit', () => killTree(child?.pid))
const deadline = setTimeout(() => interrupt('30-minute overall deadline exceeded'), 30 * 60 * 1000)
save()
try {
for (const job of selection === 'all' ? ['test', 'typecheck', 'lint'] : [selection]) {
if (interrupted) break
const started = Date.now()
const report = join(run, 'tests.json')
const args = job === 'test'
? ['test', '--', ...filters, '--reporter=default', '--reporter=json', `--outputFile.json=${report}`]
: ['run', job]
const logPath = join(run, `${job}.log`)
const log = openSync(logPath, 'w')
try {
child = spawn(process.execPath, [npm, ...args], {
cwd: root, windowsHide: true, detached: process.platform !== 'win32',
env: { ...process.env, TEMP: join(tmpdir(), 'goodbuddy-final-tests-final'), TMP: join(tmpdir(), 'goodbuddy-final-tests-final'), TMPDIR: join(tmpdir(), 'goodbuddy-final-tests-final'), NO_COLOR: '1' },
stdio: ['ignore', log, log]
})
state.active = job
state.childPid = child.pid
save()
const result = await new Promise((resolveExit, reject) => {
child.once('error', reject)
child.once('exit', (code, signal) => resolveExit({ code, signal }))
})
const entry = { job, ...result, seconds: (Date.now() - started) / 1000, log: logPath }
if (job === 'test' && existsSync(report)) {
const data = JSON.parse(readFileSync(report, 'utf8'))
entry.totals = Object.fromEntries(Object.entries(data).filter(([key]) => key.startsWith('num') || key === 'success'))
entry.failedFiles = data.testResults.filter((file) => file.status === 'failed').map((file) => ({
file: file.name.replace(root, '').replaceAll('\\', '/'),
tests: file.assertionResults.filter((test) => test.status === 'failed').map((test) => test.fullName)
}))
}
state.results.push(entry)
} finally {
killTree(child?.pid)
child = undefined
closeSync(log)
delete state.childPid
delete state.active
save()
}
}
state.status = interrupted ? 'interrupted' : 'completed'
} catch (error) {
state.status = 'error'
state.reason = error.message
} finally {
clearTimeout(deadline)
killTree(child?.pid)
try { rmSync(tmp, { recursive: true, force: true, maxRetries: 3, retryDelay: 200 }) }
catch (error) { state.cleanupError = error.code }
state.endedAt = new Date().toISOString()
save()
rmSync(lockFile, { force: true })
}
} else {
throw new Error('Usage: node scripts/final-regression.mjs start [all|test|typecheck|lint] [test filters...] | status | stop')
}
+1 -1
View File
@@ -86,7 +86,7 @@ try {
'CANDIDATES:', JSON.stringify(request.candidates), 'Return only JSON.'].join('\n\n')),
{ supervisionRunId, heartbeatRunId: run.id })
})
const plan = heartbeat.create({ name: '项目回顾', scope: { kind: 'projects', projectIds: [project.id] }, timezone: 'UTC',
const plan = await heartbeat.create({ name: '项目回顾', scope: { kind: 'projects', projectIds: [project.id] }, timezone: 'UTC',
recurrence: { type: 'daily', localTime: '09:00' }, enabled: true, lookbackHours: 24, retentionDays: 30 })
let tick = 0
const due = async () => {
+1 -1
View File
@@ -10,7 +10,7 @@ import { dirname, join } from 'node:path'
import { DatabaseSync } from 'node:sqlite'
import { parseEnv } from 'node:util'
import { AssistantDatabase } from '../src/main/assistant/assistant-database.ts'
import { assignStories } from '../src/main/assistant/supervision-stories.ts'
import { assignStories } from '../src/main/assistant/story-assignment-service.ts'
const [prepared, envPath, directory, mode, maxCallsArg] = process.argv.slice(2)
const config = parseEnv(readFileSync(envPath, 'utf8'))
+9 -5
View File
@@ -12,6 +12,8 @@ import { SupervisionModelPool } from '../src/main/assistant/supervision-model-po
import { ModelAgentRuntime } from '../src/main/agent/model-runtime'
import type { SupervisionRunRequest } from '../src/shared/supervision-contracts'
import { supervisionReviewSettingsSchema } from '../src/shared/supervision-review-contracts'
import { ReadonlyQueryReader } from '../src/main/readonly-query-reader'
import { asyncSupervisionStorage } from '../tests/support/async-supervision-storage'
async function main() {
const [mode, parent, envPath] = process.argv.slice(2)
@@ -25,7 +27,8 @@ async function main() {
bundle: true, platform: 'node', format: 'cjs', logLevel: 'silent' })
const db = new AssistantDatabase(path)
db.initialize(directory)
db.enableReadonlyWorker(worker)
const reader = new ReadonlyQueryReader('assistant', path, worker)
const storage = asyncSupervisionStorage(db, undefined, reader).supervision
const sql = (db as unknown as { requireDatabase(): DatabaseSync }).requireDatabase()
const pool = new SupervisionModelPool()
const report: Record<string, unknown> = { mode, directory, externalCalls: 0 }
@@ -49,7 +52,7 @@ async function main() {
const counts = () => ['supervision_entities', 'supervision_events', 'supervision_event_entities', 'supervision_sources'].map(table =>
[table, Number(sql.prepare(`SELECT COUNT(*) AS n FROM ${table}`).get()!.n)])
const before = counts()
await db.supervisionCandidates(request, { projectId: projects[0]!.id, crossProject: false })
await storage.supervisionCandidates(request, { projectId: projects[0]!.id, crossProject: false })
const legacy = sql.prepare(`SELECT e.id FROM supervision_entities e WHERE e.confirmation_state != 'revoked' AND EXISTS (
SELECT 1 FROM supervision_event_entities ee JOIN supervision_events ev ON ev.id = ee.event_id
WHERE ee.entity_id = e.id AND ev.superseded_by IS NULL AND COALESCE(ev.project_id, '') = ?)
@@ -61,14 +64,14 @@ async function main() {
const legacyMs = performance.now() - legacyStart
const start = performance.now()
for (const project of projects) {
const candidates = await db.supervisionCandidates(request, { projectId: project.id, crossProject: false })
const candidates = await storage.supervisionCandidates(request, { projectId: project.id, crossProject: false })
assert.equal(candidates.length, 100)
assert(candidates.every(item => item.label.startsWith(project.id + ':')))
assert.deepEqual(candidates.map(item => item.id), expected.get(project.id))
}
const isolatedMs = performance.now() - start
const crossStart = performance.now()
const candidates = await db.supervisionCandidates(request, { projectId: projects[0]!.id, crossProject: true })
const candidates = await storage.supervisionCandidates(request, { projectId: projects[0]!.id, crossProject: true })
assert.equal(candidates.length, 100)
rounds.push({ legacyMs, isolatedMs, crossProjectMs: performance.now() - crossStart })
}
@@ -106,7 +109,7 @@ async function main() {
calls++
return fetch(input, init)
} })
const service = createProductionSupervisorService(db, async () => ({ supervisorOrganizeTimeoutSeconds: 45,
const service = createProductionSupervisorService(storage, async () => ({ supervisorOrganizeTimeoutSeconds: 45,
supervisionReview: supervisionReviewSettingsSchema.parse({ crossProject: false, experienceMinEvents: 200 }) }), async () => runtime, pool)
const result = await service.run(request)
assert.equal(result.status, 'completed')
@@ -133,6 +136,7 @@ async function main() {
} finally {
report.externalCalls = calls
report.elapsedMs = performance.now() - started
await reader.close()
db.close()
pool.dispose()
report.databaseBytes = (await stat(path)).size
+2 -1
View File
@@ -8,6 +8,7 @@ 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 { ModelAgentRuntime } from '../src/main/agent/model-runtime'
import { asyncSupervisionStorage } from '../tests/support/async-supervision-storage'
async function main() {
const [directory, envPath, mode] = process.argv.slice(2)
@@ -68,7 +69,7 @@ async function main() {
const candidates = db.listSupervisionCandidates(state.request)
writeFileSync(join(directory, 'candidates.private.json'), JSON.stringify(candidates))
metrics.originalCandidates = candidates.length
const service = createProductionSupervisorService(db, async () => ({ supervisorModelConcurrency: 1, supervisorOrganizeTimeoutSeconds: 120 }), async () => runtime, pool)
const service = createProductionSupervisorService(asyncSupervisionStorage(db).supervision, async () => ({ supervisorModelConcurrency: 1, supervisorOrganizeTimeoutSeconds: 120 }), async () => runtime, pool)
const originalStore = db.supervisionReviewStore.bind(db)
const save = store.save.bind(store)
store.save = (...args) => { save(...args); service.pause(incident.run.id) }
+2 -1
View File
@@ -7,6 +7,7 @@ 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)
@@ -37,7 +38,7 @@ async function main() {
const leaves = store.batches(runId, 20)
assert.equal(leaves.length, 6)
assert.equal(store.progress(runId).remainingSources, 0)
const service = createProductionSupervisorService(db, async () => ({ supervisorModelConcurrency: 1 }),
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')
+2 -1
View File
@@ -8,6 +8,7 @@ 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 { ModelAgentRuntime } from '../src/main/agent/model-runtime'
import { asyncSupervisionStorage } from '../tests/support/async-supervision-storage'
async function main() {
const [sourceArg, outputArg, envArg, mode] = process.argv.slice(2)
@@ -79,7 +80,7 @@ async function main() {
title: 'Private selected conversation', updatedAt: Date.parse(scope.lastAt) },
messages: messages.map(message => ({ id: message.id, content: message.content, role: message.role,
createdAt: Date.parse(message.created_at), state: 'complete' })) }])
const service = createProductionSupervisorService(db, async () => ({ heartbeatEnabled: true,
const service = createProductionSupervisorService(asyncSupervisionStorage(db).supervision, async () => ({ heartbeatEnabled: true,
supervisorModelConcurrency: 2, supervisorOrganizeTimeoutSeconds: 180,
supervisionReview: { pageSize: 17, batchCharacters: 8000, batchMessages: 20, executionSeconds: 600 }
}), async () => runtime, pool)
+33
View File
@@ -0,0 +1,33 @@
/* global require, process, __dirname, console, setTimeout, clearTimeout */
/* eslint-disable @typescript-eslint/no-require-imports */
// node scripts/supervision-storage-live.cjs <current-runtime-settings.json>
const { build } = require('esbuild')
const { spawn } = require('node:child_process')
const { mkdir, mkdtemp, rm } = require('node:fs/promises')
const { join, resolve } = require('node:path')
async function main() {
const repo = resolve(__dirname, '..')
if (!process.argv[2]) throw new Error('Runtime settings path required')
const parent = join(repo, 'temp', 'supervision-storage-live')
await mkdir(parent, { recursive: true })
const root = await mkdtemp(join(parent, 'probe-'))
try {
for (const [entry, output, format] of [
['scripts/supervision-storage-live.ts', 'main.mjs', 'esm'],
['src/main/desktop-storage-entry.ts', 'desktop-storage-entry.mjs', 'esm'],
['src/main/readonly-query-worker.ts', 'readonly-query-worker.cjs', 'cjs'],
['src/main/assistant-storage-worker.ts', 'assistant-storage-worker.cjs', 'cjs']
]) await build({ entryPoints: [join(repo, entry)], outfile: join(root, output), bundle: true,
platform: 'node', format, packages: 'external', logLevel: 'silent' })
const env = { ...process.env, GB_SUPERVISION_STORAGE_ROOT: root, GB_SUPERVISION_SETTINGS: resolve(process.argv[2]), TEMP: root, TMP: root, TMPDIR: root }
delete env.ELECTRON_RUN_AS_NODE
const child = spawn(require('electron'), [join(root, 'main.mjs')], { env, stdio: ['ignore', 'pipe', 'pipe'] })
child.stdout.on('data', data => process.stdout.write(data))
// The probe prints only bounded metrics; native stderr is not a credential-safe report.
child.stderr.resume()
const timer = setTimeout(() => child.kill(), 300_000)
try { process.exitCode = (await new Promise((resolve, reject) => { child.once('exit', resolve); child.once('error', reject) })) ?? 1 }
finally { clearTimeout(timer) }
} finally { await rm(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }) }
}
main().catch(() => { console.error('Supervision storage probe failed before completion'); process.exitCode = 1 })
+134
View File
@@ -0,0 +1,134 @@
// Run through supervision-storage-live.cjs. Only synthetic evidence is sent to the model.
import assert from 'node:assert/strict'
import { randomUUID } from 'node:crypto'
import { readFile, writeFile, rm } from 'node:fs/promises'
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { app, safeStorage } from 'electron'
import { RuntimeSettingsStore } from '../src/main/runtime-settings-store'
import { ModelAgentRuntime } from '../src/main/agent/model-runtime'
import { DesktopStorageClient } from '../src/main/desktop-storage-client'
import { createSupervisionDomainPorts } from '../src/main/assistant/supervision-domain-ports'
import { createProductionSupervisorService, createProductionSuggestionPhraser } from '../src/main/assistant/supervision-production'
import { SupervisionModelPool } from '../src/main/assistant/supervision-model-pool'
import { HeartbeatService } from '../src/main/assistant/heartbeat-service'
import { deriveSuggestions } from '../src/main/assistant/supervision-suggester'
import type { SupervisionRunRequest } from '../src/shared/supervision-contracts'
const root = process.env.GB_SUPERVISION_STORAGE_ROOT!
const settingsPath = process.env.GB_SUPERVISION_SETTINGS!
const calls: Array<{ status?: number; inputBytes: number; ms?: number }> = []
const report: Record<string, unknown> = { syntheticOnly: true, maximumHttpCalls: 4, calls }
async function run() {
report.stage = 'preflight'
assert(root && settingsPath)
const profileDirectory = join(root, 'electron')
// Electron must see the copied encryption state before its ready event.
mkdirSync(profileDirectory)
app.setPath('userData', profileDirectory)
if (process.platform === 'win32') {
const state = JSON.parse(readFileSync(join(dirname(settingsPath), 'Local State'), 'utf8'))
writeFileSync(join(profileDirectory, 'Local State'), JSON.stringify({ os_crypt: state.os_crypt }))
}
await app.whenReady()
const original = await readFile(settingsPath)
const snapshot = join(root, 'settings.snapshot.json')
await writeFile(snapshot, original)
const settings = await new RuntimeSettingsStore(snapshot, {
isAvailable: () => safeStorage.isEncryptionAvailable(),
encrypt: () => { throw new Error('Probe does not write credentials') },
decrypt: value => safeStorage.decryptString(value)
}, {}).getResolvedSettings().finally(() => rm(snapshot, { force: true }))
const application = JSON.parse(await readFile(join(dirname(settingsPath), 'application-settings.json'), 'utf8'))
const selectedId = application.supervisorModelProfileId ?? settings.defaultModelProfileId
const selected = settings.modelProfiles.find(profile => profile.id === selectedId)
report.selection = { profileCount: settings.modelProfiles.length, explicitSupervisor: Boolean(application.supervisorModelProfileId),
found: Boolean(selected), protocol: selected?.protocol, authentication: selected?.authentication, credentialAvailable: Boolean(selected?.apiKey) }
assert(selected && selected.protocol !== 'openai-images-generations', 'No configured supervisor text model')
assert(selected.authentication === 'none' || selected.apiKey, 'No configured credential')
report.model = selected.modelName
report.protocol = selected.protocol
const storage = new DesktopStorageClient({ assistantPath: join(root, 'assistant.sqlite'), knowledgePath: join(root, 'knowledge.sqlite'),
userDataPath: root, defaultRootPath: root, entryPath: join(root, 'desktop-storage-entry.mjs'),
readerWorkerPath: join(root, 'readonly-query-worker.cjs'), upgradeWorkerPath: join(root, 'assistant-storage-worker.cjs') })
const pool = new SupervisionModelPool()
const runtime = () => new ModelAgentRuntime({ protocol: selected.protocol, authentication: selected.authentication,
apiKey: selected.apiKey, baseUrl: selected.baseUrl, model: selected.modelName,
requestHeaders: selected.requestHeaders, requestBody: selected.requestBody,
maximumOutputTokens: 3000, defaultWorkspace: root,
toolProvider: { listTools: async () => [], getApproval: () => { throw new Error('Probe tools disabled') },
callTool: async () => { throw new Error('Probe tools disabled') }, releaseConversation: async () => {}, dispose: async () => {} },
fetcher: async (input, init) => {
assert(calls.length < 4, 'Probe HTTP capacity reached')
const body = JSON.parse(String(init?.body))
assert.equal(body.tools?.length ?? 0, 0)
const call: (typeof calls)[number] = { inputBytes: Buffer.byteLength(String(init?.body)) }
calls.push(call)
console.log(JSON.stringify({ event: 'model-request', number: calls.length }))
const start = performance.now()
const response = await fetch(input, { ...init, signal: AbortSignal.any([...(init?.signal ? [init.signal] : []), AbortSignal.timeout(60_000)]) })
call.status = response.status
call.ms = Math.round(performance.now() - start)
return response
} })
try {
report.stage = 'storage-ready'
await storage.ready
const ports = createSupervisionDomainPorts(storage)
const project = (await storage.call('assistant', 'listProjects', []))[0]!
const now = Date.now()
const messages = [
'Synthetic project Aurora maintains a weather sensor calibration module. Decision: calibrate against a reference sensor before each field deployment. This replaced the earlier plan to calibrate only after deployment.',
'Milestone: the pre-deployment reference calibration detected a two-degree offset, which we corrected before deployment. The field measurements then matched the reference. Lesson: verify calibration before deployment to prevent biased field data.',
'Open question for the calibration module: should routine recalibration happen monthly or quarterly? No interval has been decided.'
].map((content, index) => ({ id: randomUUID(), role: 'user' as const, content, state: 'complete' as const, createdAt: now + index }))
await storage.call('assistant', 'saveLocalConversations', [[{
header: { id: randomUUID(), projectId: project.id, title: 'Synthetic Aurora calibration', updatedAt: now + 2 }, messages
}]])
const request: SupervisionRunRequest = { trigger: 'heartbeat', scope: { kind: 'global' },
timeRange: { from: new Date(now - 1000).toISOString(), to: new Date(now + 1000).toISOString() } }
const getSettings = async () => ({ supervisorModelProfileId: selectedId, supervisorOrganizeTimeoutSeconds: 60,
supervisorModelConcurrency: 1, supervisionReview: { pageSize: 10, batchCharacters: 8000, batchMessages: 10,
executionSeconds: 300, experienceMinEvents: 2, storyThreadEvents: 20 } })
const supervisor = createProductionSupervisorService(ports.supervision, getSettings, async () => runtime(), pool)
const phrase = createProductionSuggestionPhraser(ports.supervision, getSettings, async () => runtime(), pool)
const heartbeat = new HeartbeatService(ports.heartbeat, {
review: async ({ run }) => {
const result = await supervisor.run(request, run.id)
assert.equal(result.status, 'completed')
assert.equal(result.coverage?.complete, true)
assert.equal(result.coverage?.stories?.status, 'completed')
report.coverage = result.coverage
return { status: result.status, runId: result.runId }
},
suggest: async ({ run, supervisionRunId }) => deriveSuggestions(ports.suggestions, phrase, { supervisionRunId, heartbeatRunId: run.id })
})
const config = await heartbeat.create({ name: 'Synthetic probe', scope: request.scope, timezone: 'UTC',
recurrence: { type: 'daily', localTime: '09:00' }, enabled: true, lookbackHours: 24, retentionDays: 30 })
const first = await heartbeat.runNow({ id: config.id, idempotencyKey: 'first' })
report.stage = 'verify-publication'
const activity = (await storage.call('assistant', 'listSupervisionActivity', [10, 0, config.id]))[0]!
assert.equal(activity.status, 'completed')
assert.equal(activity.suggestionStatus, 'completed')
const stories = await ports.stories.list(request.scope)
const experiences = await ports.experiences.list()
const suggestions = await ports.suggestions.countForHeartbeat(first.id)
assert(stories.length > 0 && experiences.length > 0 && suggestions > 0)
const before = calls.length
const quiet = await supervisor.run(request)
assert.equal(quiet.status, 'no_change')
assert.equal(calls.length, before)
report.counts = { stories: stories.length, experiences: experiences.length, suggestions }
report.noChangeCalls = calls.length - before
report.usage = (await storage.call('assistant', 'getTokenUsageSummary', [])).systemTotals
report.settingsUnchanged = (await readFile(settingsPath)).equals(original)
assert.equal(report.settingsUnchanged, true)
assert.equal(storage.pendingCount, 0)
report.passed = true
} finally { pool.dispose(); await storage.close() }
}
void run().catch(error => {
report.passed = false
report.errorType = error instanceof Error ? error.name : 'Error'
// Do not print provider errors, headers, credentials, or settings.
}).finally(() => { console.log(JSON.stringify(report)); app.exit(report.passed ? 0 : 1) })