Skip to main content

Implementation Plan — Entity Reclassification + Execution Chains + OAA Export

Date: 2026-02-14 Status: Active — Phases A0–A4 + B1 COMPLETE. Next: B2 (temporal chains) or D (UI/connector fixes). Supersedes: Previous version (Round 2 only). Now incorporates all 5 rounds of analysis plus plan review findings.


1. Decision Summary (Rounds 1-5)

Decisions Made

RoundDecisionStatus
Round 1Automation classification: execution_mode + security_relevance propertiesSHIPPED (connector)
Round 2CALLS edge, UI label fixes, flow diagram, mutationsApproved
Round 3New execution_chains collection for chain persistenceApproved (6/6 unanimous in R4)
Round 4OAA is export format, not internal model; PO reverses R3 dissentApproved (6/6 unanimous)
Round 5Reclassify entity types: automation, connection, credentialApproved (5/6 majority)

The Four Workstreams

Workstream A: Entity Type Reclassification (~106h)
├─ Phase A0: ADRs + compatibility layer (accept old + new types)
├─ Phase A1: Platform types, storage, path materializer, evaluator
├─ Phase A2: Connector migration (emit new types + edges)
├─ Phase A3: UI + API endpoint updates
└─ Phase A4: Tests + architecture doc updates
└─ Must be done FIRST — chains should reference correctly-typed entities

Workstream B: Execution Chains Collection (~134h total: 94h Phase 1 + 40h Phase 2)
├─ Phase 1: Chain assembly + API + UI (current state + hash detection) — ~94h
└─ Phase 2: Temporal chain tracking (version history + diff API + events) — ~40h
└─ Depends on Workstream A — chain builder traverses mixed entity types

Workstream C: OAA Export Projection (~28h)
└─ Depends on Workstream A — OAA mapping uses correct entity types
└─ DEFERRED until customer/sales need

Workstream D: UI + Connector Fixes from Round 2 (~27h)
└─ Can run in parallel with B, some items absorbed by A

2. Workstream A: Entity Type Reclassification

Source: Round 5 synthesis (5/6 majority) Effort: ~106 hours (~3 weeks) Priority: P0 — do this first

Re-baseline note: Original estimate was 52h. Code review identified 13 identity-assumption locations across 47 impacted files. The developer audit (Round 5) estimated 136-168h including data migration. Since we have no active clients, data migration is unnecessary, but the base estimate needed correction to account for: (a) path materializer deep rework (14h), (b) dual-accept compatibility window, (c) API route refactoring, (d) ADR/doc sequencing (12h), (e) additional identity-assumption files found during post-fix review.

A.1 The Type System (NormalizedNodeType vs Internal Entity Type)

Critical distinction: NormalizedNodeType is the connector contract (what connectors emit). Internal entity_type is what the platform stores. They are not identical.

// CONNECTOR CONTRACT — what connectors emit in NormalizedGraph
export type NormalizedNodeType =
| "identity" // Things that authenticate: SP, OAuth App, machine account
| "automation" // Execution logic: BR, SI, Flow, Scheduled Job
| "connection" // Outbound configs: REST Message, SOAP, HTTP Connection
| "credential" // Auth material: OAuth Provider/Profile, API Key, Certificate
| "human_identity" // Human users — KEPT as connector type (see note below)
| "role" // Permission groupings (unchanged)
| "permission" // Individual capabilities (unchanged)
| "resource" // Data objects, tables, APIs (unchanged)
| "execution_evidence"; // Proof of execution (unchanged)

// PLATFORM INTERNAL — stored in entities collection
// entity_type values: identity, automation, connection, credential,
// owner (mapped from human_identity by normalizer),
// role, permission, resource, execution_evidence

Why human_identity stays in NormalizedNodeType: The connector contract (05-connectors.md line 334) explicitly states: "Do NOT add 'owner' as a NormalizedNodeType. Ownership is a platform concept derived from connector-provided relationship data." The existing owner-normalizer already enriches human_identity nodes with owner semantics. We extend this pattern: connectors emit human_identity, the platform normalizer maps to internal entity_type: "owner" during ingestion.

A.2 Artifact Reclassification Map

