Skip to main content

W1 Unified Implementation Plan

Date: 2026-02-17 Status: Ready for implementation — all documentation updates complete (Phase 6b done), all 5 mockups analyzed, 3 review rounds passed Scope: Workload rename + W1 product requirements across platform, connectors, UI, and documentation Architecture docs: Updated in parallel — see 01-data-model.md (W1 Derived Concepts section), 03-database.md, ADR-010


Executive Summary

This plan consolidates two major work streams into a single phased execution:

  1. Workload Renameentity_type: "automation""workload" across ~45 files (detailed in doc 11)
  2. W1 Product Requirements — New evaluator rules, risk clusters, exposure concept, posture summary, UX redesign

Key finding from 5-agent analysis: The data layer is almost entirely in place. The connector already produces execution_mode, egress_category, ownership_status, risk_group, data_domains, execution_count_30d, and security_relevance on automation entities. The gap is in:

  • Evaluator rules that surface risk from data that already exists (5-6 new rules)
  • Aggregation APIs for posture summary and risk clusters
  • UX reshaping to match W1 vocabulary and investigation flow

Estimated total effort: 8-10 working days for a demo-able W1.


1. Current State Assessment

What's DONE (no backend work needed)

W1 CapabilityCurrent Implementation
Autonomous execution inventoryConnector classifies execution_mode (autonomous/operator_assisted/human_triggered), platform stores, UI shows filterable table
Identity binding resolutionRUNS_AS relationships, BindingStatusBadge, ExecutionFlowDiagram shows identity chain
Data reachability classificationchain-builder.ts BFS traversal, execution_paths[] on entities, blast-radius API, UI Effects tab
Egress classificationegress_classifier.py in connector, egress_category/egress_host properties, EgressBadge throughout UI
Ownership validationownership_validator.py in connector, orphaned_ownership/ownership_degraded evaluator rules, OwnershipBadge in UI
Evidence completeness6 categories (current_roles, role_history, execution_evidence, ownership_records, approval_records, credential_state), EvidenceCompletenessBar component
Authority path diagramExecutionFlowDiagram.tsx renders linear flow: Trigger → Entry Point → Calls → Runs As → Can Access
Standing authority dataexecution_mode, auth_protocol from cross-system auth, human_session_required derivable

What's PARTIAL (reshape/extend)

W1 CapabilityGap
Posture summaryData exists on entity properties, needs aggregation API endpoint
Risk clustersConnector produces RG1-RG5 (2D), W1 needs 4D compound clusters (+ execution status + ownership)
Exposures conceptAutomations page is ~80% of Exposure View; needs rename, regroup, inline expand
HomepageDashboard has similar ingredients but wrong shape; needs execution visibility categories
Execution validationdormant_authority checks evidence age, W1 needs binary proven/unproven classification

What's NEW (build from scratch)

W1 CapabilityDescription
5-6 new evaluator rulesunproven_execution, unknown_identity_binding, reachable_sensitive_domain, llm_egress, external_egress, ownership_unknown
Risk cluster aggregation APIGET /api/v1/posture/risk-clusters — compound condition grouping
Posture summary APIGET /api/v1/posture/summary — 4 execution visibility categories
Delta since last refresh+X new autonomous identities, +Y ownership invalidations
Dark sidebar navigationComplete UX overhaul: 8 items → 7 items, white → dark navy (Graph Explorer retained)
Expandable exposure rowsInline detail panel with authority path, standing authority, ownership breakdown, evidence completeness

2. Architecture Decisions

Decision 1: Exposures = Entity + Finding Projections (NOT execution chains, NOT a new collection)

An Exposure is a derived assessment unit representing one Authority Path (Workload → Identity → Destination → Data Domain) enriched with its associated findings, execution activity, ownership state, and evidence completeness. Key distinctions:

  • Exposure ≠ Execution Chain. One ExecutionChainDoc is a BFS tree that can span multiple branches and resources. One Exposure is a single linear path through the entity graph.
  • Exposure ≠ Finding. A finding is an issue-level alert. An Exposure is the workload-level authority summary to which findings are attached.
  • Not persisted. Exposures are computed from entity relationships and execution_paths[] at query time.
  • Not dependent on execution_chains collection. W1 scope explicitly excludes chain persistence (logic.md section 9). Exposures are computed from entities directly.

Computation: For each workload entity, attempt to resolve its RUNS_AS identity. Two paths:

  1. Identity resolved: Collect execution_paths[] from the identity, group by (destination, data_domain) to produce one Exposure per unique authority path. Enrich with finding counts, execution stats, and ownership state.
  2. Identity unknown (no RUNS_AS, or non-unique target): Per logic.md section 2, unknown is a first-class result. Produce an Exposure with identity=unknown, destination=unknown, data_domain=unknown. The exposure still appears in the list with its unknown_identity_binding finding attached. This ensures every autonomous workload has at least one Exposure row — unknown states are visible, not silently dropped.

A new /api/v1/exposures endpoint serves this data. The existing /api/v1/execution-chains endpoint is NOT reused for W1.

Decision 2: Risk Clusters = Computed Aggregations (NOT persisted)

