Policy and uncertainty

As soon as several implementations can answer the same question, we also need to let them disagree about what they can provide. An image provider might not implement convolution. Another might implement it but refuse a particular kernel size. A source declaration might eventually supply the requested capability, but still depend on something we haven't resolved.

Returning a null pointer for all three would make the caller guess what happened. Worse, it would encourage the caller to keep looking underneath the provider until it found something that appeared to work. That is a fairly effective way to erase the policy we were asking in the first place.

Letting the answer carry its meaning

Semantic negotiation distinguishes Satisfied, Unsupported, Pending and Rejected. Unsupported lets an operation consider an alternative where its contract permits one. Pending says the answer isn't settled, while Rejected preserves a refusal. The caller receives the outcome from the provider it encountered and decides what its own operation allows it to do next.

There is a separate vocabulary when the answer itself is an Abstract. None means absence has been established. Unknown means the conceptual answer is still unsettled. Constant supplies an explicit invariance promise. A query can succeed and return None, just as it can succeed and tell us that the answer remains Unknown. Neither case is a failed attempt to obtain an interface.

These distinctions matter in ordinary code. Imagine a declaration whose type depends on another declaration being evaluated. Treating Unknown as absence would allow a consumer to make a permanent decision from incomplete evidence. Treating every absent answer as Unknown would leave it waiting for information that the owner already knows will never arrive.

Asking through a policy

An Alias is transparent forwarding. A policy is allowed to change what can be observed, which means the consumer has to keep asking through the policy it was given.

In the Godot example, a script provider can offer convolution and still limit the amount of synchronous work it accepts. A smaller kernel may succeed while a larger one is refused. The underlying operation's existence doesn't authorize us to reach around that limit, even if another native interface happens to be reachable from the same object.

This is why discovery, binding and admission remain distinct. Discovering an operation tells us something useful about the provider. Binding establishes an interface we can call. Admission can then apply the domain rules for the specific request. Collapsing those questions would either weaken the policy or force every provider to promise more than it can reasonably deliver.

Knowing when an answer can be reused

Successful binding is useful for repeated calls, but it doesn't make all the answers from those calls constant. We still need a reason to believe an observation remains valid.

The Source Cursor has a deliberately narrow version of that promise. Its provider supplies stable tokens at absolute logical indices, and each Cursor owns its position. A C++ wrapper can cache the token at that position and discard the cache when it moves. Copying the Cursor forks that local position without turning the provider into another mutable traversal state.

An image result needs a different justification, such as unchanged inputs and revisions. An arbitrary conceptual query may need the owner's Constant promise. The useful rule is to find the actual owner of stability rather than introduce a cache merely because repeating the question seems expensive.

Unknown and Pending also leave scheduling open. They don't tell a caller how to await a result. The base operations are synchronous; a system that needs a callback or future has to establish that additional contract. That lets an editor, a script runtime and a native client keep their own ways of arranging work.

The concrete interfaces are in Abstract and its answer contracts.