fix(aura-research): process.ref hint states the tagged { content_id } shape
campaign introspect (--block std::process_ref and --unwired) described
the slot as "content id of a process document" — a plausible bare-string
reading the validator rejects; the required {"content_id":"..."} tagging
appeared in no introspection output (binary-only M1 fieldtest finding).
The SlotKind::ContentRef label and the open-slot hint now lead with the
tagged { content_id } shape. Deliberately narrower than the issue's
suggestion of mirroring std::strategy's { content_id } | { identity_id }
form: validate_campaign refuses an identity_id process ref
(DocFault::ProcessRefMustBeContentId) and a pinned test forbids
advertising it, so the hint states the one accepted key only (C29
honesty; correction minuted on the issue). RED-first: the extended
process_ref_describe_advertises_content_id_only assertion failed against
the old label before the fix.
closes #329
This commit is contained in:
@@ -996,7 +996,7 @@ fn campaign_introspect_unwired_reports_the_spec_example_slots() {
|
|||||||
write_doc(&dir, "draft.campaign.json", draft);
|
write_doc(&dir, "draft.campaign.json", draft);
|
||||||
let (out, code) = run_code_in(&dir, &["campaign", "introspect", "--unwired", "draft.campaign.json"]);
|
let (out, code) = run_code_in(&dir, &["campaign", "introspect", "--unwired", "draft.campaign.json"]);
|
||||||
assert_eq!(code, Some(0));
|
assert_eq!(code, Some(0));
|
||||||
assert!(out.contains("open slot: process.ref (required, content id of a process document)"));
|
assert!(out.contains("open slot: process.ref (required, { content_id }: content id of a process document)"));
|
||||||
assert!(out.contains("open slot: strategies[0].axes.slow (axis declared empty — a P1 axis is a non-empty finite set)"));
|
assert!(out.contains("open slot: strategies[0].axes.slow (axis declared empty — a P1 axis is a non-empty finite set)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1022,7 +1022,7 @@ fn campaign_introspect_unwired_reports_placeholder_refs() {
|
|||||||
"strategy `ref: null` placeholder not enumerated: {out}"
|
"strategy `ref: null` placeholder not enumerated: {out}"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
out.contains("open slot: process.ref (required, content id of a process document)"),
|
out.contains("open slot: process.ref (required, { content_id }: content id of a process document)"),
|
||||||
"process `ref: {{}}` placeholder not enumerated: {out}"
|
"process `ref: {{}}` placeholder not enumerated: {out}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1102,7 +1102,7 @@ pub fn slot_kind_label(kind: SlotKind) -> &'static str {
|
|||||||
SlotKind::Strings => "list of strings",
|
SlotKind::Strings => "list of strings",
|
||||||
SlotKind::Windows => "list of { from_ms, to_ms }",
|
SlotKind::Windows => "list of { from_ms, to_ms }",
|
||||||
SlotKind::Ref => "one of { content_id } | { identity_id }",
|
SlotKind::Ref => "one of { content_id } | { identity_id }",
|
||||||
SlotKind::ContentRef => "content id of a process document",
|
SlotKind::ContentRef => "{ content_id }: content id of a process document",
|
||||||
SlotKind::Axes => "map: param name -> { kind, values }",
|
SlotKind::Axes => "map: param name -> { kind, values }",
|
||||||
SlotKind::EmitKinds => "list of: family_table | selection_report",
|
SlotKind::EmitKinds => "list of: family_table | selection_report",
|
||||||
SlotKind::TapKinds => "list of: equity | exposure | r_equity | net_r_equity",
|
SlotKind::TapKinds => "list of: equity | exposure | r_equity | net_r_equity",
|
||||||
@@ -1301,8 +1301,10 @@ pub fn open_slots_campaign(text: &str) -> Result<Vec<OpenSlot>, DocError> {
|
|||||||
}
|
}
|
||||||
if ref_slot_is_open(v.get("process").and_then(|p| p.get("ref"))) {
|
if ref_slot_is_open(v.get("process").and_then(|p| p.get("ref"))) {
|
||||||
// deliberately narrower than the strategy-ref hint: validate_campaign
|
// deliberately narrower than the strategy-ref hint: validate_campaign
|
||||||
// refuses an identity_id process ref, so the guide must not offer it
|
// refuses an identity_id process ref, so the guide must not offer it.
|
||||||
slots.push(open("process.ref", "required, content id of a process document"));
|
// The tagged { content_id } shape is stated explicitly (#329) so the
|
||||||
|
// hint cannot be misread as accepting a bare id string.
|
||||||
|
slots.push(open("process.ref", "required, { content_id }: content id of a process document"));
|
||||||
}
|
}
|
||||||
if v.get("seed").and_then(|s| s.as_u64()).is_none() {
|
if v.get("seed").and_then(|s| s.as_u64()).is_none() {
|
||||||
slots.push(open("seed", "required, non-negative integer"));
|
slots.push(open("seed", "required, non-negative integer"));
|
||||||
@@ -2374,6 +2376,14 @@ mod tests {
|
|||||||
label.contains("content"),
|
label.contains("content"),
|
||||||
"process_ref describe must still name the content-id form: {label}"
|
"process_ref describe must still name the content-id form: {label}"
|
||||||
);
|
);
|
||||||
|
// #329: the label must state the TAGGED shape ({ content_id: ... }) the
|
||||||
|
// parser actually requires, not read like a bare id string — mirroring
|
||||||
|
// the `{ content_id } | { identity_id }` bracket notation std::strategy
|
||||||
|
// already uses, narrowed to the one key process.ref accepts.
|
||||||
|
assert!(
|
||||||
|
label.contains("{ content_id }"),
|
||||||
|
"process_ref describe must state the tagged {{ content_id }} shape, not a bare id: {label}"
|
||||||
|
);
|
||||||
|
|
||||||
let strategy = describe_block("std::strategy").expect("strategy describable");
|
let strategy = describe_block("std::strategy").expect("strategy describable");
|
||||||
let strat_ref =
|
let strat_ref =
|
||||||
@@ -2430,7 +2440,7 @@ mod tests {
|
|||||||
"presentation": { "persist_taps": [], "emit": [] } }"#;
|
"presentation": { "persist_taps": [], "emit": [] } }"#;
|
||||||
let slots = open_slots_campaign(draft).unwrap();
|
let slots = open_slots_campaign(draft).unwrap();
|
||||||
assert!(slots.iter().any(|s| s.path == "process.ref"
|
assert!(slots.iter().any(|s| s.path == "process.ref"
|
||||||
&& s.hint == "required, content id of a process document"));
|
&& s.hint == "required, { content_id }: content id of a process document"));
|
||||||
assert!(slots.iter().any(|s| s.path == "strategies[0].axes.slow"
|
assert!(slots.iter().any(|s| s.path == "strategies[0].axes.slow"
|
||||||
&& s.hint == "axis declared empty — a P1 axis is a non-empty finite set"));
|
&& s.hint == "axis declared empty — a P1 axis is a non-empty finite set"));
|
||||||
|
|
||||||
@@ -2466,7 +2476,7 @@ mod tests {
|
|||||||
// ...and the `{}` process ref reports the narrower content-id-only hint.
|
// ...and the `{}` process ref reports the narrower content-id-only hint.
|
||||||
assert!(
|
assert!(
|
||||||
slots.iter().any(|s| s.path == "process.ref"
|
slots.iter().any(|s| s.path == "process.ref"
|
||||||
&& s.hint == "required, content id of a process document"),
|
&& s.hint == "required, { content_id }: content id of a process document"),
|
||||||
"process `ref: {{}}` placeholder not reported as an open slot: {slots:?}"
|
"process `ref: {{}}` placeholder not reported as an open slot: {slots:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user