Per W1 logic.md section 7: "Grouping does not replace canonical findings and does not introduce new risk semantics." Risk Clusters are ephemeral, deterministic aggregations computed from existing entity properties:

  • egress_category (llm/external/internal)
  • execution_count_30d (>0 = active, 0 = dormant)
  • ownership_status (valid/invalid/ambiguous/unknown)
  • max_sensitivity from execution_paths[]

Computed via MongoDB aggregation pipeline. No new collection needed.

Decision 3: Workload Rename Before W1 Rules

The workload rename (entity_type: "automation""workload") should happen BEFORE writing new W1 evaluator rules. This avoids writing new rules against the old name and immediately renaming them.

Decision 4: W1 Finding Types Coexist with Existing Rules

Existing evaluator rules (scope_drift, privilege_justification_gap, unresolved_cross_system_auth) are W2+ scope per product docs. They should continue to exist and run, but W1 views filter to W1 finding types only. No rules are deleted.


3. W1 Finding Type Mapping

W1 Finding TypeStatusImplementation
unproven_executionNEW_RULEFires when a workload can execute autonomously but no execution evidence can be deterministically linked to it or its RUNS_AS identity. This includes: (a) zero evidence records, AND (b) evidence exists but deterministic linkage fails (per logic.md section 1: "condition (4) cannot be satisfied"). Binary: proven or unproven. dormant_authority keeps handling stale evidence (>90 days) separately.
unknown_identity_bindingNEW_RULEFires when a workload has no deterministic RUNS_AS relationship, OR the RUNS_AS target identity is not uniquely identifiable (per logic.md section 2: "identity object is uniquely identifiable"). Broader than unresolved_cross_system_auth (which only checks oauth_app + binding_status). No heuristic correlation permitted.
reachable_sensitive_domainNEW_RULEFires when entity has execution_paths with sensitivity in ("confidential", "restricted"). Structural exposure signal — always fires when the path exists. Severity: medium (confidential), high (restricted).
llm_egressNEW_RULEFires when properties.egress_category === "llm". Trivial property check. Severity: high.
external_egressNEW_RULEFires when properties.egress_category === "external". Same pattern. Severity: medium.
ownership_invalidEXISTSMaps to current orphaned_ownership. Alias at API layer or rename (decision: alias to avoid breaking finding IDs).
ownership_ambiguousNEW_RULEDistinct from ownership_degraded. Fires when the entity has ONLY group/team owners and has never had an individual owner assigned (per 01-data-model.md ownership rules). ownership_degraded = individual was once assigned and lost; ownership_ambiguous = no individual was ever assigned.
ownership_unknownNEW_RULEFires when insufficient deterministic metadata to determine ownership. Different from orphaned (no OWNED_BY edges) — this is metadata quality issue.

4. New API Endpoints

GET /api/v1/posture/summary

Returns all 4 posture stat cards in one response:

{
"data": {
"active_autonomous": { "count": 142, "label": "Execution Identities" },
"dormant_authority": { "count": 38, "label": "Dormant Authority Identities" },
"operator_assisted": { "count": 856, "label": "Assisted Workloads" },
"human_triggered": { "count": 2100, "label": "Human-Triggered Workloads" }
},
"delta_since_last_refresh": {
"new_autonomous_identities": 2,
"ownership_invalidations": 3,
"last_sync_at": "2026-02-16T10:42:00Z"
}
}

Implementation: MongoDB aggregation pipeline with identity-first counting for cards 1-2. The pipeline must count distinct identities (RUNS_AS targets of autonomous workloads), not raw workload entities. Multiple workloads sharing one identity count as 1.

  • Cards 1-2 (Execution Identities, Dormant Authority): Count distinct identity entities that are RUNS_AS targets, split by execution_count_30d > 0 vs == 0.
  • Cards 3-4 (Assisted Workloads, Human-Triggered Workloads): Count workload entities by execution_mode. UI labels use "Workloads" (not "Automations") per terminology decision.

GET /api/v1/posture/risk-clusters?limit=10

Returns top risk clusters:

{
"data": [
{
"cluster_key": "sensitive:llm:active:ownership_invalid",
"label": "Sensitive + LLM + Active + Invalid Owner",
"identity_count": 12,
"execution_count_30d": 8400,
"sensitive_domains": ["financial", "identity"],
"ownership_invalid_count": 12,
"priority": "P0"
}
]
}

Implementation: MongoDB aggregation with two stages — first group workloads by compound key (max_sensitivity_bucket, egress_category, execution_active, ownership_status), then deduplicate RUNS_AS identity targets for the identity_count metric. The identity_count field must reflect distinct identities, not workloads.

GET /api/v1/exposures?cluster_key=&limit=50

New endpoint (NOT a modification of /api/v1/execution-chains). Computes exposures from entity graph:

  1. Query workload entities (with optional filters: cluster_key, execution_mode, finding_type, data_domain)
  2. For each workload, attempt to resolve RUNS_AS identity target
  3. If identity resolved: Collect execution_paths[] from the identity, group by (destination, data_domain). Produce one Exposure per unique authority path tuple: (workload_id, identity_id, destination, data_domain)
  4. If identity unknown (no RUNS_AS or non-unique target): Produce a single Exposure with identity=unknown, destination=unknown, data_domain=unknown. Ensures every autonomous workload appears in the exposure list — unknown is a first-class state, not silently dropped.
  5. Enrich each exposure with: execution_count_30d, last_execution_at, ownership_status, data_domains, finding_count, finding_types[], evidence_completeness