ArtifactCurrent TypeNew NormalizedNodeTypeInternal entity_typeSubtype
Service Principalautonomous_identity / service_principalidentityidentityIdentitySubtype
OAuth App Registrationautonomous_identity / oauth_appidentityidentityIdentitySubtype
Machine Accountautonomous_identity / machine_accountidentityidentityIdentitySubtype
Integration Userautonomous_identity / integration_useridentityidentityIdentitySubtype
Business Ruleautonomous_identity / business_ruleautomationautomationAutomationSubtype
Script Includeautonomous_identity / system_executionautomationautomationAutomationSubtype
Flow Designer Flowautonomous_identity / flow_designer_flowautomationautomationAutomationSubtype
Scheduled Jobautonomous_identity / scheduled_jobautomationautomationAutomationSubtype
REST MessageresourceconnectionconnectionConnectionSubtype
OAuth Providerautonomous_identitycredentialcredentialCredentialSubtype
OAuth Profileautonomous_identitycredentialcredentialCredentialSubtype
Human Userhuman_identityhuman_identity (unchanged)owner (normalizer maps)

A.3 Edge Type Updates

A.3.1 Edge Migration Mapping (Old → New)

The connector currently emits 10 edge types. Here is the explicit migration:

Current EdgeCurrent UsageNew EdgeNew SemanticsMigration
EXECUTES_ON (×6)automation→REST messageINVOKESautomation→connectionRENAME when target is connection type
EXECUTES_ON (×6)automation→resourceEXECUTES_ONautomation→resourceKEEP for automation→resource (e.g., table reads)
AUTHENTICATES_VIA (×2)REST→OAuthUSESconnection→credentialRENAME
RUNS_AS (×5)automation→SPRUNS_ASautomation→identityKEEP (type constraint changes)
RUNS_AS (×5)flow→human userRUNS_ASautomation→ownerKEEP (add owner as valid target)
TRIGGERS_ON (×3)automation→tableTRIGGERS_ONautomation→resourceKEEP (type constraint changes)
OWNED_BY (×3)entity→creatorOWNED_BYany→ownerKEEP
AUTHENTICATES_TO (×2)SP→SP cross-systemAUTHENTICATES_TOidentity→identityKEEP
HAS_ROLE (×1)identity→roleHAS_ROLEidentity→roleKEEP
GRANTS (×1)role→permissionGRANTSrole→permissionKEEP
CREATED_BY (×1)entity→creatorCREATED_BYany→ownerKEEP
APPLIES_TO (×1)permission→resourceAPPLIES_TOpermission→resourceKEEP
(none)CALLSautomation→automationNEW (BR→SI)
(none)AUTHENTICATES_AScredential→identityNEW (OAuth→SP)

A.3.2 Complete Edge Type Reference

EdgeFrom → ToChangeNotes
CALLSautomation → automationNEWBR invokes SI
INVOKESautomation → connectionNEW (replaces EXECUTES_ON for connection targets)SI uses REST Message
USESconnection → credentialNEW (replaces AUTHENTICATES_VIA)REST uses OAuth Profile
AUTHENTICATES_AScredential → identityNEWOAuth represents SP
RUNS_ASautomation → identity | ownerUpdated constraintAutomation executes as identity OR human user
TRIGGERS_ONautomation → resourceUpdated constraintAutomation fires on resource events
EXECUTES_ONautomation → resourceNarrowed constraintAutomation reads/writes resource (kept for non-connection targets)
HAS_ROLEidentity → roleUnchangedIdentity has role
GRANTSrole → permissionUnchangedRole grants permission
APPLIES_TOpermission → resourceUnchangedPermission applies to resource
OWNED_BYany → ownerUnchangedEntity owned by human
CREATED_BYany → ownerUnchangedEntity created by human
AUTHENTICATES_TOidentity → identityPreservedSP→SP cross-system auth

A.3.3 Compatibility Window

During migration, the platform must accept both old and new edge types:

// Dual-accept edge types in ingest.ts validator
const EDGE_TYPES = [
// New canonical types
"CALLS", "INVOKES", "USES", "AUTHENTICATES_AS",
// Preserved types
"RUNS_AS", "TRIGGERS_ON", "EXECUTES_ON",
"HAS_ROLE", "GRANTS", "APPLIES_TO",
"OWNED_BY", "CREATED_BY", "AUTHENTICATES_TO",
// Legacy aliases (accepted during migration, normalized on ingest)
"AUTHENTICATES_VIA", // → normalized to USES
"DELEGATES_TO", "APPROVED_BY", "MEMBER_OF", // kept for future connectors
] as const;

