Public claim level: concept. Static event flow is a bounded evidence chain, not a replay of a web request. It starts with a declared control event, follows the scoped handler identity, connects only to static call or dependency evidence that is already indexed, and ends at a bounded terminal surface when one is present. The composed row can show that checked-in evidence supports a possible code path. It cannot show that a person reaches the screen, that the event fires, or that the path executes in production. This article explains the current implementation's five flow classifications, their evidence tiers, and the owner questions that remain when a hop is missing. Read it with the legacy modernization evidence map and the review handoff matrix.
An event attribute starts a question.
A Web Forms event attribute is a declaration: a checked-in markup surface
records that a control names an event and a handler identifier. Under
legacy.webforms.event-binding.v1, that declaration keeps a
control identity, event name, handler name, file path, line span, rule ID,
and evidence tier. The record is useful even before a handler is resolved:
it gives a reviewer an inventory row, a bounded starting point, and a
concrete question about what evidence should be inspected next. The
inventory context is governed by
legacy.webforms.inventory.v1, which keeps that root tied to a
safe repository-relative surface.
The declaration does not prove that a control exists in the runtime control tree, that a user or role can reach it, that a postback occurs, that event bubbling selects the named handler, or that the handler executes. Static declaration evidence is valuable precisely because it keeps those unknowns visible instead of turning a name into a runtime conclusion. Duplicate bindings remain separate facts, and malformed or dynamic wiring remains a gap or needs-review condition.
The evidence chain is bounded at every hop.
-
declared: A control event declaration is recorded under
legacy.webforms.event-binding.v1with its evidence site or span. -
handler: The declaration is connected only to a scoped
handler-resolution fact under
legacy.webforms.handler-resolution.v1, or remains a candidate or gap when that scope cannot be proven. -
relationship: Existing direct call, object-creation,
service-reference, HTTP, SQL/query, configuration, or dependency facts
may supply static relationship evidence. Semantic call edges use
csharp.semantic.callgraph.v1; syntax-only edges usecsharp.syntax.callgraph.v1. -
terminal: A bounded terminal surface is represented only
when the implementation finds direct handler evidence for it. Safe kinds
include
wcf-operation,sql-query,http-client, anddependency-surface; unsafe names are hashed or omitted. - classification: The projection composes the available evidence into a composed classification from the current static set, while retaining coverage and limitations.
- gap: A missing or reduced hop becomes an owner question, not an invisible join or a runtime claim.
Facts and edges carry their originating rule IDs, evidence tiers, safe file
paths and line spans, commit and extractor provenance, and stable IDs where
available. The projected flow also keeps deterministically ordered
supportingFactIds, supportingEdgeIds,
ruleIds, evidenceTiers, and a
coverage label. See the evidence
explorer for the public evidence contract and the
gap guide for why an unavailable hop stays
explicit.
Handler identity controls the root.
A semantic handler identity is compiler-backed Tier1 evidence under
csharp.semantic.symbolidentity.v1. It is stronger than a
structural match based on page/type identity and a compatible signature,
and stronger than a syntax match based on a linked code-behind filename and
method name. The page directive, markup file, linked code-behind scope,
partial type, method span, and binding fact all matter. The same method name
in another page or file is not an equivalent event root.
legacy.webforms.handler-resolution.v1 keeps ambiguity fail
closed: multiple methods or partial-class candidates become an explicit
gap rather than an arbitrary winner. Designer fields under
legacy.webforms.designer-control.v1 can support control
identity, but they are generated or stale-prone syntax evidence and do not
create a handler or backend flow by themselves. A path with the wrong root
can look complete while every downstream relationship belongs to another
page, so root identity is part of the evidence, not a display detail.
The weakest required hop caps the path.
The four evidence tiers describe what a hop can support:
- Tier1Semantic: compiler-resolved symbol or call-edge evidence when the project loads with the required references.
- Tier2Structural: a known page/type, signature, config, service-reference, or framework shape without a compiler-resolved symbol.
- Tier3SyntaxOrTextual: syntax-only declarations, filename-and-name matches, or syntax call edges whose receiver and overload are not proven.
- Tier4Unknown: an explicit analysis gap when the needed linkage or evidence cannot be established.
The flow fact records the weakest tier across its supporting facts and the
handler resolution. One semantic hop does not upgrade a syntax-only call,
a missing generated artifact, or an unproven dependency target. Missing
project loading, generated code, dynamic dispatch, reflection, delegates,
event bubbling, unsupported wiring, or multi-hop traversal remain
limitations that can sit under coverage: Full when
BuildStatus == Succeeded; a failed or partial build carries
coverage: Reduced. The current MVP prefers direct
handler-to-evidence facts and does not infer branch feasibility, runtime
dependency selection, or mutation.
What the current classifications mean.
These names are deterministic projections, not confidence percentages. The current implementation first gathers direct handler-linked facts and bounded terminal facts. Its terminal set includes WCF service-reference mappings, SQL/query facts, HTTP calls, dependency facts, and config bindings. It can also attach a WCF mapping when a direct call edge names the mapped client symbol.
- StrongStaticEventFlow: at least one terminal exists, the handler resolution is Tier1Semantic, and at least one terminal fact is Tier1Semantic. This is the strongest current static composition; it is still not proof of event firing or execution.
- ProbableStaticEventFlow: a terminal exists, but the Strong conditions do not hold and the handler resolution is not Tier3SyntaxOrTextual. A Tier2 handler, or a Tier1 handler with a weaker terminal hop, can land here. “Probable” names the evidence composition; it is not a probability of runtime behavior.
- NeedsReviewEventFlow: a terminal exists and the handler resolution is Tier3SyntaxOrTextual. The direct static relationship is useful review evidence, but the handler identity is syntax-level.
-
NoBackendEvidence: no bounded terminal is found while
the scan manifest reports
BuildStatus == Succeeded; the flow exposescoverage: Fullunder that implementation gate. This means no indexed terminal was found under the selected scan, not that the application has no backend behavior or that all applicable framework behavior was analyzed. -
UnknownAnalysisGap: no bounded terminal is found while
the manifest build status is not
Succeeded; the flow exposescoverage: Reduced. The missing or reduced evidence prevents a credible absence conclusion. If a terminal is present despite reduced coverage, the current implementation may retain a static-flow classification while recording the reduced coverage and limitations; a reduced label is never silently converted to full proof.
This direct-projection behavior is documented by
legacy.webforms.event-flow.v1. The rule limitations remain
attached: call edges are static sites, service reachability is not tested,
SQL is not executed, and event lifecycle or dynamic dispatch is not
reconstructed.
A bounded synthetic example.
Consider two generic Web Forms files in a synthetic application. The first
records a button event declaration and one handler in the linked page
scope. A syntax-only call edge candidate points from that handler to one
service-client call, and a structural service-reference fact supplies one
bounded wcf-operation terminal surface. The project does not
load semantically, so the call edge and terminal mapping are not
compiler-resolved.
| Question | Observed static evidence |
|---|---|
| Root | Declared event and linked handler in the same page/type scope. |
| Relationship | One Tier3SyntaxOrTextual call-edge candidate from that handler. |
| Terminal | One Tier2Structural service-reference mapping to a bounded operation surface. |
| Weakest required hop | Tier3SyntaxOrTextual, because the call edge is syntax-only. |
| Classification | ProbableStaticEventFlow under the current direct-terminal conditions; coverage remains Reduced. |
| Coverage gap | Semantic project loading and compiler-resolved call identity are unavailable. |
| Owner question | Can the project/reference setup be restored so the service call and its runtime dependency selection can be reviewed? |
The result is a reviewable possible path, not a claim that a user reaches
the page, that the handler fires, that the service responds, or that data
changes. If the same synthetic handler had no bounded terminal and the
manifest build status were not succeeded, the current implementation would
emit UnknownAnalysisGap; under a succeeded build it would emit
NoBackendEvidence. Those outcomes are coverage-relative and
should lead to different owner questions.
What static event flow is good for.
- scoping a review around a declared event and its evidence-backed downstream surfaces;
- building a modernization inventory of code areas that deserve human inspection;
- identifying static relationships and missing evidence to discuss with an owner;
- turning bounded paths into test-planning questions, such as where a runtime check would distinguish a candidate call from an executed one;
- locating reduced coverage before a team treats a no-evidence row as absence; and
- prioritizing where runtime validation may be useful without selecting tests or declaring impact automatically.
Use the review handoff matrix to assign the next question, and the article on successful builds with reduced coverage to keep build state separate from feature coverage. The earlier Web Forms inventory guide covers the broader static evidence lane; the button identity article explains why the event root must stay scoped.
What static event flow does not prove.
A static path or classification does not prove any of the following:
- screen visibility;
- user or role reachability;
- event firing;
- page lifecycle order;
- event bubbling outcome;
- branch feasibility;
- runtime dependency selection;
- service availability or response;
- SQL execution;
- database state or mutation;
- deployment;
- production usage;
- migration correctness or parity;
- business intent; or
- release approval.
The article is synthetic and public-safe. It contains no private repository, endpoint address, credential, credential-bearing configuration, executable source or markup, source snippet, or production observation. TraceMap's event-flow model remains deterministic static evidence with rule IDs, tiers, spans, commit provenance, coverage labels, and documented limitations; it is not an LLM, embedding, vector-database, or prompt-based impact-analysis claim. For the product-wide boundary, read static versus runtime.