The exposure ID is deterministic: EXP-{short_hash(tenant_id, workload_id, identity_id, destination, data_domain)}.

GET /api/v1/exposures/:id (Exposure Detail)

Returns a single exposure with full detail for 6 panels (per mockup exposure--graph.jpg):

{
"data": {
"exposure_id": "EXP-021",
"title": "Auto-GPT Instance #42 → OpenAI",
"evidence_verified_at": "2026-02-16T10:42:00Z",

"authority_path": {
"workload": { "id": "...", "name": "Auto-GPT Instance #42", "entity_type": "workload" },
"identity": { "id": "...", "name": "svc_llm_processor", "entity_type": "identity", "subtype": "service_principal" },
"destination": { "id": "...", "name": "OpenAI API Gateway", "entity_type": "connection" },
"data_domain": { "id": "...", "name": "Financial", "sensitivity": "confidential" },
"edges": [
{ "source": "workload", "target": "identity", "type": "RUNS_AS" },
{ "source": "workload", "target": "destination", "type": "INVOKES" },
{ "source": "destination", "target": "data_domain", "type": "REACHES", "derived": true }
]
},

"standing_authority": {
"execution_model": "autonomous",
"auth_type": "client_credentials",
"human_session_required": false
},

"deterministic_linkage_proof": {
"issuing_tenant": "acme-prod",
"target_instance": "openai-org-772",
"match_type": "deterministic",
"match_detail": "Matching sub_id value workload-42-primary"
},

"ownership_breakdown": {
"primary": { "status": "departed", "owner_name": null },
"secondary": { "status": "none" },
"inherited": { "status": "present", "owner_name": "Platform Team" }
},

"workload_metadata": {
"source_system": "github",
"artifact_identifier": "auto-gpt-main",
"last_refreshed_at": "2026-02-16T10:40:00Z"
},

"identity_binding": {
"relationship": "RUNS_AS",
"label": "Workload Identity",
"protocol": "OIDC (Federated)",
"target_system": "gcp"
},

"findings": [...],
"evidence_completeness": {...},
"execution_evidence_summary": {
"total_records": 1420,
"last_execution_at": "2026-02-16T10:40:00Z",
"execution_count_30d": 1420
}
}
}

Key data sources:

  • Standing authority: execution_mode from entity properties, auth_type from cross-system auth record, human_session_required derived from execution_mode
  • Deterministic linkage proof: Cross-system auth record fields (issuing_tenant, target_instance, binding_status, matching criteria)
  • Ownership breakdown: OWNED_BY relationships resolved to owner entities with status field
  • Workload metadata: Entity source_system, source_id, updated_at
  • Identity binding: RUNS_AS relationship type + cross-system auth protocol + identity entity's source_system
  • Execution evidence: Aggregated from execution_evidence entities linked to the workload or its RUNS_AS identity (E3 cross-lookup)

5. UX Redesign

5.0 Mockup Reference

All mockups are in docs/product/wedges/w1-exposure/mockups/:

MockupFileShows
Exposure Discovery2026-02-17-mockup-exposure-discovery.jpgW1 landing page: Posture Summary (4 cards), delta indicators, Top 5 Risk Clusters, collapsed findings view
Exposures List2026-02-17-mockup-expsosures-list.jpgExposure table with search, filters, pagination, data domain badges, egress category. "Create Ticket" + "Export" buttons
Risk Cluster Drill-down2026-02-17-mockup-risk-clusters.jpgCluster → exposures list with inline expandable rows showing authority path, standing authority, ownership, evidence completeness
Exposure Detail (Graph)2026-02-17-mockup-exposure--graph.jpgSingle exposure detail: interactive authority path graph, 6 detail panels (Standing Authority, Deterministic Linkage Proof, Ownership Breakdown, Workload Metadata, Identity Binding, Execution Evidence), "Create Ticket" button
Relationship Diagram2026-02-17-relationship-diagram.jpgConceptual model: Automation Definition → Authority Path → Exposure ↔ Risk Cluster; Authority Path → Automation Run → Execution Evidence

5.0.1 Cross-Mockup Consistency Notes

Minor mockup discrepancies (resolve during implementation):

  1. Nav item count: Discovery mockup shows 5 nav items (missing "Exposures"). Exposures List and Detail mockups show 6 items. Canonical: 7 items (Overview, Clusters, Exposures, Identities, Data Domains, Graph Explorer, Settings). Graph Explorer is retained from current UI — it's already built and provides value for investigation.
  2. Nav label "Clusters" vs "Risk Clusters": Discovery mockup uses "Clusters", Risk Cluster drill-down mockup uses "Risk Clusters". Canonical: "Clusters" (shorter, consistent with Discovery mockup).
  3. Identity node type in detail graph: Exposure Detail mockup labels the identity node as entity_type: "resource" with a "service" badge. In the real data model, RUNS_AS targets are entity_type: "identity". Implementation: use actual entity_type from data, the mockup label is illustrative.
  4. User personas differ across mockups: "Sarah Jenkins, SecOps Admin" (Discovery), "Jane Doe, Security Analyst" (List, Detail). This is intentional (different user roles), not an inconsistency.