The ingestion pipeline normalizes legacy edges: AUTHENTICATES_VIAUSES (when source is connection, target is credential).

A.4 Corrected AzureGraphRouter Chain

[automation:business_rule] AzureGraphRouter
--TRIGGERS_ON--> [resource] incident table
--CALLS--> [automation:script_include] AzureGraphRouterSI
--INVOKES--> [connection:rest_message] Azure Graph REST
--USES--> [credential:oauth_profile] AzureGraphOAuth
--AUTHENTICATES_AS--> [identity:service_principal] SP-AzureGraph
--HAS_ROLE--> [role] Directory.Read.All
--GRANTS--> [permission] User.Read.All
--APPLIES_TO--> [resource] Graph API /users

A.5 Identity-Assumption Locations (Audited)

The following files contain hardcoded entity_type === "identity" assumptions that must be updated:

Core Platform (highest impact)

FileLine(s)What It DoesEffort
src/ingestion/path-materializer.ts27, 169, 195Skips non-identity entities in path traversal; identity-check on RUNS_AS and AUTHENTICATES_TO targets12-16h
src/workers/handlers/sync-ingestion.ts133Filters to identity-only before path materialization4h
src/storage/mongo/adapter.ts629-633Execution flow traversal: assumes non-automation seed = identity for reverse edge logic4h
src/workers/handlers/build-evidence-pack.ts44-60AUTHENTICATES_TO targets assumed to be identities; credential fetch logic3h
src/evidence/sections.ts23EvidenceBuildContext interface hardcodes identity: EntityDoc as primary entity2h
src/api/routes/paths.ts19, 82, 111API validates entity_type on blast-radius, accessible-by, cross-system-paths endpoints6h

Ingestion + Normalization

FileLine(s)What It DoesEffort
src/ingestion/types.ts1-26NormalizedNodeType and NormalizedEdgeType enum definitions2h
src/api/routes/ingest.ts10-35NODE_TYPES and EDGE_TYPES validators reject new types2h
src/ingestion/normalizer/owner-normalizer.ts26Gates on nodeType === "human_identity" for owner enrichment2h

UI

FileLine(s)What It DoesEffort
ui/src/hooks/use-automations.ts20Hardcodes entity_type: "identity" for automation queries2h
ui/src/hooks/use-blast-radius.ts10URL hardcodes /identities/ path1h
ui/src/hooks/use-cross-system.ts10URL hardcodes /identities/ for cross-system paths1h
ui/src/components/graph/GraphNodeDetailsDrawer.tsx73isIdentity = entity?.entity_type === "identity" gates tabs/features1h

Total audited locations: 13 files, ~42h effort within Workstream A.

Path materializer is the hardest change — it fundamentally assumes identity → role → permission → resource chains. With reclassification, the traversal must handle: automation → (CALLS) → automation → (INVOKES) → connection → (USES) → credential → (AUTHENTICATES_AS) → identity → role → permission → resource.

A.6 Implementation Tasks (Re-baselined)

