The opener that says what the business does and the look-around card lead nowhere: they are what the page says before its options, so a task and a simulation step carry them as `page` context and offer only the cards that lead somewhere. Five personas per round had been "choosing" the opener and counted as misroutes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d2450fcb75
commit
00db014eae
+44
-3
@@ -571,7 +571,8 @@ pub fn sim_model(
|
|||||||
json!({
|
json!({
|
||||||
"page": step.page,
|
"page": step.page,
|
||||||
"question": page.name,
|
"question": page.name,
|
||||||
"options": page.alternatives.iter().filter(|a| !a.disabled).map(|a| json!({
|
"context": page_context(page),
|
||||||
|
"options": page.alternatives.iter().filter(|a| !a.disabled && leads_somewhere(a)).map(|a| json!({
|
||||||
"name": a.name,
|
"name": a.name,
|
||||||
"description": plain(&a.description),
|
"description": plain(&a.description),
|
||||||
})).collect::<Vec<_>>(),
|
})).collect::<Vec<_>>(),
|
||||||
@@ -646,6 +647,41 @@ fn plain(text: &str) -> String {
|
|||||||
text.split_whitespace().collect::<Vec<_>>().join(" ")
|
text.split_whitespace().collect::<Vec<_>>().join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A card a visitor can act on: it leads to a page, records an
|
||||||
|
/// answer, or moves a record. A card with none of those is read, not
|
||||||
|
/// picked - the opener that says what the business does, the look
|
||||||
|
/// around - and is context on the page, never an option.
|
||||||
|
pub fn leads_somewhere(a: &Alternative) -> bool {
|
||||||
|
a.action.is_some() || a.record_as.is_some() || a.self_transition.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What the page says before its options: every card that leads
|
||||||
|
/// nowhere, its heading, description and features, as one line each.
|
||||||
|
pub fn page_context(page: &Question) -> String {
|
||||||
|
page.alternatives
|
||||||
|
.iter()
|
||||||
|
.filter(|a| !a.disabled && !leads_somewhere(a))
|
||||||
|
.map(|a| {
|
||||||
|
let mut line = a.name.clone();
|
||||||
|
let description = plain(&a.description);
|
||||||
|
if !description.is_empty() {
|
||||||
|
line.push_str(&format!(": {description}"));
|
||||||
|
}
|
||||||
|
for f in &a.features {
|
||||||
|
let text = plain(&f.description);
|
||||||
|
match (f.name.trim().is_empty(), text.is_empty()) {
|
||||||
|
(true, true) => {}
|
||||||
|
(true, false) => line.push_str(&format!(" {text}")),
|
||||||
|
(false, true) => line.push_str(&format!(" {}.", f.name.trim())),
|
||||||
|
(false, false) => line.push_str(&format!(" {}: {text}", f.name.trim())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
/// Every (persona, page-on-their-path) pair with a real choice on it.
|
/// Every (persona, page-on-their-path) pair with a real choice on it.
|
||||||
/// `skim` shows the engine only each alternative's heading - what a
|
/// `skim` shows the engine only each alternative's heading - what a
|
||||||
/// visitor who never reads the description has to go on.
|
/// visitor who never reads the description has to go on.
|
||||||
@@ -660,10 +696,11 @@ pub fn tasks(file: &NeedsFile, questions: &Questions, skim: bool) -> Vec<Task> {
|
|||||||
};
|
};
|
||||||
for (i, step) in path.iter().enumerate() {
|
for (i, step) in path.iter().enumerate() {
|
||||||
let page = &questions[&step.page];
|
let page = &questions[&step.page];
|
||||||
let open: Vec<&Alternative> = page.alternatives.iter().filter(|a| !a.disabled).collect();
|
let open: Vec<&Alternative> = page.alternatives.iter().filter(|a| !a.disabled && leads_somewhere(a)).collect();
|
||||||
if open.len() < 2 {
|
if open.len() < 2 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let context = page_context(page);
|
||||||
let mut trail: Vec<String> = path[..=i].iter().map(|s| s.page.clone()).collect();
|
let mut trail: Vec<String> = path[..=i].iter().map(|s| s.page.clone()).collect();
|
||||||
let expect: Vec<String> = viable(questions, need, page, need.max_steps - i, i == 0, false, &mut trail)
|
let expect: Vec<String> = viable(questions, need, page, need.max_steps - i, i == 0, false, &mut trail)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -684,7 +721,11 @@ pub fn tasks(file: &NeedsFile, questions: &Questions, skim: bool) -> Vec<Task> {
|
|||||||
persona: persona.id.clone(),
|
persona: persona.id.clone(),
|
||||||
need: need.id.clone(),
|
need: need.id.clone(),
|
||||||
page: step.page.clone(),
|
page: step.page.clone(),
|
||||||
state: BTreeMap::from([("body", plain(&persona.text))]),
|
state: if context.is_empty() {
|
||||||
|
BTreeMap::from([("body", plain(&persona.text))])
|
||||||
|
} else {
|
||||||
|
BTreeMap::from([("body", plain(&persona.text)), ("page", context)])
|
||||||
|
},
|
||||||
questions: BTreeMap::from([(
|
questions: BTreeMap::from([(
|
||||||
"pick",
|
"pick",
|
||||||
ChoiceQuestion {
|
ChoiceQuestion {
|
||||||
|
|||||||
Reference in New Issue
Block a user