Schema: a problem carries its field and a structured kind, phrased by label or by key

schema::Problem now holds the &'static Field it is about and a ProblemKind
(Required, NotANumber, Below, Above, NotAChoice, UnknownVariant, ...).
Problem::for_form phrases it by the field's label, Problem::for_agents by
its JSON path, from the same data. The form no longer rewrites problem
text by string matching or re-walks the field tree; field_at moves to
schema.rs for the engine's own Param errors. The forms test matches
EngineError::Param { key, .. } directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-14 21:09:22 -04:00
1 parent 904dc3381b
commit bdd84a491d
4 files changed
+219 -109

No files matched your search

+11 -6
View File
@@ -1045,12 +1045,17 @@ mod tests {
if fill_refs {
fill_required(&s, form, &mut p);
}
let missing: Vec<String> = problems(form, &p).into_iter().filter(|p| p.message == "required").map(|p| p.path).collect();
let r = s.execute(c.id, &p).map_err(|e| match e {
EngineError::Param { .. } => EngineError::Params(e.to_string()),
e => e,
});
match r {
let missing: Vec<String> = problems(form, &p).into_iter().filter(|p| p.kind == ProblemKind::Required).map(|p| p.path).collect();
// The engine names a missing nested field by its path, its own key, or the group
// that holds it.
let is_missing = |key: &str| {
missing.iter().any(|m| m == key || m.rsplit('/').next() == Some(key) || m.strip_prefix(key).is_some_and(|r| r.starts_with('/')))
};
match s.execute(c.id, &p) {
Err(EngineError::Param { key, .. }) if is_missing(&key) => {}
Err(EngineError::Param { key, problem }) => {
failures.push(format!("{}: {p} refused for `{key}` {problem}, but only {missing:?} were missing", c.id));
}
// State, not parameters: the meshers' default is the open design's bodies, the
// bar has no explicit step; activation and probes need one of several fields.
Err(EngineError::Params(e)) if STATE.iter().any(|m| e.contains(m)) => {}