#TaskStackEffortDetails
Phase A0: Foundation + Compatibility12hCOMPLETE (2026-02-14)
A0.1Create ADR-006 through ADR-009Docs3hDONE — ADR-006 (entity reclassification), ADR-007 (execution relationship types), ADR-008 (execution chains), ADR-009 (OAA export)
A0.2Expand types.ts: ENTITY_TYPES 6→9, NormalizedNodeType +3, NormalizedEdgeType +4Platform TS2hDONEautomation, connection, execution_evidence added to EntityType; identity, automation, connection added to NormalizedNodeType; CALLS, INVOKES, USES, AUTHENTICATES_AS added to NormalizedEdgeType
A0.3Expand ingest.ts validators: accept both old and new types/edgesPlatform TS2hDONE — NODE_TYPES +3, EDGE_TYPES +4
A0.4Restructure identity-subtypes.ts: split into per-entity-type arraysPlatform TS2hDONE — IDENTITY_SUBTYPES, AUTOMATION_SUBTYPES, CONNECTION_SUBTYPES, CREDENTIAL_SUBTYPES + combined ALL_NHI_SUBTYPES. pat moved to credential. Mongo adapter imports canonical source.
A0.5Update mapNodeType() + verify tests passPlatform TS1hDONE — 3 new cases in graph-transformer.ts. Return type simplified to EntityType. 207 unit + 96 integration tests pass.
Note: A0.4 in original plan (ingestion normalizer for old→new reclassification) deferred to Phase A1 — reclassifying autonomous_identity based on subtype requires path materializer updates first.
Phase A1: Platform Core30h
A1.1Update StorageAdapter: handle new entity types in upsert, query, versioningPlatform TS8hNew indexes for automation, connection, credential
A1.2Rewrite path materializer for multi-type traversalPlatform TS14hFollow CALLS→INVOKES→USES→AUTHENTICATES_AS→HAS_ROLE→GRANTS→APPLIES_TO; also RUNS_AS→identity|owner
A1.3Update finding evaluator: type-based rulesPlatform TS4h"Orphaned automation" not "orphaned identity"; adjust all type filters
A1.4Update sync-ingestion handler: remove identity-only filterPlatform TS4hPath materialization for automation + identity types
Phase A2: Connector Migration16h
A2.1Update transformer.py: emit new node types + subtypesConnector PY6hautomation, connection, credential types
A2.2Update transformer.py: emit new edge typesConnector PY4hCALLS, INVOKES, USES, AUTHENTICATES_AS; keep RUNS_AS, TRIGGERS_ON, EXECUTES_ON
A2.3Update connector tests (247 tests)Connector PY6hFix assertions for new types/edges
Phase A3: UI + API22h
A3.1Update API routes: entity-type-aware endpointsPlatform TS6h/automations/, /connections/ or generic /entities/:id/ with type validation
A3.2Update UI entity pages: separate views per typePlatform UI8hIdentity/Automation/Connection/Credential pages, badges, icons
A3.3Update UI graph layout: layer assignment by entity typePlatform UI4hDistinct shapes/colors for automation, connection, credential
A3.4Update UI hooks: use-automations, use-blast-radiusPlatform UI4hCorrect entity_type filters, URL paths
Phase A4: Validation + Docs26h
A4.1Update/add platform unit testsPlatform TS6hNew type coverage, path materializer tests
A4.2Update platform integration testsPlatform TS6hEnd-to-end ingest with new types
A4.3Update architecture docs (02-data-model, 01-database, 04-connectors, glossary)Docs12hPer architecture docs update plan Steps 2-6 (~11-14h). ADRs already created in A0.1.
A4.4Remove old type aliases after connector migratedPlatform TS2hClean up dual-accept
Total~106h

A.7 Execution Order

✅ DONE     Phase A0 — ADRs + compatibility layer (2026-02-14)
ADRs 006-009 created. Types expanded: EntityType 6→9,
NormalizedNodeType +3, NormalizedEdgeType +4. Subtypes split
into per-entity-type arrays. 207 unit + 96 integration tests pass.
Old connector still works. No behavior change.

✅ DONE Phase A1 — Platform core (2026-02-13)
Storage, path materializer, evaluator, sync handler.
Ingestion normalizer handles autonomous_identity reclassification.
Tests updated for new types.

✅ DONE Phase A2 — Connector migration (2026-02-13)
transformer.py emits new types + edges (CALLS, INVOKES,
USES, AUTHENTICATES_AS). 247 connector tests pass.

✅ DONE Phase A3 — UI + API (2026-02-13)
Canonical /entities/ routes with /identities/ aliases.
Entity type colors, blast radius eligibility expanded.
Graph filter sidebar + layout edge styles updated.
234 platform tests pass.

✅ DONE Phase A4 — Validation + docs (2026-02-13)
Architecture docs updated. Deprecation comments added.
Legacy type aliases kept for backward compat.

✅ DONE Phase B1 — Execution chains (2026-02-13)
Chain builder, storage adapter methods, API routes,
UI pages (list + detail). Chain assembly integrated
into sync pipeline.

A.8 Rollback Strategy

Each phase is independently rollbackable:

  • A0 rollback: Remove new types from validators. No data change.
  • A1 rollback: Revert storage/materializer. Old connector data still works (normalizer accepts old types).
  • A2 rollback: Revert connector to emit old types. Platform normalizer handles them.
  • A3 rollback: Revert UI/API. Backend still works with new types.

