lower: refuse role fills the frame does not name and referents no role mentions; header states what is and is not rendered (Soul pass on 3d851bf)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Weksa 2026-11-02 18:27:18 +00:00
commit 22eba3a106
2 changed files with 33 additions and 3 deletions

View file

@ -2,9 +2,11 @@
//! fixed table keyed by inventory ids. It renders predications, referents and the
//! speech act, and nothing else: no style, no model, no corpus text. It takes a
//! [`LoweringInput`], so it cannot see the trace or the corpus item. A packet
//! carrying anything it does not render is refused, because rendering part of a
//! meaning would assert a different one (`polarity: negative` dropped says the
//! opposite).
//! carrying a feature, relation, extension, role fill or referent it does not
//! render is refused, because rendering part of a meaning would assert a different
//! one (`polarity: negative` dropped says the opposite). Context, kind and
//! constraints steer delivery and are not rendered; the concept of a predication
//! must resolve but the frame owns the verb.
//!
//! The table is a temporary owner. Each row speaks for an inventory entry and
//! names the gloss it speaks for, so a row cannot outlive a change of what its id
@ -112,6 +114,15 @@ pub fn lower(input: &LoweringInput, inv: &Inventory) -> Result<String, LowerErro
for p in input.predications() {
sentences.push(clause(input, inv, p)?);
}
let mentioned = |r: &NodeId| {
input
.predications()
.iter()
.any(|p| p.roles.iter().any(|f| &f.filler == r))
};
if input.referents().iter().any(|r| !mentioned(&r.id)) {
return unrendered("a referent no role mentions");
}
let mut out = String::new();
for (i, clause) in sentences.iter().enumerate() {
if i > 0 {
@ -164,6 +175,11 @@ fn clause(input: &LoweringInput, inv: &Inventory, p: &Predication) -> Result<Str
said.push(&fill.filler);
}
out.push_str(rest);
if p.roles.len() != said.len() {
return Err(LowerError::Unrendered {
what: "a role the frame does not name",
});
}
Ok(out)
}

View file

@ -113,12 +113,26 @@ fn a_packet_carrying_what_the_lowerer_does_not_render_is_refused() {
})
};
let no_predication = |p: &mut Packet| p.predications.clear();
let extra_role = |p: &mut Packet| {
let filler = p.predications[0].roles[0].filler.clone();
p.predications[0].roles.push(weksa::packet::RoleFill {
role: iv("role:3"),
filler,
})
};
let lone_referent = |p: &mut Packet| {
let mut r = p.referents[0].clone();
r.id = nd("n99");
p.referents.push(r)
};
for (what, edit) in [
("features", &discourse as &dyn Fn(&mut Packet)),
("features", &predication),
("relations", &relation),
("extensions", &extension),
("no predication", &no_predication),
("a role the frame does not name", &extra_role),
("a referent no role mentions", &lone_referent),
] {
let mut p = proof_packet();
edit(&mut p);