From e8f919d956f6834e6a4a0668e8a8605be7fb9757 Mon Sep 17 00:00:00 2001 From: Brummel Date: Fri, 3 Jul 2026 16:58:25 +0200 Subject: [PATCH] fix(research): process_ref describe advertises content-id only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fieldtest finding F2 (cycle-0106 corpus): aura campaign introspect --block std::process_ref rendered the generic dual-form ref label ('one of { content_id } | { identity_id }') while validate_campaign refuses an identity_id process ref — the authoring guide offered a value the validator rejects. The --unwired hint was narrowed in the 0106 audit; this narrows the parallel describe path: std::process_ref's slot moves to a distinct content-only SlotKind::ContentRef whose label names only the content-id form. Strategy refs keep the dual-form label (both ids are valid there) — pinned by the same RED test. RED-first: tests::process_ref_describe_advertises_content_id_only failed on the shared-label tree, passes now; workspace 917/0, clippy clean, doc 0 warnings. refs #189 --- crates/aura-research/src/lib.rs | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/crates/aura-research/src/lib.rs b/crates/aura-research/src/lib.rs index 70bbbf5..1ea8c8e 100644 --- a/crates/aura-research/src/lib.rs +++ b/crates/aura-research/src/lib.rs @@ -123,6 +123,9 @@ pub enum SlotKind { Strings, Windows, Ref, + /// A content-id-only reference (the process ref: `validate_campaign` + /// refuses an identity id there, so the describe path must not offer one). + ContentRef, Axes, EmitKinds, } @@ -684,7 +687,7 @@ pub const CAMPAIGN_SECTIONS: &[BlockSchema] = &[ BlockSchema { id: "std::process_ref", doc: "campaign section: reference to a named process document (content id)", - slots: &[SlotInfo { name: "ref", kind: SlotKind::Ref, required: true }], + slots: &[SlotInfo { name: "ref", kind: SlotKind::ContentRef, required: true }], }, BlockSchema { id: "std::presentation", @@ -708,6 +711,7 @@ pub fn slot_kind_label(kind: SlotKind) -> &'static str { SlotKind::Strings => "list of strings", SlotKind::Windows => "list of { from_ms, to_ms }", SlotKind::Ref => "one of { content_id } | { identity_id }", + SlotKind::ContentRef => "content id of a process document", SlotKind::Axes => "map: param name -> { kind, values }", SlotKind::EmitKinds => "list of: family_table | selection_report", } @@ -1197,6 +1201,41 @@ mod tests { assert!(describe_block("std::nope").is_none()); } + /// A campaign process reference is content-id-only: `validate_campaign` + /// refuses an `identity_id` process ref (`ProcessRefMustBeContentId`), and + /// the block's own doc line says "(content id)". So the `std::process_ref` + /// describe output — the `describe_block` + `slot_kind_label` composition + /// the `--block` CLI verb renders — must not advertise an `identity_id` + /// form the validator would reject. The `--unwired` hint is already + /// narrowed (see `open_slots_campaign`); this pins the parallel describe + /// path to the same content-id-only contract. The narrowing is + /// process-ref-specific: a `std::strategy` ref legitimately accepts either + /// id form and must keep advertising both. + #[test] + fn process_ref_describe_advertises_content_id_only() { + let block = describe_block("std::process_ref").expect("process_ref describable"); + let ref_slot = + block.slots.iter().find(|s| s.name == "ref").expect("process_ref has a ref slot"); + let label = slot_kind_label(ref_slot.kind); + assert!( + !label.contains("identity_id"), + "process_ref advertises an identity_id form the validator refuses: {label}" + ); + assert!( + label.contains("content"), + "process_ref describe must still name the content-id form: {label}" + ); + + let strategy = describe_block("std::strategy").expect("strategy describable"); + let strat_ref = + strategy.slots.iter().find(|s| s.name == "ref").expect("strategy has a ref slot"); + let strat_label = slot_kind_label(strat_ref.kind); + assert!( + strat_label.contains("identity_id") && strat_label.contains("content_id"), + "strategy ref must keep advertising both id forms: {strat_label}" + ); + } + #[test] fn open_slots_report_partial_documents_by_path() { assert_eq!(open_slots_process(PROCESS_FIXTURE).unwrap(), Vec::new());