3. Workstream B: Execution Chains Collection

Source: Round 3 synthesis (6/6 unanimous after Round 4) Effort: ~94 hours Phase 1 + ~40h Phase 2 (~134h total) Priority: P1 — after Workstream A Dependency: Workstream A must complete first

B.1 New Collection Schema

// execution_chains collection
{
_id: "chain-uuid",
tenant_id: "...",
name: "AzureGraphRouter Incident Routing",
anchor_entity_id: "uuid-of-business-rule", // Stable identity root
entity_refs: [
{ entity_id: "uuid-br", entity_type: "automation", role: "entry_point" },
{ entity_id: "uuid-si", entity_type: "automation", role: "code_component" },
{ entity_id: "uuid-rest", entity_type: "connection", role: "outbound_target" },
{ entity_id: "uuid-oauth", entity_type: "credential", role: "auth_credential" },
{ entity_id: "uuid-sp", entity_type: "identity", role: "destination_identity" }
],
summary: {
trigger: "incident table insert",
destination: "graph.microsoft.com",
egress_category: "external",
blast_radius_domains: ["identity_platform"],
ownership_status: "orphaned",
total_roles: 4,
max_sensitivity: "confidential",
canonical_permissions: { // OAA enrichment (Phase 1.5)
reads: ["DataRead:incident"],
writes: ["DataWrite:user"]
}
},
composition_hash: "sha256:abc...", // Fingerprint for change detection
first_detected_at: ISODate("2026-02-12"),
last_seen_at: ISODate("2026-02-13"),
sync_version: 42
}

B.2 Chain Identity

Chain identity is anchored to the entry point (Business Rule, Flow, Scheduled Job):

const chainId = sha256(`${tenantId}:${anchorEntitySourceId}`).slice(0, 24);

Entity rotation (OAuth client_id change, SP credential rotation) does NOT break chain identity. The anchor entity persists → the chain persists.

B.3 Chain Assembly

Chains are assembled by the platform (not connectors) during sync pipeline:

Sync pipeline:
1. Receive NormalizedGraph
2. Diff engine → entity versions → events
3. Path materialization
4. ★ Chain assembly (NEW) ← BFS from entry points
5. Finding evaluation (now includes chain-level findings)

Chain builder algorithm:

  1. Find all entities with entity_type: "automation" and automationSubtype in ["business_rule", "flow_designer_flow", "scheduled_job"]
  2. BFS from each entry point following: CALLS → INVOKES → USES → AUTHENTICATES_AS → HAS_ROLE → GRANTS → APPLIES_TO. Also follow: RUNS_AS, TRIGGERS_ON, EXECUTES_ON for complete chain capture.
  3. Collect entity_refs with roles
  4. Compute composition_hash (SHA256 of sorted entity_id:role pairs)
  5. Upsert chain document (update if hash unchanged, create version if changed)

BFS edge traversal note: The BFS must follow ALL execution-relevant edges, not just the "happy path" chain. RUNS_AS captures identity binding (automation→identity or automation→owner). TRIGGERS_ON captures the trigger resource. EXECUTES_ON captures data resources read/written. These are all part of the chain's blast radius.

B.4 Phase 1 Implementation Tasks

#TaskStackEffortDetails
B1Define chain types: ExecutionChainDoc, ChainEntityRef, ChainSummaryPlatform TS4hTypeScript interfaces
B2Add execution_chains collection + indexes to StorageAdapterPlatform TS12h5 new methods (upsert, get, query, version, history)
B3Implement chain builder: anchor discovery + BFS + fingerprintPlatform TS16hCore algorithm
B4Integrate chain assembly into sync pipelinePlatform TS8hAfter path materialization
B5OAA canonical permission enrichment on chain docsPlatform TS4hPhase 1.5 — map roles to DataRead/DataWrite
B6API routes: GET /execution-chains, GET /execution-chains/:idPlatform TS10hList + detail endpoints
B7UI: ExecutionChainsPage (list)Platform UI10hDataTable with chain list
B8UI: ExecutionChainDetailPage (detail)Platform UI10hChain visualization + entity list + summary
B9Add connector chain hints (optional chainMembership property)Connector PY8hOptional optimization
B10Unit + integration tests for chain assemblyPlatform TS12hChain builder + API tests
Phase 1 Total~94h

