Fix static compilation for capabilities using preflight: hydrate_invoke_target - #35
Conversation
ryan-s-roberts
left a comment
There was a problem hiding this comment.
The bug is real: compile-only preflight left HydrateInvokeTarget as a no-op, so mappings that reference {prefix}_{field} (Grafana ds_type, Gmail parent_*, etc.) fail with unknown-variable before live hydration runs. The fixture tests for prefix, typo rejection, and provides not stripping decoded fields are the right coverage. Keep those.
The implementation is much larger than the missing match arm. Requested change: reframe this so the extra concepts disappear.
Do this instead
Extend the existing compile-stub match arm with the existing wire-key heuristic. Motivating mappings are string vars (ds_type). The compile path only needs the env key to exist; unused stub values are not transport values and CML does not type-check them.
PreflightStep::HydrateInvokeTarget { get, prefix } => {
let Some(get_cap) = cgs.get_capability(get) else { continue };
let Some(entity) = cgs.get_entity(get_cap.domain.as_str()) else { continue };
for field_name in entity.fields.keys() {
let key = format!("{prefix}_{field_name}");
env.insert(key.clone(), preflight_wire_key_compile_stub_value(&key));
}
}That keeps apply_preflight_compile_stubs infallible, leaves live hydrate_invoke_target untouched, and deletes compile_stub_value.rs, HydrateInvokeTargetContract, the Result signature change, the extra capability argument on the live hydrator, and the view_stub_rows lock-in comment/test.
If typed stubs are actually required, show a mapping that fails compilation when the stub is "preflight-stub" (date formatter, compound entity-ref descent, etc.). Then delete preflight_wire_key_compile_stub_value and route HydrateEntityRefParam / QueryPick through the same helper. One dialect. Right now there are three (wire-key heuristic, schema-derived typed stubs, view placeholder_value).
Also
- Do not reimplement
validate_capability_preflight/validate_get_on_domainin the runtime for an “unvalidated CGS” defensive boundary. - Do not add a second Create-skip predicate (
capability.kind != Createvs liveis_create). Schema load already rejects this step on Create. - Drop the
apis/grafanacompile test.plasm-runtimetests must not take newapis/dependencies for compile/runtime shape; the new fixture already is Grafana-shaped.
Approval is blocked on the structural cut, not on behavior.
|
💯 |
Live runtime hydration was already implemented, but the
network-freecompile path left thispreflightvariant as a no-op. As a result, valid mappings could fail withunknown-variableerrors before live hydration had a chance to provide the required target fields.Problem
Capabilities can hydrate their invoke target before dispatch:
At runtime, this fetches the target and exposes fields such as:
APIs such as Grafana require this metadata in their request mappings:
The actual value is available during live execution, but static compilation runs first and intentionally performs no network requests. Because
hydrate_invoke_targetdid not declare compile-time placeholders, compilation rejected ds_type before runtime hydration executed.Other preflight variants already modeled their explicit merge fields during compilation.
hydrate_invoke_targetwas the remaining schema-derived case.Changes
Compile-time placeholders are never sent to the remote API:
This is a generic runtime fix required by catalogs that reference hydrated target fields, including Grafana, Discord, Gmail, Google Drive, and Linear. It is independent of semantic discovery and capability
effect classification.