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.

  1. declared: A control event declaration is recorded under legacy.webforms.event-binding.v1 with its evidence site or span.
  2. 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.
  3. 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 use csharp.syntax.callgraph.v1.
  4. 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, and dependency-surface; unsafe names are hashed or omitted.
  5. classification: The projection composes the available evidence into a composed classification from the current static set, while retaining coverage and limitations.
  6. 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 exposes coverage: Full under 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 exposes coverage: 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.

QuestionObserved static evidence
RootDeclared event and linked handler in the same page/type scope.
RelationshipOne Tier3SyntaxOrTextual call-edge candidate from that handler.
TerminalOne Tier2Structural service-reference mapping to a bounded operation surface.
Weakest required hopTier3SyntaxOrTextual, because the call edge is syntax-only.
ClassificationProbableStaticEventFlow under the current direct-terminal conditions; coverage remains Reduced.
Coverage gapSemantic project loading and compiler-resolved call identity are unavailable.
Owner questionCan 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.