Observation and reuse

After establishing an interface, the obvious performance question is how much of that work we can reuse. Repeating an unchanged negotiation before every small operation would be expensive, but caching every answer is no better if the answer was only valid for one observation.

The distinction becomes easier to see in the image lab. The callable used to compose two images may remain valid for the provider's lifetime. The composed image itself is useful only while the inputs still justify it. Those are two different things to retain, with two different reasons to retain them.

Following a change through the scene

Move the overlay in the lab and the composed output needs to change. The upstream filter has the same input it had before, so recomputing it would do unnecessary work. Change the source image instead and that filter must be observed again.

The image graph owns those relationships. Its revisions and input dependencies provide the reason an observation can be reused, and the rendered check verifies that an overlay edit leaves the upstream filter intact. Semantic Flow doesn't need to understand what an overlay is to transfer the resulting pixels.

The native mixed-provider check also counts the transfers and plan builds. Changing its CPU overlay requires one upload while leaving the CUDA background and FFT plan in place. The test reads the completed image back only afterward, when it needs pixels to check correctness. The lab walkthrough follows those two requests separately.

Reusing facts with a known lifetime

There are smaller opportunities for reuse in the lower layers. A prepared Representation is immutable while borrowed, so two references to the same record can take an identity fast path. Independently published descriptions still agree through their canonical bytes.

A Cursor has a similarly local guarantee. Its token provider offers stable observations by logical index, while the wrapper owns its position. Caching the token at that position saves repeated calls without introducing shared mutable progress. Moving the Cursor invalidates the local observation; copying it forks the position.

Neither example gives us permission to cache arbitrary Abstract answers. For those, we need whatever stability promise the owner actually supplies. An optimization becomes easier to reason about when we can point to the fact that makes reuse valid and the event that ends it.

When the work takes time

A provider may need to cross a process boundary or wait for another system, but Pending and Unknown don't tell us how to schedule that work. They describe an outcome, not a future with an implicit completion mechanism.

The base operations are synchronous. A higher-level contract can add callbacks, polling or cancellation, and a host can adapt the call into its own async runtime. Doing that explicitly lets each application choose the ownership and scheduling cost it is willing to pay.

It also keeps performance observations interpretable. A warm interface call, result allocation, a GPU kernel and a pixel readback measure different parts of the request. The Godot tests try to keep those distinctions visible, so an improvement in one part doesn't hide extra work in another.