5.1 Navigation Restructure

Current (8 items, white sidebar)W1 (7 items, dark navy sidebar)
DashboardOverview ("Exposure Discovery")
AutomationsExposures (formerly Automations)
Findings(moved under Exposure detail)
EntitiesIdentities (filtered to workloads + identities)
Graph ExplorerGraph Explorer (retained — already built, useful for investigation)
Chains(replaced by Exposures)
Syncs(moved to Settings)
Temporal Compare(available via link from entity pages)
Clusters (new)
Data Domains (new)
Settings (new, contains Syncs + config)

5.2 Page Mapping

W1 PageSourceReuse %Key Changes
Exposure Discovery (Homepage)Dashboard.tsx60%Title "Exposure Discovery". Replace stat cards with 4 Posture Summary cards, add delta indicators, add Top 5 Risk Cluster cards, add collapsed Filtered Findings View at bottom
Exposures ListAutomationsPage.tsx80%Rename, add search by Exposure ID/name, add Filters button, add pagination ("Showing 1-12 of 145 exposures"), add "Create Ticket" + "Export" buttons. Table columns: Exposure ID, Exposure (name with → arrow notation), Last Execution, Executions (30D), Ownership Status, Data Domains, Egress Category
Exposure DetailAutomationDetailPage.tsx50%Major rework — see section 5.6 below. Interactive authority path graph, 6 detail panels, "Create Ticket" button, breadcrumb navigation
Risk Cluster Drill-downNEW (but reuses Exposures table pattern)40%Breadcrumb: "Risk Clusters > [cluster name]". Exposures table filtered by cluster, with inline expandable rows showing authority path + standing authority + ownership + evidence completeness. "Export" + "Create ticket" buttons
IdentitiesEntitiesListPage.tsx85%Filter to workloads + identities only
Data DomainsNEW0%New page browsing resources by business domain
SettingsNEW30%Move Syncs, tenant config, user settings here

5.3 New Components Required

  1. RiskClusterCard — Compound condition title (e.g., "Sensitive + LLM + Active + Invalid Owner"), "COMPOUND CONDITION" label, data domain badges with icons, dual metrics (Identities + 30d Execs), ownership warning pill (red), priority border color (red = highest, blue = others)
  2. DataDomainBadge — Pill badges with icons for FIN, GenAI, PII, SRC, SaaS, EXT, INT, Logs, Keys, Customer Data, Eng
  3. DeltaIndicator — Change-since-refresh inline badges: "+2 new autonomous identities", "+3 ownership invalidations", "Since Last Refresh"
  4. ExpandableExposureRow — Row with chevron toggle and inline detail panel showing: authority path (4-node linear with icons), standing authority, ownership breakdown, evidence completeness. Footer: "Evidence verified: X mins ago" + "Cross-system identity linkage verified" status + "View Full Detail →" link
  5. StandingAuthorityPanel — Key-value card: Execution Model (Autonomous/Assisted/Human), Auth Type (Client Credentials/etc.), Human Session Required (Yes/No)
  6. OwnershipBreakdownPanel — Per-owner status: Primary (Departed/Present/None), Secondary (Departed/Present/None), Inherited (Departed/Present/None) with status icons
  7. DeterministicLinkageProofPanel — Cross-system linkage evidence: Issuing Tenant, Target Instance, "Deterministic Match" badge with matching detail (e.g., "Matching sub_id value workload-42-primary"). Shows how the cross-system identity join was established deterministically.
  8. WorkloadMetadataPanel — Source System (with platform icon), Artifact Identifier, Last Refreshed timestamp
  9. IdentityBindingPanel — Relationship type (RUNS_AS + "Workload Identity" label), Protocol (OIDC Federated/SAML/etc.), Target System (with platform icon: GCP/Azure/AWS)
  10. Breadcrumb — Navigation breadcrumb component (e.g., "Exposures > EXP-021" or "Risk Clusters > Sensitive + LLM + Active + Invalid Owner")
  11. UserProfileHeader — Top-right user info with avatar, name, role, org
  12. RefreshTimestamp — Pill with clock icon showing "Last Refreshed: Feb 16, 2026, 10:42 AM"
  13. CreateTicketButton — "Create Ticket" action button, appears on Exposures List, Exposure Detail, and Risk Cluster drill-down
  14. ExportButton — "Export" action button with download icon
  15. FilteredFindingsView — Collapsible findings table for the Overview page, pre-filtered to W1 finding types. Shown collapsed by default with "Filtered Findings View (Collapsed)" label.

5.4 Existing Components Reusable