B.5 Phase 1 Execution Order

Week 1: B1 (types) → B2 (storage) → B3 (builder) → B4 (sync pipeline)
Week 2: B5 (OAA enrichment) → B6 (API) → B7 + B8 (UI) → B9 (connector hints)
Week 3: B10 (tests) + integration validation

B.6 Phase 2: Temporal Chain Tracking

Source: Round 3 synthesis, product feedback ("Delta view 'was → is' will be huge") Effort: ~40 hours Priority: P1 — ship within 2 weeks of Phase 1 Dependency: Phase 1 must complete first

Product requirement: Product feedback explicitly requests before-vs-after state comparison, temporal tracking of permission changes, and visual "was → is" representation on automations. Phase 1 can detect change (composition_hash differs) but cannot show what changed or when. Phase 2 closes this gap.

B.6.1 Phase 2 Schema Addition

// execution_chain_versions collection
{
_id: "version-uuid",
chain_id: "chain-uuid", // FK to execution_chains._id
tenant_id: "...",
version_number: 3,
entity_refs: [ /* snapshot at this version */ ],
summary: { /* snapshot at this version */ },
composition_hash: "sha256:def...",
created_at: ISODate("2026-02-14"),
sync_version: 43,
diff_from_previous: { // What changed
entities_added: [{ entity_id: "...", entity_type: "...", role: "..." }],
entities_removed: [{ entity_id: "...", entity_type: "...", role: "..." }],
summary_changes: {
blast_radius_domains: { added: ["storage"], removed: [] },
ownership_status: { from: "orphaned", to: "owned" }
}
}
}

// execution_chain_events collection
{
_id: "event-uuid",
chain_id: "chain-uuid",
tenant_id: "...",
event_type: "chain_entity_added" | "chain_entity_removed" | "chain_created"
| "chain_blast_radius_changed" | "chain_ownership_changed",
timestamp: ISODate("2026-02-14"),
details: { /* event-specific payload */ },
sync_version: 43
}

B.6.2 Phase 2 Implementation Tasks

#TaskStackEffortDetails
B11Add execution_chain_versions collection + indexesPlatform TS8hVersion storage + queries
B12Chain versioning: create version when composition_hash or summary changesPlatform TS10hIntegrated into chain upsert
B13Chain diff API: GET /execution-chains/:id/diff?from=ts1&to=ts2Platform TS6hCompare two versions
B14Chain events: emit events on structural/summary changesPlatform TS6hchain_created, chain_entity_added, etc.
B15UI: Chain temporal comparison tab (was→is view)Platform UI10hVisual diff of chain state over time
Phase 2 Total~40h

B.6.3 Phase 2 Execution Order

Week 4: B11 (version storage) → B12 (version creation) → B13 (diff API)
Week 5: B14 (events) → B15 (temporal UI)

4. Workstream C: OAA Export Projection (DEFERRED)

Source: Round 4 synthesis (6/6 unanimous) Effort: ~28 hours Priority: P2 — deferred until customer/sales need Decision: OAA is an export format, not the internal data model

C.1 Architecture

Internal model (entities + execution_chains)
→ Export layer
→ OAA Application JSON (per source system)
→ SCIM User/Group JSON (future)
→ Neo4j Cypher (future)

C.2 OAA Export Design

  • Each source system → one OAA Application (ServiceNow App, Entra App)
  • identity entities → OAA local_user
  • automation entities → OAA resource (type: automation)
  • connection entities → OAA resource (type: connection)
  • credential entities → custom properties on OAA local_user
  • role → OAA local_role
  • permission → OAA custom_permission (mapped to 10 canonical types)
  • Chain membership → sv0_chain_memberships custom property

C.3 The "Execute" Permission Extension

OAA's 10 canonical permissions lack "Execute." Add sv0_action_type extension:

{
"permission_type": ["NonData"],
"custom_properties": {
"sv0_action_type": "execute_automation",
"sv0_action_detail": "business_rule_trigger"
}
}

C.4 Implementation Tasks (when triggered)

#TaskEffort
C1OAA export endpoint: GET /api/v1/export/oaa/:sourceSystem12h
C2Entity → OAA type mapper4h
C3Chain → OAA chain registry resource4h
C4Tests + documentation4h
C5Optional: Veza push script4h
Total~28h

