The effort budget counts what a person fills in, not carrier fields
Test / test (push) Successful in 2m38s

A type: record field carries the case an answer is about on the link,
and a hidden preset carries a value; neither is asked. An objection
form that carried the application's id counted one field over.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GT37Z1Xtfd9pUuQtMTg6Yt
This commit is contained in:
Bendik Aagaard Lynghaug
2026-09-30 08:57:03 +02:00
co-authored by Claude Fable 5.1
parent 572dfc200c
commit 41db6093e5
2 changed files with 21 additions and 1 deletions
+4
View File
@@ -3,6 +3,10 @@
One line per change, grouped by the release that shipped it. Newest One line per change, grouped by the release that shipped it. Newest
first. Each release names the portal tag it is built against. first. Each release names the portal tag it is built against.
## Unreleased
- The effort budget counts what a person fills in: a `type: record` field (the case an answer is about, carried on the link) and a `hidden` preset are not asked and no longer count. An objection page whose form carried the application's id used to be one field over.
## 0.5.6 (2026-09-30) - portal v0.5.6 ## 0.5.6 (2026-09-30) - portal v0.5.6
- Matches portal v0.5.6 (released by portal's publish job). - Matches portal v0.5.6 (released by portal's publish job).
+17 -1
View File
@@ -157,11 +157,14 @@ fn visible(q: &Question, as_group: Option<&str>) -> bool {
} }
} }
/// What a person has to fill in: required fields, less the ones that
/// carry rather than ask - a `record` naming the case an answer is
/// about, a `hidden` preset - which cost nobody anything.
fn required_fields(alt: &Alternative) -> usize { fn required_fields(alt: &Alternative) -> usize {
alt.features alt.features
.iter() .iter()
.flat_map(|f| &f.requirements) .flat_map(|f| &f.requirements)
.filter(|r| !r.optional) .filter(|r| !r.optional && r.kind != "record" && r.kind != "hidden")
.count() .count()
} }
@@ -860,6 +863,19 @@ mod tests {
let (questions, aggregates) = site(FULL_DESK); let (questions, aggregates) = site(FULL_DESK);
let findings = check(&needs(" max_fields: 1\n"), &questions, &aggregates); let findings = check(&needs(" max_fields: 1\n"), &questions, &aggregates);
assert_eq!(fails(&findings), vec!["the path asks for 2 required field(s), over the budget of 1"]); assert_eq!(fails(&findings), vec!["the path asks for 2 required field(s), over the budget of 1"]);
// A field that carries rather than asks is not effort: the
// record an answer is about arrives on the link.
let (mut questions, aggregates) = site(FULL_DESK);
let front = questions.get_mut("/").unwrap();
let brief = &mut front.alternatives[0].features[0].requirements;
let mut carrier = brief[0].clone();
carrier.name = "case".into();
carrier.kind = "record".into();
carrier.of = Some("projects".into());
carrier.optional = false;
brief.push(carrier);
let findings = check(&needs(" max_fields: 2\n"), &questions, &aggregates);
assert!(fails(&findings).is_empty(), "{findings:?}");
} }
#[test] #[test]