ComponentReuse Strategy
StatCard.tsxExtend with accentColor, statusDot, subtitle props for Posture Summary cards
ExecutionFlowDiagram.tsxTwo rendering modes (both linear per ux.md): (1) Inline expand: compact icon-based 4-node path, (2) Detail page: full 4-node linear diagram with entity-type colored cards and labeled edges (RUNS_AS, INVOKES, REACHES — note: REACHES is a display label, not a stored relationship)
AutomationBadges.tsxRename to WorkloadBadges.tsx (part of workload rename), extend for new badge types
EvidenceCompletenessBar.tsxReuse as-is: 6-category horizontal bars in both inline expand and detail page
DataTable.tsxAlready supports renderSubRow and expandedRowId — use existing expand pattern, no extension needed
SeverityBadge.tsxReuse for finding severity in exposure rows
OwnershipBadge.tsxReuse for ownership status column in exposure table (Valid/Invalid badges)

5.5 Exposure Discovery Page (Overview) Detail

Per mockup: 2026-02-17-mockup-exposure-discovery.jpg

Layout (top to bottom):

  1. Header: "Exposure Discovery" title + RefreshTimestamp pill + UserProfileHeader
  2. Posture Summary: 4 StatCard cards in a row:
    • Card 1: "EXECUTION IDENTITIES" = 142, red dot, "Autonomous Authority" — counts distinct RUNS_AS identity targets
    • Card 2: "DORMANT AUTHORITY IDENTITIES" = 38, orange dot, "No execution in Last 30d" — counts distinct identities with zero 30d executions
    • Card 3: "ASSISTED WORKLOADS" = 856, blue dot, "Requires Human Session" — counts workloads with execution_mode: "operator_assisted"
    • Card 4: "HUMAN-TRIGGERED WORKLOADS" = 2.1k, grey dot, "User-Initiated" — counts workloads with execution_mode: "human_triggered"
  3. Delta indicators: DeltaIndicator badges: "+2 new autonomous identities", "+3 ownership invalidations", "Since Last Refresh"
  4. Top 5 Autonomous Authority Risk Clusters: Section title + "View all clusters →" link. 5 RiskClusterCard in a row, each showing:
    • Priority border (red = P0, blue = others)
    • Compound condition title
    • "COMPOUND CONDITION" label
    • Data domain badges (FIN, GenAI, PII, SRC, SaaS, EXT, INT)
    • Egress type badge if applicable
    • Dual metrics: "Identities" count + "30d Execs" count
    • Ownership warning pill (red) or neutral status text ("All ownership verified", "No status flags")
  5. Filtered Findings View: Collapsible section at bottom, collapsed by default. When expanded, shows a findings table filtered to W1 finding types.

5.6 Exposure Detail Page Detail

Per mockup: 2026-02-17-mockup-exposure--graph.jpg

Layout (top to bottom):

  1. Breadcrumb: "Exposures > EXP-021"
  2. Header: "EXP-021 | Auto-GPT Instance #42 → OpenAI" + CreateTicketButton
  3. Subheader: "Evidence verified: Feb 16, 2026, 10:42 AM"
  4. Authority Path Graph: 4-node linear diagram (per ux.md section 3A: "Linear only"). Nodes have entity-type styling:
    • Workload node: blue dashed border, entity name + "workload" type label
    • Identity node: coral/red background, entity name + subtype badge (e.g., "service_principal")
    • Destination node: cyan border, entity name + "connection" type label
    • Data Domain node: data domain badge with sensitivity level
    • Edge labels: "RUNS_AS" (workload→identity), "INVOKES" (workload→destination), "REACHES" (destination→data domain — display label only, not a stored relationship; derived from execution_paths[])
    • Note: The mockup shows 3 visible nodes with data domain as a badge on the destination. Implementation adds data domain as a true 4th node for consistency with the 4-node authority path model. Per user decision: more detail is better.
  5. Detail cards (2-column grid, 3 rows):
    • Standing Authority (left): Execution Model, Auth Type, Human Session Required
    • Ownership Breakdown (right): Primary/Secondary/Inherited owner with Departed/Present/None status
    • Deterministic Linkage Proof (left): Issuing Tenant, Target Instance, "Deterministic Match" with sub_id matching evidence
    • Workload Metadata (right): Source System (with icon), Artifact Identifier, Last Refreshed
    • (bottom left: empty or additional space)
    • Identity Binding (right): RUNS_AS relationship, Protocol (OIDC Federated), Target System (GCP)
  6. Execution Evidence (bottom): Section showing linked execution evidence records

6. Phased Execution Plan

Phase 0: Workload Rename (Day 1-2)

Detailed in doc 11 — workload-rename-implementation-plan.md

Execute the full workload rename FIRST so all subsequent work uses the new vocabulary:

  • Platform core: entity_type: "workload", WORKLOAD_SUBTYPES, workloadSubtype
  • Platform tests: Update all fixtures and assertions
  • UI: "workload" in types, color maps, filters; rename files
  • Connector: node_type="workload", workloadSubtype
  • DB migration: entities, entity_versions, execution_chains
  • Backward compat: Accept "automation" as deprecated alias

Verification: npm test + npx tsc --noEmit + cd ui && npm run build + pytest

Phase 1: W1 Domain Types + Evaluator Rules (Day 2-3)

1a. Add W1 finding types to type system

FileChanges
src/domain/findings/types.tsAdd to FINDING_TYPES: unproven_execution, unknown_identity_binding, reachable_sensitive_domain, llm_egress, external_egress, ownership_ambiguous, ownership_unknown
ui/src/api/api-types.tsAdd same types to FindingType union

1b. Write new evaluator rules

