fix: add precedes graph edge from classification to execution
Every run call creates a classification entity, but it was never
connected to the execution via a graph edge — only via a DB column
(executions.classification_id). The ontology requires:
classification —precedes→ execution
Without this edge, all 53 classification entities had zero
relationships, making them invisible to get_relations and
blast-radius analysis.
Adds an idempotent INSERT into relationships after the existing
classification_id update, matching the same pattern used for
targets edges.
This commit is contained in:
@@ -921,6 +921,13 @@ func classifyAndGate(ctx context.Context, pool *db.Pool, agentID, targetID uuid.
|
|||||||
classID, actionCol, riskClass, classRoute, classReason, correlationID)
|
classID, actionCol, riskClass, classRoute, classReason, correlationID)
|
||||||
// Link classification to execution.
|
// Link classification to execution.
|
||||||
pool.Exec(ctx, `UPDATE executions SET classification_id = $2 WHERE entity_id = $1`, id, classID)
|
pool.Exec(ctx, `UPDATE executions SET classification_id = $2 WHERE entity_id = $1`, id, classID)
|
||||||
|
// Graph edge: classification —precedes→ execution (required by ontology).
|
||||||
|
pool.Exec(ctx, `INSERT INTO relationships (source_id, target_id, type, attributes, valid_from)
|
||||||
|
SELECT $1, $2, 'precedes', '{"by":"nomos"}'::jsonb, now()
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1 FROM relationships
|
||||||
|
WHERE source_id = $1 AND target_id = $2 AND type = 'precedes' AND valid_to IS NULL)`,
|
||||||
|
classID, id)
|
||||||
|
|
||||||
// Audit: record the execution creation with session_id for traceability.
|
// Audit: record the execution creation with session_id for traceability.
|
||||||
// Every run call, whether auto-run or queued-for-approval, gets an audit
|
// Every run call, whether auto-run or queued-for-approval, gets an audit
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import TrendingUpIcon from '@lucide/svelte/icons/trending-up'
|
|||||||
import SettingsIcon from '@lucide/svelte/icons/settings'
|
import SettingsIcon from '@lucide/svelte/icons/settings'
|
||||||
import EggIcon from '@lucide/svelte/icons/egg'
|
import EggIcon from '@lucide/svelte/icons/egg'
|
||||||
import StoreIcon from '@lucide/svelte/icons/store'
|
import StoreIcon from '@lucide/svelte/icons/store'
|
||||||
|
import Share2Icon from '@lucide/svelte/icons/share-2'
|
||||||
|
|
||||||
export type { AppManifest, AppPermission }
|
export type { AppManifest, AppPermission }
|
||||||
|
|
||||||
@@ -180,6 +181,17 @@ export const builtinApps: AppDef[] = [
|
|||||||
component: () => import('./mascot/MascotLayer.svelte'),
|
component: () => import('./mascot/MascotLayer.svelte'),
|
||||||
docked: true,
|
docked: true,
|
||||||
source: 'builtin'
|
source: 'builtin'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'entity-graph',
|
||||||
|
title: 'Entity Graph',
|
||||||
|
icon: Share2Icon,
|
||||||
|
component: () => import('../pages/EntityGraph.svelte'),
|
||||||
|
width: 1100,
|
||||||
|
height: 750,
|
||||||
|
minWidth: 640,
|
||||||
|
minHeight: 420,
|
||||||
|
source: 'builtin'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user