5. Workstream D: UI + Connector Fixes (Round 2)

Source: Round 2 synthesis Effort: ~27 hours Priority: P1 — can run in parallel with B after A completes Note: Some items from original plan are now absorbed by Workstream A

D.1 Items Absorbed by Workstream A

Original ItemNow Part Of
2.5A: Fix entity labelsA3.2 (UI entity pages — types now correct, labels natural)
2.5I: 9-layer graph layoutA3.3 (graph layout by type — layers from entity_type)

D.2 Remaining Items

#ItemStackEffortStatus
D1Add CALLS relationship typeConnector + Platform3hPart of A0.2 + A2.2
D2Fix flow diagram trigger for Script IncludesUI3-4hPending
D3Add "Show full chain" toggle (Level 2 view)UI3-5hPending
D4Fix 22 "unknown" execution_mode flowsConnector2hPending
D5setWorkflow(false) warning badgeConnector + UI2hPending
D6Local mutations + Effects tabConnector + UI4hPending
D7Trigger examples displayConnector + UI3hPending
D8Data domain badges on graph nodesUI1-2hPending
D9Promote sensitive-data flows to dormant_authorityConnector2hPending
Total~23-27h

6. Master Schedule

Week 1:     WA Phase A0 — ADRs + compatibility layer (12h)
Week 1-2: WA Phase A1 — Platform core (30h)
Week 2-3: WA Phase A2 — Connector migration (16h)
Week 3: WA Phase A3 — UI + API (22h)
Week 3-4: WA Phase A4 — Tests + docs (20h)
Week 4-6: WB Phase 1 — Execution chains (94h)
Week 4-5: WD — UI/connector fixes in parallel (27h)
Week 6-7: WB Phase 2 — Temporal chain tracking (40h)
Deferred: WC — OAA Export (28h, when needed)

Milestone Timeline

MilestoneWeekDeliverable
M0: CompatibilityEnd of Week 1Old + new types accepted. ADR-006/007 published. Zero behavior change.
M1: Correct TypesEnd of Week 3All entities correctly typed. NHI count accurate. Connector emitting new types.
M2: Full UIEnd of Week 4UI shows separate entity pages. Graph layered by type. Tests green. Docs updated.
M3: Chain AssemblyEnd of Week 5Chains discoverable via API. Stable chain IDs. Chain UI.
M4: Full DemoEnd of Week 6End-to-end: correct types → chain list → chain detail → finding → evidence
M5: Temporal ChainsEnd of Week 7Chain versions, diff API, "was→is" UI. Product feedback addressed.
M6: OAA ExportWhen neededGET /export/oaa/:sourceSystem endpoint

Total Effort

WorkstreamEffortWeeks
A: Entity Reclassification~106h3-4
B Phase 1: Execution Chains~94h2.5
B Phase 2: Temporal Tracking~40h1.5
D: UI/Connector Fixes~27h1 (parallel)
C: OAA Export (deferred)~28h1
Total (A+B+D)~267h~7 weeks

7. Success Criteria

After Workstream A Phase A0 (Compatibility)

  1. Platform accepts both old and new node/edge types without rejection
  2. ADR-006 and ADR-007 published
  3. All existing tests pass unchanged (zero behavior change)

After Workstream A Complete (Entity Reclassification)

  1. GET /entities?entity_type=identity returns ONLY authenticating entities (SPs, OAuth Apps, machine accounts)
  2. GET /entities?entity_type=automation returns Business Rules, Script Includes, Flows, Jobs
  3. GET /entities?entity_type=credential returns OAuth Providers/Profiles
  4. GET /entities?entity_type=connection returns REST Messages
  5. NHI count drops from ~92 to ~8-15 (accurate)
  6. Graph shows distinct node shapes/colors per entity type
  7. All existing tests pass with updated types
  8. Architecture docs (02-data-model, 01-database, 04-connectors, glossary) updated

After Workstream B Phase 1 (Execution Chains)

  1. GET /execution-chains returns all discovered chains
  2. Each chain has stable ID (survives entity rotation)
  3. Chain composition_hash detects structural changes between scans
  4. Chains include OAA canonical permission summary
  5. UI: Execution Chains list page with filter/sort
  6. UI: Chain detail page with entity list + summary + graph

