fix: synchronize graph review selection and attention radii

Share review history selection between overview and graph while preserving explicit navigation and stale-response guards. Return attention for the selected review scope and interval, and align spiral events and time with that review.

Normalize radii from message rates, including partial turns, without lifting quiet turns toward peaks. Preserve one continuous helix, uniform time height, round turn sections, and smooth transitions; equal densities retain equal radii. Document current-message and hourly-bucket limitations.

Validation: 51 focused unit tests, 2 production IPC tests, Electron DOM and geometry checks, Node/Agent/Web typecheck, targeted ESLint, and diff checks passed.

Release note: Story graphs now offer synchronized review history selection, and spiral radii reflect recorded message density within the selected review.
This commit is contained in:
mesalogo
2026-10-04 20:24:49 +08:00
parent 56ebd40bd8
commit 577210a8ae
18 changed files with 240 additions and 45 deletions
+8 -1
View File
@@ -9308,10 +9308,17 @@ export class AssistantDatabase {
if (!story) return { storyLine: null, events: [], entities: [], relations: [], sources: [], eventEntities: [], eventSources: [] }
const id = (story as { id: string }).id
if (input.resultId) {
const row = database.prepare('SELECT graph_snapshot_json FROM supervision_results WHERE id = ?').get(input.resultId) as { graph_snapshot_json: string }
const row = database.prepare(`SELECT r.graph_snapshot_json, sr.scope_json, sr.time_range_json
FROM supervision_results r JOIN supervision_runs sr ON sr.id = r.run_id WHERE r.id = ?`).get(input.resultId) as {
graph_snapshot_json: string; scope_json: string; time_range_json: string
}
const snapshot = JSON.parse(row.graph_snapshot_json) as { entities: unknown[]; relations: Array<{ confirmation_state: string }> }
const scope = JSON.parse(row.scope_json) as SupervisionRunRequest['scope']
const range = JSON.parse(row.time_range_json) as SupervisionRunRequest['timeRange']
return {
storyLine: story, ...snapshot, relations: snapshot.relations.filter((relation) => relation.confirmation_state !== 'revoked'),
attention: supervisionAttention(database, scope.kind === 'projects' ? scope.projectIds : undefined,
new Date(range.from).toISOString(), new Date(range.to).toISOString()),
events: database.prepare('SELECT * FROM supervision_events WHERE result_id = ? ORDER BY occurred_at').all(input.resultId),
sources: database.prepare('SELECT * FROM supervision_sources WHERE result_id = ?').all(input.resultId),
eventEntities: database.prepare(`SELECT ee.event_id, ee.entity_id FROM supervision_event_entities ee JOIN supervision_events e ON e.id = ee.event_id WHERE e.result_id = ?`).all(input.resultId),