A call from a zoned file to a callee forbidden for that zone via
boundaries.calls.forbidden. One finding is reported per unique callee
path per file (first occurrence wins).
Wire-shape envelope for a BoundaryCallViolation finding. Carries
actions for refactoring the forbidden call out of the zone or suppressing
it with the shared boundary-violation token.
Wire-shape envelope for a BoundaryCoverageViolation finding. Carries
actions for assigning the file to a zone or explicitly allowing it to stay
unmatched.
Wire-shape envelope for a BoundaryViolation finding. Mirrors
UnusedFileFinding: flattens the bare finding and carries a typed
actions array (refactor-boundary primary plus suppress-line
secondary).
Wire-shape envelope for a CircularDependency finding. Mirrors
UnusedFileFinding: flattens the bare finding and carries a typed
actions array (refactor-cycle primary plus suppress-line
secondary).
Wire-shape envelope for a DuplicateExport finding. Carries up to
three actions in position-locked order: an add-to-configignoreExports
snippet (only when locations[] carries at least one path) followed by
the remove-duplicate fix and the multi-location suppress.
A React/Preact component that participates in a duplicate-prop-shape GROUP:
three or more distinct components across two or more files whose
statically-harvested, fully-known prop NAME set is byte-for-byte IDENTICAL
after excluding a fixed denylist of ubiquitous DOM / render-passthrough prop
names, with the REMAINING significant set holding four or more members. This
is a structural-refactor health signal (extract a shared Props type or a
base component), never a correctness error and never an auto-fix. One finding
is emitted per participating component; sharing_components lists the other
members of the same group. Health signal: the rule defaults to off
(opt-in), so this is dormant until enabled. Exact full-set identity only: a
superset / subset relationship does NOT group (so the finding always fits one
extracted shared type).
Wire-shape envelope for a DuplicatePropShape finding. There is no safe
auto-fix: extracting a shared Props type or a base component for a group of
same-shaped components is a design decision. The actions are manual guidance
(extract the shared shape) plus a line-level suppress at the component
definition and a file-level suppress escape hatch (mirroring the
route-collision multi-file model). The rule defaults to off (opt-in health
signal), so this finding is dormant by default.
One member of a duplicate-prop-shape group: the OTHER components that share
the same significant prop-name set, listed in each member’s
sharing_components. Path-sorted for stable output. A located reference (no
shape, which is carried once on the owning DuplicatePropShape).
Two or more sibling dynamic route segments at the SAME App Router tree
position using different param spellings ([id] vs [slug], or [...x]
vs [[...x]]). Next.js throws “You cannot use different slug names for the
same dynamic path” at dev / production RUNTIME when the position is hit;
next build does NOT catch it, so fallow’s static catch surfaces a route
that would otherwise pass CI and crash at request time. One finding is
emitted per involved file.
Wire-shape envelope for a DynamicSegmentNameConflict finding. The
conflict is a Next.js dev / runtime error (next build does NOT catch it),
so the primary action is manual guidance (rename the dynamic segments to a
single consistent slug name), with a file-level suppress as escape hatch.
Wire-shape envelope for an EmptyCatalogGroup finding. Carries a
remove-empty-catalog-group primary. YAML-sourced findings also include a
YAML-comment suppress action.
A "use client" file that exports a Next.js server-only / route-segment
config name. Next.js rejects this combination at build time; fallow catches
it statically before the build runs.
Wire-shape envelope for an InvalidClientExport finding. There is no safe
auto-fix: the export itself may be a legitimate client-component value
export that happens to collide with a Next.js server-only name, so removing
it could break the component. Actions are a manual move-to-server-module
fix (the real remediation) plus a line-level suppress.
An override entry whose key or value is malformed. Default severity is
error because pnpm refuses to install (or silently produces a no-op
override) when it encounters these shapes.
Wire-shape envelope for a MisconfiguredDependencyOverride finding.
Carries a fix-dependency-override primary plus the conditional
add-to-configignoreDependencyOverrides suppress (skipped when both
target_package and raw_key are empty, since the rule matcher keys on
a non-empty package name).
A "use client" / "use server" directive written as an expression
statement after a non-directive statement (an import, a const). The RSC
bundler only honors a directive in the leading prologue, so once any
statement precedes it the string is parsed as an ordinary expression and
silently ignored: the intended client/server boundary never takes effect.
The fix is to move the directive to the very top of the file.
Wire-shape envelope for a MisplacedDirective finding. There is no safe
auto-fix: moving a directive to the leading prologue is a small but
judgement-bearing edit (the author may have intended the file to be a
server module after all). Actions are a manual hoist-directive fix (the
real remediation) plus a line-level suppress.
A barrel file that re-exports BOTH a "use client" origin module AND a
server-only origin module. Importing one name from such a barrel drags the
other’s directive context across the React Server Components boundary (the
Next.js App Router footgun); fallow catches it statically.
Wire-shape envelope for a MixedClientServerBarrel finding. There is no
safe auto-fix: splitting a barrel into separate client and server modules is
a human decision (the barrel may intentionally aggregate both surfaces).
Actions are a manual split-mixed-barrel fix (the real remediation) plus a
line-level suppress.
A banned call, banned import, banned effect, or banned export matched by a
declarative rule pack (rulePacks config). Banned-call and banned-effect
findings report one entry per unique callee path per file (first occurrence
wins, matching boundary_call_violations); banned-import findings anchor
at each matching import or re-export declaration; banned-export findings
anchor at matching export declarations.
Wire-shape envelope for a PolicyViolation finding. Carries actions for
replacing the banned call, import, or effect, or suppressing it with a scoped
policy-violation:<pack>/<rule-id> token.
Wire-shape envelope for a PrivateTypeLeak finding. Mirrors
UnusedFileFinding: flattens the bare finding and carries a typed
actions array (export-type primary plus suppress-line secondary).
One hop in a prop-drilling chain: a component that received the prop and
passed it along (or, at the chain ends, the source that owns it and the
consumer that substantively reads it).
A located prop-drilling chain: a received prop forwarded unchanged through
>= N intermediate pass-through components, each of which only re-passes it,
until a component that substantively consumes it. The high-confidence signal
is “the received identifier is used ONLY as the root of forwarded child-JSX
attribute values”, not the attribute name matching. Health signal (rule
defaults to off, opt-in): a small capped penalty plus a health --hotspots
surface, and located per-chain records so CI / an agent can act (“colocate or
lift to context at hop B”). Zero-FP doctrine: any spread / cloneElement /
element-as-prop / render-prop / context-provider / dynamic shape in the path
abstains the whole chain.
Wire-shape envelope for a PropDrillingChain finding. There is no safe
auto-fix: collapsing a drilling chain (colocate the consumer, lift to a
context, or compose the component) is a design decision. The only action is a
line-level suppress at the source hop’s prop declaration. The rule defaults
to off (opt-in health signal), so this finding is dormant by default.
Wire-shape envelope for a ReExportCycle finding. Mirrors
CircularDependencyFinding: flattens the bare finding and carries a
typed actions array (refactor-re-export-cycle informational primary
plus suppress-file secondary; cycles are file-scoped so a single
file-level suppression on the alphabetically-first member breaks the
cycle, and no // fallow-ignore-next-line form makes sense because the
diagnostic is anchored at line 1 col 0 of each member).
Per-component render + prop + hook intelligence for one React component.
DESCRIPTIVE ambient editor context surfaced by the LSP (a component summary
code lens plus per-prop hovers), NOT a finding, IssueKind, severity, or
total_issues input. Carried in-process on the #[serde(skip)]AnalysisResults::react_component_intel field (like
RenderFanInMetric); never serialized, so bare fallow / audit and the
JSON / schema surface are untouched.
Per-kind hook counts for a React component, summarized from hook_uses.
DESCRIPTIVE editor context (the LSP code-lens hook breakdown), never a
finding, severity, or total_issues input. custom collects every
use*-named call that is not one of the four built-ins.
A prop-drilling trace for a prop at the ROOT of a forwarding chain.
DESCRIPTIVE ambient editor context (the LSP per-prop hover): the prop is
forwarded unchanged through depth components before a component
substantively consumes it. Reuses the prop-drilling chain machinery’s
abstain ladder (spread / cloneElement / dynamic / provider-in-subtree drop
the whole chain), so the trace is honest. NOT a finding (the opt-in
prop-drilling rule owns the finding); this rides the #[serde(skip)]ReactComponentIntel carrier.
Per-prop usage intelligence for one React component prop. DESCRIPTIVE editor
context (the LSP per-prop hover): whether the prop is read in the component
body and how many render sites pass it. NOT a finding (the
unused-component-prop React arm owns the deadness rule); this is ambient
signal. anchor_line / anchor_col follow the same convention the React
unused-component-prop findings use (1-based line, byte-derived col from
byte_offset_to_line_col).
Two or more Next.js App Router route files that resolve to the SAME URL
within one app-root. Next.js fails the build (“You cannot have two parallel
pages that resolve to the same path”); fallow catches it statically and
names every colliding file at once. One finding is emitted per colliding
file; conflicting_paths lists the sibling files that share the URL.
Wire-shape envelope for a RouteCollision finding. A route collision is a
guaranteed next build failure, so the PRIMARY action is manual guidance
(move or merge one of the colliding files), NOT a suppress: suppressing a
build error never makes the build pass. A file-level suppress is offered as
an escape hatch only.
An agent-actionable candidate record on a SecurityFinding. fallow fills
source_kind, sink, and boundary. The exploitability IMPACT is
deliberately NOT a field: severity on the parent finding is only a
review-priority tier, while deciding exploitability remains the consuming
agent’s job. A perpetually-null impact key would only train consumers to
ignore it. The agent reads this record, then writes its own impact verdict
downstream.
The boundary slot of a SecurityCandidate: which structural boundaries the
candidate’s flow crosses. A flow that crosses a client/server or module
boundary is a stronger review target than a self-contained one; the boundary
is fallow’s structural signal over a pure source-sink match.
The sink slot of a SecurityCandidate: a self-contained description of the
matched sink site. Echoes the finding’s own span (path/line/col) plus
the catalogue category/cwe and the captured callee, so an agent can act
on candidate.sink in isolation (e.g. after fanning a finding out to a
sub-agent) without reading the parent finding.
A local security CANDIDATE for downstream agent verification, NOT a verified
vulnerability. Emitted only by fallow security, never under bare fallow
or the audit gate. There is deliberately no confidence or
signal_strength field: fallow does not prove exploitability, so the trace
(its hops and length) is the only honest signal.
Network-destination context for a secret-to-network candidate (#890): where
the secret-bearing network call sends its data. Present only on
network-category candidates. A consuming agent uses it to triage exfil
(dynamic / untrusted destination) from intended auth (a literal provider
host) without re-reading source.
Graph-derived reachability ranking signal for a security candidate. Computed
from the existing module graph after detection, never proven exploitable.
Used to surface candidates that sit on a request/runtime-reachable surface,
receive same-module source evidence, or are import-reachable from an
untrusted-source module above isolated helpers or scripts.
A source-to-sink taint-flow triple, emitted only when an untrusted source is
import-reachable to the sink (reachability.reachable_from_untrusted_source).
The { source, sink, path } shape matches the model agent SAST tooling
expects (cf. Semgrep taint_source / taint_sink, SARIF threadFlows).
Compact taint-flow path shape. The ordered per-hop trace is NOT duplicated
here: it lives on SecurityReachability::untrusted_source_trace. This
carries only the flow’s structural summary (intra-module flow plus the
cross-module hop count) so consumers do not parse two copies of the hops.
Wire-shape envelope for a TestOnlyDependency finding. Carries a
move-to-dev primary (different prose than TypeOnlyDependencyFinding)
plus the standard ignoreDependencies config suppress.
A located thin-wrapper / passthrough component: a React/Preact component
whose entire body is return <Child {...props}/> (a single spread-forwarded
child render, no host wrapper, no own value-add). It is pure structural
indirection, a CANDIDATE for inlining at call sites or deleting. Health
signal (rule defaults to off, opt-in): never a correctness error. Zero-FP
doctrine: forwardRef / memo / exported / context-provider /
cloneElement / render-prop / named-attr / unresolved-child wrappers all
abstain (each is an intentional indirection or unprovable shape).
Wire-shape envelope for a ThinWrapper finding. There is no safe
auto-fix: inlining a thin wrapper at its call sites (or deleting it) is a
design decision. The only action is a line-level suppress at the wrapper’s
definition. The rule defaults to off (opt-in health signal), so this
finding is dormant by default.
One hop in a security finding’s structural trace. Stored as an absolute path
internally; JSON serialization strips the project root via
serde_path::serialize.
A production dependency that is only used via type-only imports.
In production builds, type imports are erased, so this dependency
is not needed at runtime and could be moved to devDependencies.
Wire-shape envelope for an UnlistedDependency finding. Carries an
install-dependency primary (non-auto-fixable) plus the standard
ignoreDependencies config suppress.
A Vue inject(KEY) or Svelte getContext(KEY) whose symbol KEY is
provide/setContext’d nowhere in the analyzed project. The key is a
symbol with cross-file identity, so an unmatched key is a real dead-half DI
link: at runtime the inject returns undefined, surfaced only at render.
The fix is binary: provide the key somewhere, or remove the dead inject.
Wire-shape envelope for an UnprovidedInject finding. There is no safe
auto-fix: the fix is binary but judgement-bearing (add a provide for the
key, or delete the dead inject). Actions are manual remediation guidance
plus a line-level suppress.
A Vue/Svelte single-file component (the default export of a .vue/.svelte
file) that is reachable in the module graph but rendered NOWHERE in the
project: no <Tag>, no :is/this= binding, no components/app.component
registration, no h()/auto-import use, and no script value-read. It survives
unused-file (a barrel re-export keeps it reachable) and unused-export
(the re-export counts as a use), yet no file actually instantiates it.
Wire-shape envelope for an UnrenderedComponent finding. There is no safe
auto-fix: the fix is binary but judgement-bearing (render the component
somewhere, or delete the dead component). Actions are manual remediation
guidance plus a line-level suppress.
Wire-shape envelope for an UnresolvedCatalogReference finding. The
primary action at position 0 discriminates on available_in_catalogs:
add-catalog-entry when the array is empty (no other catalog declares
the package), or update-catalog-reference when at least one
alternative exists. When exactly one alternative exists, the action
also carries suggested_target so deterministic agents can land the
edit without picking from a list.
Wire-shape envelope for an UnresolvedImport finding. Mirrors
UnusedFileFinding: flattens the bare finding and carries a typed
actions array (resolve-import primary plus config and inline
suppression actions).
Wire-shape envelope for an UnusedCatalogEntry finding. Per-instance
auto_fixable flips to false when hardcoded_consumers is non-empty or
the source is not pnpm-workspace.yaml.
Wire-shape envelope for an UnusedMember finding consumed under the
unused_class_members key. Same Rust struct as
UnusedEnumMemberFinding; the fix action and suppress comment carry
the class-member kebab-case identifier instead.
A Vue <script setup>defineEmits declared event that is EMITTED nowhere
inside its own single-file component (no emit('<name>') call). Single-file
finding, zero-FP doctrine: the whole file abstains on any
unharvestable / dynamic-emit / whole-object-use / defineModel signal.
Wire-shape envelope for an UnusedComponentEmit finding. There is no safe
auto-fix: removing a declared emit is judgement-bearing (the event may be
part of a deliberately-stable public component API). Actions are manual
remediation guidance plus a line-level suppress at the emit declaration.
An Angular @Input() / signal input() / model() declared input that is
read NOWHERE inside its own component (neither the inline/external template
nor the class body). Single-file dead-input direction; the Angular analogue
of UnusedComponentProp. The whole component abstains on an unresolved
extends heritage clause (a base class in another file may read this.foo).
Wire-shape envelope for an UnusedComponentInput finding. There is no safe
auto-fix: removing a declared input is judgement-bearing (the input may be
part of a deliberately-stable public component API). The only action is a
line-level suppress at the input declaration.
An Angular @Output() / signal output() declared output that is EMITTED
nowhere inside its own component (no this.<output>.emit(...)). Single-file
dead-output direction; the Angular analogue of UnusedComponentEmit. A
model() is recorded as an input only, so its framework-driven update:
emit is never flagged here. The whole component abstains on an unresolved
extends heritage clause.
Wire-shape envelope for an UnusedComponentOutput finding. There is no safe
auto-fix: removing a declared output is judgement-bearing (the event may be
part of a deliberately-stable public component API). The only action is a
line-level suppress at the output declaration.
A Vue <script setup>defineProps, Svelte 5 $props(), or React declared
prop that is referenced NOWHERE inside its own component. Single-component
finding, zero-FP doctrine: the component abstains on any opaque public or
fallthrough signal.
Wire-shape envelope for an UnusedComponentProp finding. There is no safe
auto-fix: removing a declared prop is judgement-bearing (the prop may be part
of a deliberately-stable public component API). Actions are manual
remediation guidance plus a line-level suppress at the prop declaration.
Wire-shape envelope for an UnusedDependency finding consumed under
the unused_dependencies key (production deps). Flattens the bare
finding; the typed actions array carries either a remove-dependency
or move-dependency primary depending on
inner.used_in_workspaces.
An entry in pnpm’s overrides: map (or the legacy pnpm.overrides in
package.json) whose target package is not declared in any workspace
package.json and is not present in pnpm-lock.yaml. Projects without a
readable lockfile fall back to package manifest checks; the hint field
flags that conservative mode.
Wire-shape envelope for an UnusedDependencyOverride finding. Carries
a remove-dependency-override primary plus an add-to-configignoreDependencyOverrides suppress scoped to the target package and
declaration source.
Wire-shape envelope for an UnusedDependency finding consumed under
the unused_dev_dependencies key. Same bare struct as
UnusedDependencyFinding; the fix description points at
devDependencies and the suppress comment uses
unused-dev-dependency.
Wire-shape envelope for an UnusedExport finding consumed under the
unused_exports key. Same Rust struct as UnusedTypeFinding, with a
different fix description so consumers can tell value-export from
type-export removal at the action level.
Wire-shape envelope for an UnusedFile finding. The bare finding
flattens in via #[serde(flatten)], with a typed actions array
populated at construction time and the audit-pass introduced flag
attached as an optional sibling.
A SvelteKit +page.{ts,server.ts,js,server.js}load() return-object key
read by no consumer: not off the sibling +page.svelte’s data.<key>, nor
project-wide via page.data.<key> / $page.data.<key>. A dead load key runs
a real server/DB fetch cost on every request for data nothing renders. The
fix is a human call (delete the key, or wire a consumer): a load fetch may
have side effects, so there is no safe auto-fix.
Wire-shape envelope for an UnusedLoadDataKey finding. There is no safe
auto-fix: a load() fetch can have side effects, so deleting the key is a
human call. Actions are manual remediation guidance plus a line-level
suppress.
Wire-shape envelope for an UnusedDependency finding consumed under
the unused_optional_dependencies key. Same bare struct as
UnusedDependencyFinding; the fix description points at
optionalDependencies. Reuses the unused-dependency suppress
IssueKind because there is no dedicated variant for optional deps.
A Next.js Server Action (an export of a "use server" file) that no code in
the analyzed project references: no import-and-call, no action={fn} JSX
binding, no <form action={fn}>. This is the cross-graph “declared but zero
consumers” direction, reclassified out of unused-export for "use server"
files so the finding carries the action-specific signal. It does NOT mean the
endpoint is unreachable: Next still registers the action id, so it stays
POST-able. It means no project code calls it (likely forgotten / dead, and a
candidate for removal to shrink surface area).
Wire-shape envelope for an UnusedServerAction finding. There is no safe
auto-fix: the fix is binary but judgement-bearing (wire the action up to a
consumer, or delete it). Actions are manual remediation guidance plus a
line-level suppress.
Wire-shape envelope for an UnusedMember finding consumed under the
unused_store_members key (a Pinia state / getters / actions key, or
a setup-store returned key, declared but never accessed by any consumer
project-wide). Same Rust struct as UnusedClassMemberFinding. Emits only
a line-level suppress action: there is no safe auto-fix because a store
member can be accessed reflectively (a Pinia plugin, store.$onAction, or
dynamic dispatch) in ways syntactic analysis cannot see, so removal is a
behavioral change the user must own.
A Svelte component dispatching a custom event via createEventDispatcher()
whose event name is listened to NOWHERE in the analyzed project. Cross-file
dead-output direction: the component fires an event nothing handles.
Zero-FP doctrine: the whole component abstains on any dynamic-dispatch or
whole-dispatch-value signal, and a listener on ANY component anywhere
credits the event name (the liberal over-credit direction).
Wire-shape envelope for an UnusedSvelteEvent finding. There is no safe
auto-fix: removing a dispatched event is judgement-bearing (the event may be
part of a deliberately-stable public component API, or a listener may be
added later). Actions are manual remediation guidance plus a line-level
suppress at the dispatch call.
Wire-shape envelope for an UnusedExport finding consumed under the
unused_types key. Wraps the same bare UnusedExport struct as
UnusedExportFinding but emits a fix action targeted at type-only
declarations, with the same is_re_export-aware note swap.
Why a dependency-override entry is misconfigured. pnpm install would
either fail at install time or silently no-op on these entries; surfacing
them statically catches the issue before pnpm does.
Where an override entry was declared. Serialized as the filename label
("pnpm-workspace.yaml" or "package.json") so the value in JSON output
matches the value users write in ignoreDependencyOverrides[].source.
Effective severity of a single PolicyViolation. Per-rule severity
overrides the rules."policy-violation" master; off rules emit nothing,
so only error and warn appear on the wire. The exit-code gate inspects
this per-finding value, not the master severity.
How strongly the untrusted-source signal is associated with the sink, a
structured discriminator so a consumer can tier candidates without parsing
the human evidence prose. Present only when
SecurityReachability::reachable_from_untrusted_source is true. Neither
value proves exploitability; both are ranking signals (issue #885 doctrine:
rank, never gate).