After Workstream B Phase 2 (Temporal Chains)

  1. Chain version history stored on each structural/summary change
  2. GET /execution-chains/:id/diff compares two timestamps
  3. Chain events emitted (created, entity_added, blast_radius_changed)
  4. UI: "Was → Is" temporal comparison tab on chain detail page

After Workstream D (UI/Connector Fixes)

  1. "Show full chain" toggle on automation detail pages
  2. Flow diagram shows correct trigger for Script Includes
  3. 0 "unknown" execution_mode flows
  4. setWorkflow(false) shows warning badge
  5. Data domain badges visible on graph nodes

8. ADRs to Create

ADRDecisionWhenSupersedes
adr-006-entity-type-reclassification.mdSplit autonomous_identity into identity + automation + connection + credential. NormalizedNodeType keeps human_identity; platform stores owner.WA Phase A0 (before code)Replaces planned adr-006 (subtype taxonomy)
adr-007-execution-relationship-types.mdCALLS + INVOKES + USES + AUTHENTICATES_AS edge types. Edge migration mapping from old types.WA Phase A0 (before code)Extends original CALLS-only ADR
adr-008-execution-chains-collection.mdNew execution_chains collection for chain persistenceWB startNew
adr-009-oaa-export-projection.mdOAA as export format, not internal modelWhen WC startsNew

9. Risk Assessment

RiskLikelihoodImpactMitigation
Path materializer rework takes longer than 14hMediumMediumIt's the hardest single task. Budget 2 extra days. Existing path-materializer tests serve as regression suite.
Entity reclassification breaks unexpected code pathsMediumMediumPhase A0 compatibility layer means old data keeps working. Run full test suite after each phase. No clients to break.
Edge migration leaves orphan edges in DBLowLowNo existing data (no clients). Fresh ingest with new connector.
Chain builder BFS performance on large graphsLowMediumComplexity budget (50-node cap per chain). Index on entity_type.
Phase 2 temporal tracking deferred too longMediumMediumExplicit milestone M5 at Week 7. Product feedback makes this a P1.
OAA export deferred too long, blocks salesLowHighC1-C2 can ship in 2 days if urgently needed.
Integrator's dissent is correct (BRs should stay identity)LowLowTypes are easy to rename later. No clients.
Connector contract drift during migration windowLowMediumDual-accept ensures both old and new connector versions work. Migration window is ~1 week (Phase A0→A2).

10. Plan Review Findings (Incorporated)

This plan was updated to address 8 review findings:

#FindingSeverityResolution
1WA under-scoped (52h vs 168h developer audit)CriticalRe-baselined to ~106h. 13 identity-assumption locations across 47 files. Phased execution with rollback points.
2New vocabulary breaks ingestion validatorsCriticalPhase A0 adds compatibility layer: dual-accept old+new types with ingestion normalizer.
3owner in NormalizedNodeType conflicts with connector contractCriticalFixed: NormalizedNodeType keeps human_identity. Platform stores owner internally. Normalizer maps.
4Identity-only assumptions in 5+ locationsHighExplicit file-by-file audit in A.5. Path materializer re-estimated at 12-16h.
5Edge migration mapping missingHighAdded A.3.1 migration table: old→new edge mapping with compatibility window.
6Chain temporal tracking missing from planHighAdded B.6 Phase 2: execution_chain_versions + diff API + events + UI (~40h).
7RUNS_AS typing unresolved for flow→human userMediumFixed: RUNS_AS constraint is automation → identity | owner.
8Doc/ADR updates missing from WA tasksMediumAdded A0.1 (ADRs before code) and A4.3 (doc updates). Sequenced with implementation.

11. Analysis References

Plan SectionAnalysis Source
Workstream A: Entity typesRound 5 Synthesis
Workstream A: Decision treeRound 5 Architect
Workstream A: File impact auditRound 5 Developer
Workstream B: execution_chainsRound 3 Synthesis
Workstream B: Chain builderRound 3 Architect
Workstream B: Effort estimatesRound 3 Developer
Workstream C: OAA exportRound 4 Synthesis
Workstream C: Execute gapRound 4 CISO
Workstream D: UI fixesRound 2 Synthesis
Security relevance tiersRound 1 Synthesis