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:
@@ -7,6 +7,7 @@ import { AssistantDatabase } from './assistant-database'
|
||||
import { createProductionSupervisorService, createProductionSuggestionPhraser } from './supervision-production'
|
||||
import { SupervisionModelPool } from './supervision-model-pool'
|
||||
import { supervisionEntitySchema } from '../../shared/supervision-contracts'
|
||||
import { asyncSupervisionStorage } from '../../../tests/support/async-supervision-storage'
|
||||
|
||||
const cleanups: Array<() => void> = []
|
||||
afterEach(() => { for (const cleanup of cleanups.splice(0)) cleanup() })
|
||||
@@ -45,7 +46,7 @@ it('keeps one model across extraction, navigation, stories and experiences, and
|
||||
} as AgentRuntime))
|
||||
const pool = new SupervisionModelPool()
|
||||
cleanups.push(() => pool.dispose())
|
||||
const service = createProductionSupervisorService(f.db, async () => ({ supervisorModelProfileId: profileId,
|
||||
const service = createProductionSupervisorService(asyncSupervisionStorage(f.db).supervision, async () => ({ supervisorModelProfileId: profileId,
|
||||
supervisionReview: { pageSize: 10, batchCharacters: 1000, batchMessages: 10, executionSeconds: 300, experienceMinEvents: 2 } }), resolve, pool)
|
||||
const result = await service.run(f.request)
|
||||
expect(phases).toEqual(['extraction', 'extraction', 'navigation', 'stories', 'experiences'])
|
||||
@@ -70,7 +71,7 @@ it('releases a failed review runtime and uses the current model when continuing
|
||||
} as AgentRuntime))
|
||||
const pool = new SupervisionModelPool()
|
||||
cleanups.push(() => pool.dispose())
|
||||
const service = createProductionSupervisorService(f.db, async () => ({ supervisorModelProfileId: profileId }), resolve, pool)
|
||||
const service = createProductionSupervisorService(asyncSupervisionStorage(f.db).supervision, async () => ({ supervisorModelProfileId: profileId }), resolve, pool)
|
||||
await expect(service.run(f.request)).rejects.toThrow('Provider unavailable')
|
||||
expect(dispose).toHaveBeenCalledOnce()
|
||||
expect(service.execution().active).toBe(false)
|
||||
@@ -88,7 +89,7 @@ it('uses the supervisor selection for suggestions and disposes its runtime on fa
|
||||
} as AgentRuntime))
|
||||
const pool = new SupervisionModelPool()
|
||||
cleanups.push(() => pool.dispose())
|
||||
const phrase = createProductionSuggestionPhraser(f.db, async () => ({ supervisorModelProfileId: 'reviewer' }), resolve, pool)
|
||||
const phrase = createProductionSuggestionPhraser(asyncSupervisionStorage(f.db).supervision, async () => ({ supervisorModelProfileId: 'reviewer' }), resolve, pool)
|
||||
await expect(phrase({ systemInstruction: 'Suggest', outputContract: '{}', candidates: [] })).rejects.toThrow('Provider unavailable')
|
||||
expect(resolve).toHaveBeenCalledExactlyOnceWith('reviewer')
|
||||
expect(dispose).toHaveBeenCalledOnce()
|
||||
@@ -209,7 +210,7 @@ function fixture(content = 'Atlas and Beacon are separate projects.') {
|
||||
yield { type: 'text', requestId: input.requestId, delta: JSON.stringify(respond(input.prompt)) }
|
||||
yield { type: 'done', requestId: input.requestId }
|
||||
}
|
||||
const service = (responseKiB = 1024) => createProductionSupervisorService(db, async () => ({ supervisorModelConcurrency: 1,
|
||||
const service = (responseKiB = 1024) => createProductionSupervisorService(asyncSupervisionStorage(db).supervision, async () => ({ supervisorModelConcurrency: 1,
|
||||
supervisionReview: { pageSize: 10, batchCharacters: 1000, batchMessages: 10, executionSeconds: 300, responseKiB } }),
|
||||
async () => ({ runtimeId: 'model', capability: 'chat', run } as AgentRuntime), pool)
|
||||
// Project ownership comes from timeline events, not the scope that first saved an entity.
|
||||
@@ -233,7 +234,7 @@ it('records supervisor model usage under a hidden supervision task', async () =>
|
||||
model: 'gpt-review', inputTokens: 40, outputTokens: 8, cacheReadTokens: 0, cacheWriteTokens: 0 }
|
||||
yield { type: 'done', requestId: input.requestId }
|
||||
}
|
||||
const service = createProductionSupervisorService(f.db, async () => ({ supervisorModelConcurrency: 1,
|
||||
const service = createProductionSupervisorService(asyncSupervisionStorage(f.db).supervision, async () => ({ supervisorModelConcurrency: 1,
|
||||
supervisionReview: { pageSize: 10, batchCharacters: 1000, batchMessages: 10, executionSeconds: 300, responseKiB: 1024 } }),
|
||||
async () => ({ runtimeId: 'model', capability: 'chat', run } as AgentRuntime), new SupervisionModelPool())
|
||||
await service.run(f.request)
|
||||
|
||||
Reference in New Issue
Block a user