From 277f8714d46262a2c0637b0145dca00d2c416e32 Mon Sep 17 00:00:00 2001 From: Brummel Date: Sun, 14 Jun 2026 16:33:00 +0200 Subject: [PATCH] plan: 0040 add derive_signature bounds-guard step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement-time discovery: the new check (and the existing edge/role checks) compute signature() on every interior node before the recursion validates that node's interior. For a structurally-invalid composite (an out-of-range OutField or role target), derive_signature indexed unguarded and PANICKED — exposed by output_port_out_of_range_rejected the moment its covering root role forces c.signature(). Added Task 1 Step 2b: make derive_signature and interior_slot_kind bounds-total (a placeholder kind for an invalid index; the real fault is still reported by validate_wiring's guarded OutputPortOutOfRange / BadInteriorIndex). Fix verified empirically before re-dispatch. Not a design change to the check itself. refs #65 --- docs/plans/0040-wiring-totality-check.md | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/docs/plans/0040-wiring-totality-check.md b/docs/plans/0040-wiring-totality-check.md index ff1a167..edae074 100644 --- a/docs/plans/0040-wiring-totality-check.md +++ b/docs/plans/0040-wiring-totality-check.md @@ -136,6 +136,54 @@ fn check_ports_connected( } ``` +- [ ] **Step 2b: Make `derive_signature` bounds-total (the check exposes a latent panic)** + +`check_ports_connected` (and the existing edge/role checks) compute `signature()` on +every interior node *before* the recursion validates that node's interior. For a +structurally-invalid composite (an out-of-range `OutField` or role target), the +current `derive_signature` indexes unguarded and **panics** instead of letting +`validate_wiring`'s guarded loops report `OutputPortOutOfRange` / `BadInteriorIndex`. +Make the two indexers bounds-total (a placeholder kind for an invalid index; the real +fault is still reported by `validate_wiring`). + +In `crates/aura-engine/src/blueprint.rs`, replace the `output` map in `derive_signature`: + +```rust + let kind = c.nodes()[of.node].signature().output[of.field].kind; +``` + +with: + +```rust + // bounds-total: a structurally-invalid OutField (out-of-range node/field) + // yields a placeholder kind, never a panic — the real fault is reported by + // validate_wiring's guarded output check (OutputPortOutOfRange). signature() + // is computed speculatively by the parent's edge/role/connectivity checks + // before the recursion validates this composite's interior (cycle 0040). + let kind = c + .nodes() + .get(of.node) + .and_then(|n| n.signature().output.get(of.field).map(|f| f.kind)) + .unwrap_or(ScalarKind::F64); +``` + +and replace `interior_slot_kind`'s body: + +```rust + nodes[t.node].signature().inputs[t.slot].kind +``` + +with: + +```rust + // bounds-total: a target into a missing node/slot yields a placeholder kind, never a + // panic — the real fault is reported by validate_wiring's guarded index checks. + nodes + .get(t.node) + .and_then(|n| n.signature().inputs.get(t.slot).map(|p| p.kind)) + .unwrap_or(ScalarKind::F64) +``` + - [ ] **Step 3: Build and confirm exactly the four expected flips** Run: `cargo build -p aura-engine` @@ -226,6 +274,11 @@ with: - [ ] **Step 3: Re-wire `output_port_out_of_range_rejected`** +(This is the test whose deep fault is an out-of-range OUTPUT field. The covering role +forces the root's role-kind loop to compute `c.signature()`, which only stays +panic-free because of the `derive_signature` guard in Task 1 Step 2b; the recursion +then reports `OutputPortOutOfRange` as before.) + Replace: ```rust