Pangram verdict · v3.3
We believe this text is mainly AI, with some human-written content.
AI likelihood · overall
AIArticle text · 1,449 words · 1 segments analyzed
AI can generate components faster than humans can understand their combined execution. Graphs make the application structure visible. A compiler can turn that structure into a deterministic orchestrator. AI coding has created a strange inversion: writing code is becoming cheap, while understanding what all that code will do together is becoming expensive. An LLM can add a handler, connect an API, introduce a queue, implement a retry, update some state and call another service in minutes. Each change can look perfectly reasonable when read on its own. The problem appears when those reasonable pieces interact. The real behaviour of an application is rarely contained in one method. It emerges from the order in which callbacks, listeners, timers, queues, retries, lifecycle hooks and state changes combine. An LLM can now generate this orchestration faster than a human can reconstruct the execution model it is creating. This is one reason graph engineering is attracting attention. LangChain recently used the term to describe constructing agentic systems as graphs containing deterministic code, model calls, tools and complete agents. The graph constrains the paths the system may follow instead of leaving every decision to an LLM. That is an important improvement — but making the graph visible is only half the solution. The other half is deciding exactly how the graph executes. AI writes locally. Systems execute globally. LLMs are often very good at implementing local behaviour. Suppose an application receives a trade and must: Update position ↓ Recalculate risk ↓ Publish the result An LLM might generate: updatePosition(trade); publishPosition(); recalculateRisk(); Every method call is valid, the code is readable, and the implementation may compile and pass many tests. But the global ordering is wrong. Nothing in those method signatures tells the compiler that risk must be recalculated before the position is published. That requirement exists somewhere outside the code: in an architecture document, in a test, in a comment, or in the mind of an experienced developer. The dangerous AI-generated code is not usually obvious nonsense. It is locally plausible code that subtly violates a global invariant. The problem compounds over time. One prompt introduces retries. Another moves work onto an executor. A third adds metrics. A fourth supports another event type. Each change may be reasonable in isolation while changing:
execution order; state visibility; reentrancy; failure handling; completion semantics; replay behaviour.
The application gradually develops an execution model that no person—and no single prompt—ever explicitly designed. The loop is not the villain A small loop can be perfectly deterministic: while (running) { Event event = queue.take();
updateState(event); calculateRisk(); publishResult(); } Given the same initial state and the same ordered inputs, this loop can produce the same result every time. The problem is not that loops are inherently unpredictable. The problem is that real applications rarely remain one loop. Over time, updateState publishes another event. A listener receives it. A timer refreshes reference data. A retry schedules more work. A framework invokes a lifecycle method. A callback observes some state before another callback has finished updating it. The original loop has not disappeared. It has become distributed throughout the application: Event loop ├── listener │ └── callback │ └── queue ├── scheduled task ├── retry handler └── asynchronous publisher Someone still has to understand the complete sequence. In a conventional project, that person is often a senior developer who has accumulated an unwritten model of the system over several years. In an AI-generated project, we risk asking an LLM to become that global coordination engineer. That is a poor division of responsibility. Graph engineering makes the application model visible A graph replaces implicit control flow with explicit relationships: Trade ↓ Position ↓ Risk ↓ Policy ↓ Route The graph says that risk depends on the updated position, policy depends on risk, and routing depends on the policy decision. That is easier to inspect than equivalent behaviour spread across queues, callbacks and listeners. It is also a natural model for systems that combine ordinary code with probabilistic components: Request ↓ Classification agent ↓ Policy validation ↓ Human approval ↓ Approved action The classification agent may remain probabilistic. The surrounding graph constrains where the model can operate and what must happen before an external action is permitted. Current agent graph frameworks generally make this graph explicit: nodes perform work, while edges or routing definitions determine what happens next. Microsoft’s Agent Framework, for example, describes workflows as directed graphs of executors and edges; LangGraph similarly uses nodes, state and transitions to define an agent workflow. This is much better than hiding the workflow inside a large agent loop, but it still leaves an important problem: someone must author the orchestration. The graph is not the orchestrator Consider a simple diamond: A / \ B C \ / D The topology tells us that B and C depend on A, and D depends on B and C. The diagram alone does not necessarily answer:
Does B run before C? May B and C run concurrently? When do their state changes become visible? Should D run if B produced no change? What happens if C emits another event? Is that event handled immediately or queued? What happens when B fails? When does end-of-cycle cleanup occur? Can D observe a partially completed update?
Workflow runtimes answer these questions through their execution semantics and the graph definition supplied by the author. That is entirely appropriate when routes must remain dynamic. But it means the global coordination plan is still authored software. In applications whose components already express structural dependencies, an explicit workflow can also duplicate relationships that exist elsewhere in the program. Even when there is no literal duplication, someone still has to construct and maintain the global routing and lifecycle plan. Fluxtion asks a narrower question:
When the component graph is closed and its local event semantics are known, how much of the global coordinator can a compiler derive?
Inferred orchestration This is the approach I have been exploring through Fluxtion. I did not arrive at this problem through agent frameworks. Fluxtion grew out of electronic-trading systems, where event order, latency, replay and the ability to reconstruct a decision were production requirements. The recent rise of AI-generated software has made the same coordination problem much more general. Fluxtion treats orchestration as a compiler problem. None of the ingredients is unprecedented. Jane Street’s Incremental maintains a dependency graph and recomputes the affected portion when inputs change; its graph may also change at runtime. Dagger uses compile-time graph analysis to generate Java that constructs and wires dependencies, while Dagger Producers extends that approach to dependent asynchronous computations. Fluxtion applies related ideas to a different layer: repeated event coordination across a closed graph of stateful business components, including event-specific dispatch, change and trigger propagation, lifecycle, reentrancy, audit and replay, specialised into a standalone Java processor. Developers write ordinary Java components containing local state and behaviour. References between those components form an object graph. Annotations and interfaces declare event-handling and lifecycle semantics. Depending on the authoring style, the topology may be expressed through Java object references, a fluent DSL or Spring wiring — the important point is not that every graph originates identically; it is that the author declares the structure once rather than separately implementing its runtime coordinator. Once the complete graph is known, the compiler analyses it and derives the orchestration. Java components + dependencies + event semantics ↓ Closed object graph ↓ Execution inference ↓ Compiled orchestrator ↓ Generated Java Fluxtion calls the compiler technique execution inference. The programming model it enables is inferred orchestration: developers define components, dependencies and local event semantics, while the compiler derives and emits the global dispatcher. Execution inference does not guess the developer’s intentions from method names or comments. It derives the consequences of explicit structure that already exists: object references, event handlers, trigger methods, lifecycle callbacks, sinks and exported services. From that structure, Fluxtion derives:
which components are affected by each event; their valid topological execution order; when changes should propagate; when trigger methods become eligible; lifecycle and cleanup ordering; audit-hook placement; queued reentrant event handling.
“Inferred” does not mean that the compiler guesses intent or that developers declare nothing. A component still states its local role: that it handles a particular event, triggers after an upstream change, participates in lifecycle processing or exports a service. What the developer does not write is the global coordination program — the complete route, execution order, change-propagation plan, lifecycle sequence and reentrancy behaviour. Execution inference derives that global program from the closed graph and its local declarations. It then generates the runtime dispatcher as ordinary Java source. The orchestration is compiled rather than separately authored. A small example Imagine three stateful components: final class Position {