Flow logic, process mining, and breaking-change graph
Beyond the per-flow SAST detectors, Vulkro builds an automation graph across every flow, subflow, process, and the fields they touch. This graph powers three families: flow-logic integrity (broken or stale references inside a flow), process mining (the shape of the automation estate as a whole), and a breaking-change graph (what a delete or rename would ripple into).
These findings are about correctness and blast radius, not exploits. They catch the automation that silently does nothing, the field a flow reads that no longer exists, and the central flow that half the org depends on.
SF-FLOW-LOGIC-001: subflow to a missing or inactive flow
What triggers it. A flow contains a subflow element whose
flowName resolves to a flow that is not present in the project, or
resolves to a flow whose active version is inactive.
Why it matters. A subflow call into a missing or inactive target fails at runtime or silently skips the called logic, depending on the trigger context. The parent flow looks complete in the builder but a branch of its behaviour never runs. This is a common artifact of a partial retrieve or a flow that was deactivated without auditing its callers.
How to fix. Restore the called flow (retrieve it if it lives in the org but not in the project), activate the correct version, or remove the subflow call if the called logic is genuinely retired.
SF-FLOW-LOGIC-002: flow references a candidate-unused field
What triggers it. A flow reads or writes a field that the reference graph also marks as a candidate-unused field, meaning the flow is the field's only consumer and nothing populates or reads it elsewhere.
Why it matters. A flow assigning a value to a field that no report, page layout, or downstream automation ever reads is doing dead work, and often signals a half-finished migration. Conversely, a flow reading a field nothing writes will always see a null and branch the wrong way.
How to fix. Trace the field's intended lifecycle. Either wire up the missing consumer or producer, or retire both the field and the flow branch that touches it.
SF-PROCESS-MINE-001: orphan flow
What triggers it. A flow with no inbound trigger and no parent: not record-triggered, not schedule-triggered, not platform-event-triggered, not called as a subflow, and not invoked from any process, Apex, or action.
Why it matters. An orphan flow can never run. It is pure deploy weight and review surface, and it muddies the automation inventory so that genuinely live flows are harder to find. Orphans accumulate from abandoned experiments and from triggers that were removed without removing the flow.
How to fix. Confirm the flow has no runtime-dynamic launch path (for example an invocable call built from a string in Apex), then retire it or document why it is intentionally dormant.
SF-PROCESS-MINE-002: hub flow
What triggers it. A flow whose inbound reference count (subflow callers plus invocations) exceeds a configurable fan-in threshold, marking it as a central automation hub.
Why it matters. A hub flow is a single point of failure and a change-management hazard. A defect in a hub propagates to every caller, and any edit to its interface (an input variable rename, an output removal) is a breaking change with wide reach. Hubs are not bugs, but they deserve extra test coverage and a documented contract.
How to fix. Treat the hub as an interface. Pin its input and output variable names, add regression coverage that exercises each caller path, and review every change to it as you would a shared library.
SF-PROCESS-MINE-003: automation inventory
What triggers it. This is an informational rollup rather than a defect finding. It emits the full automation inventory: every flow with its trigger type, version state, caller count, and the fields and objects it touches.
Why it matters. The inventory is the baseline for governance and for AppExchange Security Review prep. It answers "what automation runs in this org, and on what" in one artifact, which is otherwise tedious to assemble by hand.
How to fix. No fix is required. Use the inventory to prioritize the orphan, hub, and logic findings above, and to brief reviewers.
SF-BREAKING-001: high-fan-in node, high-risk delete or rename
What triggers it. A planned or detected delete or rename of a node (a flow, a field, an object, an Apex member) that has many inbound edges in the automation and reference graph. The finding ranks the change by the number and type of dependents it would break.
Why it matters. The most expensive Salesforce incidents come from a "simple" rename or delete whose blast radius was never mapped. Renaming a field that 30 flows read, or deleting an object an installed package depends on, breaks far more than the change author can see in the builder. This finding turns blast radius into a number before you deploy.
How to fix. Review each dependent the finding lists. Stage the change behind a deprecation window where the platform allows it, update every dependent in the same change set, and never ship a high-fan-in delete or rename without first confirming the full dependent list is addressed.
Reading the output
Each finding carries the node API name, its node type, and its inbound and outbound edge counts. The breaking-change finding additionally lists the dependent nodes by type so the blast radius is explicit. JSON output includes the graph node identifiers so a change can be replayed against the inventory across runs.