FileRuleLogic
src/evaluator/rules/unproven-execution.ts (NEW)unproven_executionWorkload can execute autonomously but no ExecutionEvidence can be deterministically linked to it or its RUNS_AS targets. Covers both zero records AND records that exist but lack deterministic linkage.
src/evaluator/rules/unknown-identity-binding.ts (NEW)unknown_identity_bindingWorkload has no RUNS_AS relationship, OR the RUNS_AS target identity is not uniquely identifiable. No heuristic correlation.
src/evaluator/rules/reachable-sensitive-domain.ts (NEW)reachable_sensitive_domainEntity has execution_paths with sensitivity in (confidential, restricted)
src/evaluator/rules/egress-exposure.ts (NEW)llm_egress, external_egressCheck properties.egress_category === "llm" or === "external"
src/evaluator/rules/ownership-gaps.ts (NEW)ownership_ambiguous, ownership_unknownGroup-only ownership / insufficient metadata
src/evaluator/rules/dormant-authority.ts (MODIFY)SplitAdd guard: if zero evidence records, return null (let unproven_execution handle it). Only fire when evidence exists but is stale (>90 days).
src/evaluator/rules/index.ts (MODIFY)RegisterAdd all new rules to ALL_RULES array

1c. Tests for new rules

  • Unit tests for each new rule (~2 tests each minimum)
  • Update dormant-authority.test.ts for split behavior

Verification: npm test — all tests pass

Phase 2: Aggregation APIs (Day 3-4)

2a. Storage layer — add aggregation support

FileChanges
src/storage/storage-adapter.tsAdd aggregatePostureSummary(tenantId) and aggregateRiskClusters(tenantId, limit) to interface
src/storage/mongo/adapter.tsImplement using MongoDB aggregation pipeline ($match, $group, $sort)

2b. New API routes

FileEndpoints
src/api/routes/posture.ts (NEW)GET /api/v1/posture/summary — 4 execution visibility counts + delta
src/api/routes/posture.ts (NEW)GET /api/v1/posture/risk-clusters — compound condition aggregation
src/api/routes/exposures.ts (NEW)GET /api/v1/exposures + GET /api/v1/exposures/:id — compute from entity graph, NOT from execution_chains

2c. Exposure computation logic

FileChanges
src/domain/exposures/compute.ts (NEW)Pure function: given a workload entity + its RUNS_AS identity + identity's execution_paths + associated findings → produce Exposure view models. No dependency on execution_chains collection or chain-builder.ts.

2d. Route registration

FileChanges
src/api/app.tsRegister createPostureRoutes(deps.storageAdapter) and createExposureRoutes(deps.storageAdapter) alongside existing route mounts (lines 66-74). Routes mount in app.ts, not index.ts.

Verification: npm test + npm run test:integration + manual API smoke test

Phase 3: UI Workload Rename + Foundation (Day 4-5)

Included in Phase 0 workload rename, but listing UI-specific changes for clarity:

FileChanges
ui/src/api/api-types.ts"automation""workload" in EntityType union
ui/src/hooks/use-automations.tsuse-workloads.tsRename hook, entity_type: "workload"
ui/src/components/AutomationBadges.tsxWorkloadBadges.tsxRename exports
All UI files referencing "automation"Update to "workload"

Phase 4: W1 UX Redesign (Day 5-8)

4a. Navigation + Layout

