feat(0088): §A shared gate predicates — edge_kind_check, resolution helpers, try_bind

Iteration-1 §A of the construction service (#157): the surface-agnostic shared
predicates the eager op-script path and the holistic finalize gates both call —
no second validator (C24).

- edge_kind_check (blueprint.rs): the per-edge producer/consumer kind check,
  lifted verbatim out of validate_wiring's edge loop into a pub(crate) fn that
  validate_wiring now calls — behaviour-preserving (same Bootstrap(KindMismatch)
  variant; the existing compile-time gate test stays green).
- resolve_input_slot / resolve_output_field (builder.rs): the exactly-one-match
  name→index resolution extracted as pub(crate) fns over (&NodeSchema, &str), so
  the runtime-String op-script names share GraphBuilder's resolution; GraphBuilder
  delegates and maps to the unchanged BuildError variants.
- try_bind + BindOpError (aura-core node.rs): the fallible Result twin of bind
  (bind keeps its panic contract and pinned messages verbatim; try_bind is a
  separate method reporting the same three conditions as values).
- check_param_namespace_injective + validate_wiring widened to pub(crate) for the
  finalize-stage reuse by the upcoming GraphSession::finish (§B).

Partial iteration: §B (the GraphSession/Op/replay surface + introspection) and
the §A→§B integration land next (plan Tasks 4-8). compile_with_params /
check_ports_connected are behaviourally unchanged. Full suite green; clippy clean.

Plan correction folded in: Task 3's test originally referenced aura_std::Sma —
infeasible inside aura-core (aura-std depends on aura-core; the reverse edge is a
dependency cycle). Adapted to a local PrimitiveBuilder probe with identical
assertions.

refs #157
This commit is contained in:
2026-06-29 18:38:34 +02:00
parent a5b887a955
commit ea1ca32dbd
5 changed files with 241 additions and 37 deletions
+23 -4
View File
@@ -310,17 +310,30 @@ crates/aura-core/src/node.rs`):
#[test]
fn try_bind_ok_and_typed_errors() {
use super::BindOpError;
use aura_std::Sma; // SMA has one i64 param `length`
// A probe with one i64 param `length` (a real std node like `Sma` would
// pull in aura-std, but aura-core cannot dev-depend on it without a
// dev-cycle that compiles aura-core twice — incompatible `Scalar` types).
let probe = || {
PrimitiveBuilder::new(
"Probe",
NodeSchema {
inputs: vec![],
output: vec![],
params: vec![ParamSpec { name: "length".into(), kind: ScalarKind::I64 }],
},
|_| Box::new(Bare),
)
};
// ok: exact name, matching kind
assert!(Sma::builder().try_bind("length", Scalar::i64(3)).is_ok());
assert!(probe().try_bind("length", Scalar::i64(3)).is_ok());
// unknown param name
assert_eq!(
Sma::builder().try_bind("nope", Scalar::i64(3)).err(),
probe().try_bind("nope", Scalar::i64(3)).err(),
Some(BindOpError::UnknownParam("nope".into()))
);
// kind mismatch (f64 into an i64 param)
assert_eq!(
Sma::builder().try_bind("length", Scalar::f64(3.0)).err(),
probe().try_bind("length", Scalar::f64(3.0)).err(),
Some(BindOpError::KindMismatch {
param: "length".into(),
expected: ScalarKind::I64,
@@ -332,6 +345,12 @@ fn try_bind_ok_and_typed_errors() {
> `.err()` not `.unwrap_err()`: the `Ok` type `PrimitiveBuilder` is not `Debug`
> (it holds a build closure), mirroring `builder.rs`'s tests.
>
> **Plan correction (orchestrator, post-block):** the original Step-1 test
> referenced `aura_std::Sma`, infeasible inside `aura-core` (aura-std depends on
> aura-core; the reverse edge is a dependency cycle). Replaced with a local
> `PrimitiveBuilder::new` probe carrying identical assertions — `Bare` is the
> test module's existing zero-output node.
- [ ] **Step 2: Run test to verify it fails**