← Back to journal

Initialization Order Is Behavior

Moving code can preserve every exported value and still change effects, cycles, registries, scheduling, or top-level-await order.

Evidence basisKodeProof module-graph, effect-order, and initialization-entrypoint verification history
DisclosureStatic verification guidance; dynamic loading and host behavior may require additional runtime evidence.
Published by Kalu KodeApply for KodeProof private alpha →

A refactor can move every function correctly and still break the application before the first function is called.

Module evaluation has order. Top-level code can register plugins, mutate shared state, install handlers, read configuration, schedule callbacks, or trigger host effects. Moving that code changes behavior when the required ordering relationship is lost.

Imports are execution edges

An import is not only a way to access values. In JavaScript modules, it participates in evaluation order.

Consider an entrypoint that imports configuration, then a registry, then a bootstrap module. Extracting the registry initializer into a new owner may alter which effect runs first—even if the entrypoint continues to export the same names.

Sibling import order, dependency paths, and cycles can all matter.

Which events require order

A structural verifier can identify order edges when eager events:

  • write and read the same binding or resource;
  • write the same resource;
  • use one host channel non-commutatively;
  • register or observe the same key;
  • schedule observable callbacks;
  • change exception order;
  • access overlapping or unknown dynamic resources;
  • participate in a cycle, temporal dead zone, or top-level await dependency.

Unknown effects should pin or escalate the move. Assuming commutativity is not proof.

Registry order is especially easy to miss

Plugin systems, route tables, serializers, handlers, and dependency registries often use strings and insertion order as behavior.

A refactor that creates one clean registry module may still change:

  • duplicate-key resolution;
  • provider order;
  • aggregate observation timing;
  • key identity;
  • initialization count;
  • the point at which consumers see the registry.

Registry keys are contract data, not cleanup candidates.

Cycles can turn a move into a runtime failure

Moving a binding may create a new strongly connected component or change which side of a cycle observes an uninitialized export.

The code can typecheck because every name resolves. At runtime it may throw a temporal-dead-zone error or read undefined during module evaluation.

Cycle analysis and top-level-effect comparison catch a class of failures ordinary export snapshots miss.

Public entrypoints can remain pure

A hard-cut refactor may intentionally move initialization into a new module while retaining a stable public entrypoint.

That can be safe when the candidate graph proves an exact static chain from the entrypoint through the moved initializers in the required order. The verifier should derive reachability and effect ownership from source, not trust an ordered list supplied by the caller.

Dynamic or conditional loading, dropped effects, or an unproven chain remains a block.

Runtime evidence complements the graph

Static order proof is strongest for analyzable module edges and known effects. Browser or module-load evidence can test the actual candidate environment, observe duplicate initialization, and exercise routes that trigger lazy boundaries.

Neither layer should erase uncertainty in the other. A successful route visit does not prove all initialization orders. An incomplete graph does not prove a runtime regression.

What a useful finding explains

“Initialization order changed” should include the baseline effectful modules, the edge that established order, the candidate owners, and compact dependency paths showing what moved.

That gives the engineer a repair direction: restore a static edge, centralize ownership, remove a cycle, or add an explicit bootstrap sequence.

KodeProof treats initialization order as part of the change contract because structure is not only where code lives. It is also when authority becomes active.