FileChanges
ui/src/components/Layout.tsxDark navy sidebar, new nav items (Overview, Clusters, Exposures, Identities, Data Domains, Graph Explorer, Settings), SecurityV0 branding with Admin Console subtitle, UserProfileHeader top-right
ui/src/App.tsxNew routes: /, /clusters, /exposures, /identities, /data-domains, /graph, /settings; redirect /automations/*/exposures/*; keep existing graph explorer route

4b. Exposure Discovery (Homepage)per mockup 2026-02-17-mockup-exposure-discovery.jpg

ComponentSourceChanges
Page renameDashboardPage.tsxExposureDiscoveryPage.tsxTitle "Exposure Discovery", completely new layout per section 5.5
PostureSummaryCardsExtend StatCard.tsx4 cards with colored accent dot, subtitle. New usePostureSummary hook calling /api/v1/posture/summary
DeltaIndicatorNEW"+2 new autonomous identities", "+3 ownership invalidations", "Since Last Refresh"
RiskClusterCardsNEWTop 5 clusters with priority borders. New useRiskClusters hook calling /api/v1/posture/risk-clusters. "View all clusters →" link
RefreshTimestampNEWClock icon + last sync timestamp pill in header
FilteredFindingsViewNEWCollapsible W1 findings table at bottom, collapsed by default

4c. Exposures Page (replaces Automations)per mockup 2026-02-17-mockup-expsosures-list.jpg

ComponentSourceChanges
Page renameAutomationsPage.tsxExposuresPage.tsxTitle "Exposures". Search bar ("Search by Exposure ID or name..."), Filters button, pagination ("Showing 1-12 of 145 exposures"), CreateTicketButton + ExportButton in header
Table columnsReframe from automation columnsEXPOSURE ID (EXP-NNN, clickable link), EXPOSURE (name with → arrow notation + execution mode badge), LAST EXECUTION, EXECUTIONS (30D), OWNERSHIP STATUS (Valid/Invalid badge), DATA DOMAINS (pill badges), EGRESS CATEGORY (text with color: LLM=orange, External=red, Internal=grey)
Expandable rowsDataTable.tsx (already supports renderSubRow + expandedRowId)Implement renderSubRow callback; no DataTable extension needed

4d. Exposure Detail (replaces Automation Detail)per mockup 2026-02-17-mockup-exposure--graph.jpg

ComponentSourceChanges
Page renameAutomationDetailPage.tsxExposureDetailPage.tsxMajor rework per section 5.6. Breadcrumb, interactive authority path graph, 6 detail panels, Create Ticket button
AuthorityPathGraphAdapt ExecutionFlowDiagram.tsx4-node linear diagram (per ux.md: "Linear only") with entity-type colored nodes, labeled edges (RUNS_AS, INVOKES, REACHES). Data domain rendered as true 4th node.
StandingAuthorityPanelNEWExecution Model / Auth Type / Human Session Required
DeterministicLinkageProofPanelNEWIssuing Tenant, Target Instance, Deterministic Match badge with sub_id evidence
OwnershipBreakdownPanelNEWPrimary/Secondary/Inherited owner with Departed/Present/None status
WorkloadMetadataPanelNEWSource System (icon), Artifact Identifier, Last Refreshed
IdentityBindingPanelNEWRUNS_AS relationship, Protocol (OIDC/SAML), Target System (GCP/Azure/AWS icon)
Execution Evidence sectionNEW or extend existing evidence tabLinked execution evidence records for the workload and its RUNS_AS identity

4e. Risk Cluster Drill-downper mockup 2026-02-17-mockup-risk-clusters.jpg

ComponentSourceChanges
RiskClusterDrilldownPage.tsxNEW (but reuses Exposures table)Breadcrumb: "Risk Clusters > [cluster name]". Title "Exposures: [cluster name]". ExportButton + CreateTicketButton. Exposures table filtered by cluster_key. Inline expandable rows with full detail panel.
ExpandableExposureRow detail panelNEW3-column layout: Authority path (4-node linear with icons), Standing Authority, Ownership Breakdown, Evidence Completeness (6 bars). Footer: "Evidence verified: X ago" + "Cross-system identity linkage verified" + "View Full Detail →" link
RiskClustersPage.tsx (grid view)NEWGrid of RiskClusterCard components, click to drill into RiskClusterDrilldownPage
RiskClusterCardNEWPriority border (red/blue), compound condition title, "COMPOUND CONDITION" label, domain badges, identity count, 30d execs, ownership warning
DataDomainBadgeNEWIcon + label pills for FIN, GenAI, PII, SRC, SaaS, EXT, INT, Logs, Keys, Customer Data, Eng

Phase 5: Connector Workload Rename (Day 8-9)

From workload rename plan:

FileChanges
transformer.pynode_type="workload", workloadSubtype, _enrich_workload_properties
correlator.pyVariable names, comments
tests/unit/test_transformer.pyProperty name assertions
Other connector filesComments/docstrings

Verification: pytest — all tests pass

Phase 6: Database Migration + Documentation (Day 9-10)

6a. Database migration

// Run AFTER deploying code that accepts both old and new values
db.entities.updateMany(
{ entity_type: "automation" },
[{ $set: {
entity_type: "workload",
"properties.workloadSubtype": "$properties.automationSubtype"
}}]
);
db.entity_versions.updateMany(
{ entity_type: "automation" },
[{ $set: {
entity_type: "workload",
"properties.workloadSubtype": "$properties.automationSubtype"
}}]
);
db.execution_chains.updateMany(
{ "entity_refs.entity_type": "automation" },
{ $set: { "entity_refs.$[elem].entity_type": "workload" } },
{ arrayFilters: [{ "elem.entity_type": "automation" }] }
);

6b. Documentation updates

FileStatusChanges
sv0-documentation/docs/architecture/01-data-model.mdDONEEntity type "workload", W1 Derived Concepts section, new finding types
sv0-documentation/docs/architecture/03-database.mdDONEWorkload entity type, W1 scope note on execution_chains
sv0-documentation/docs/architecture/decisions/adr-010-workload-entity-rename.mdDONEFormal rename decision record
sv0-documentation/docs/analysis/.../09-naming-research-comparison.mdDONEMarked workload as chosen, surface as rejected
sv0-documentation/docs/glossary.mdDONEEntity type table (workload), W1 vocabulary (exposure, authority path, risk cluster, standing authority, posture summary), W1 finding types
sv0-documentation/docs/architecture/04-api-layer.mdDONEWorkload entity type, W1 posture + exposure endpoints, updated endpoint summary
sv0-platform/CLAUDE.mdDONEEntity types, W1 API endpoints, W1 finding types, W1 evaluator rules, W1 UI pages
sv0-documentation/docs/product/wedges/w1-exposure/*.mdDONEImplementation status markers on definition, scope, logic, UX specs

7. MVP Path (Minimum for Demo-able W1)

If time is constrained, prioritize these for maximum "wow moment" impact:

Day 1: Workload Rename + W1 Finding Types

  • Phase 0 (workload rename) — establishes clean vocabulary
  • Phase 1a (finding types) + three highest-impact rules: reachable_sensitive_domain, llm_egress, external_egress
  • These fire on data that ALREADY EXISTS — immediate new findings after re-evaluation

Day 2: Posture API + Homepage Reshape

  • Phase 2a-b (posture summary + risk cluster aggregation endpoints)
  • Phase 4b (Homepage with execution visibility cards + Top 5 clusters)
  • Use existing RG1-RG5 as demo proxy for full compound clusters

Day 3: Exposure View + Detail

  • Phase 4c (rename Automations → Exposures, add inline expand)
  • Phase 4d (Standing Authority block on detail page)
  • Phase 4a (dark sidebar navigation)

Deferrable for post-demo:

  • Full compound Risk Cluster computation (RG1-RG5 works for demo)
  • Delta since last refresh (show "Last synced: timestamp" instead)
  • Data Domains page
  • Remaining new evaluator rules (unproven_execution, unknown_identity_binding, ownership_unknown)
  • Connector workload rename (platform backward compat handles old names)
  • DB migration (backward compat handles old values)

8. Verification Checklist

Build & Test

  • npm test — all unit tests pass (including new rule tests)
  • npm run test:integration — all integration tests pass
  • npx tsc --noEmit — typecheck clean
  • cd ui && npm run build — UI builds
  • pytest (connectors) — all tests pass
  • Grep for leftover "automation" (excluding deprecated-alias code and comments)

Platform

  • Local docker compose up --build — UI displays "Workload" in graph legend
  • Ingest payload with node_type: "workload" — works correctly
  • Ingest payload with node_type: "automation" (deprecated) — backward compat works
  • New W1 findings appear after re-ingestion (reachable_sensitive_domain, llm_egress, etc.)
  • GET /api/v1/posture/summary returns 4 cards with identity-first counting
  • GET /api/v1/posture/risk-clusters returns compound condition clusters
  • GET /api/v1/exposures returns computed exposures (not execution chains)
  • GET /api/v1/exposures/:id returns all 6 detail panels' data

UI — Exposure Discovery (per mockup-exposure-discovery.jpg)

  • Page title "Exposure Discovery" with RefreshTimestamp pill
  • 4 Posture Summary cards with correct labels, counts, colored dots, subtitles
  • Delta indicators below posture cards
  • Top 5 Risk Cluster cards with priority borders, domain badges, identity counts
  • "View all clusters →" link navigates to Risk Clusters page
  • Filtered Findings View section (collapsed by default)

UI — Exposures List (per mockup-expsosures-list.jpg)

  • Search bar, Filters button, pagination
  • Table columns: Exposure ID, Exposure, Last Execution, Executions (30D), Ownership Status, Data Domains, Egress Category
  • Create Ticket + Export buttons
  • Exposure names use → arrow notation with execution mode badge

UI — Exposure Detail (per mockup-exposure--graph.jpg)

  • Breadcrumb: "Exposures > EXP-NNN"
  • Header with exposure title (name → destination) + Create Ticket button
  • Interactive authority path graph with entity-type colored nodes and labeled edges
  • Standing Authority panel: Execution Model, Auth Type, Human Session Required
  • Deterministic Linkage Proof panel: Issuing Tenant, Target Instance, Match evidence
  • Ownership Breakdown panel: Primary/Secondary/Inherited with status
  • Workload Metadata panel: Source System, Artifact Identifier, Last Refreshed
  • Identity Binding panel: RUNS_AS, Protocol, Target System
  • Execution Evidence section

UI — Risk Cluster Drill-down (per mockup-risk-clusters.jpg)

  • Breadcrumb: "Risk Clusters > [cluster name]"
  • Exposures table filtered by cluster with inline expandable rows
  • Expanded row shows: authority path (linear icons), standing authority, ownership, evidence completeness (6 bars)
  • Expanded row footer: evidence timestamp, linkage verification status, "View Full Detail →" link

9. What Does NOT Change

  • execution_chains collection — W1 explicitly excludes chain persistence; existing collection continues to work but W1 does not depend on it
  • Drift detection (scope_drift rule) — W2 scope, keeps running but not surfaced in W1 views
  • Permission history (privilege_justification_gap rule) — W2 scope, same
  • Evidence pack assembly — continues as-is, used by exposure detail views
  • Existing API endpoints — all stay, new endpoints are additive
  • Graph Explorer — remains in primary navigation as-is (useful for investigation workflows)
  • Temporal Compare — remains available via direct link
  • Connector ingestion formatNormalizedGraph schema unchanged (just the node_type value changes)

10. Risk Mitigation

RiskMitigation
Workload rename breaks existing dataBackward-compat alias in NormalizedNodeType; platform accepts both "automation" and "workload"
New evaluator rules generate too many findingsStart with medium severity; add security_relevance filter to suppress internal_inventory entities
MongoDB aggregation performanceRisk clusters are computed on entities collection which has indexes on tenant_id + entity_type; add compound index on (tenant_id, entity_type, properties.execution_mode) if needed
UX redesign scope creepMVP path defined — prioritize Days 1-3, defer rest
Finding ID stability after rename`eval:hash(tenant