Merge origin/main (2308b91) into weksa/dao-de-jing-test-bed

Main's proof revision owns concept:6 and frame:3; Dao ids renumbered to
start at concept:7 and frame:4 (daodejing.rs, lower.rs rows).
data/daodejing inventory.cc and packets.cc regenerated with weksa inventory
seed/proof/dao and weksa packet dao.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Weksa 2026-11-09 10:16:22 +00:00
commit 8a78761a7a
9 changed files with 258 additions and 43 deletions

View file

@ -42,8 +42,8 @@ const CONCEPTS: &[&str] = &[
"resemble",
];
/// Frame glosses, from `frame:3`. 3 is minted from a Train chapter, 4 and 5
/// from Validation chapters, 6 and 7 from Test chapters.
/// Frame glosses, from `frame:4`. 4 is minted from a Train chapter, 5 and 6
/// from Validation chapters, 7 and 8 from Test chapters.
const FRAMES: &[&str] = &[
"act",
"intransitive",
@ -56,7 +56,7 @@ const FRAMES: &[&str] = &[
pub fn revision() -> (InventoryRevision, Vec<InventoryEntry>) {
let mut entries = Vec::new();
for (family, glosses) in [(Family::Concept, CONCEPTS), (Family::Frame, FRAMES)] {
let first = if family == Family::Concept { 6 } else { 3 };
let first = if family == Family::Concept { 7 } else { 4 };
for (i, gloss) in glosses.iter().enumerate() {
entries.push(InventoryEntry {
id: family.id(NonZeroU32::new(first + i as u32).expect("nonzero")),
@ -85,7 +85,7 @@ fn concept(gloss: &str) -> &'static str {
.iter()
.position(|c| *c == gloss)
.expect("known concept");
Box::leak(format!("concept:{}", 6 + at).into_boxed_str())
Box::leak(format!("concept:{}", 7 + at).into_boxed_str())
}
fn frame(gloss: &str) -> &'static str {
@ -93,7 +93,7 @@ fn frame(gloss: &str) -> &'static str {
.iter()
.position(|c| *c == gloss)
.expect("known frame");
Box::leak(format!("frame:{}", 3 + at).into_boxed_str())
Box::leak(format!("frame:{}", 4 + at).into_boxed_str())
}
fn hex8(ascii: &str) -> String {

View file

@ -485,9 +485,20 @@ pub fn proof_revision() -> (InventoryRevision, Vec<InventoryEntry>) {
for (family, glosses) in [
(
Family::Concept,
["endanger", "prevent", "player", "control", "ship_mind"].as_slice(),
[
"endanger",
"prevent",
"player",
"control",
"ship_mind",
"request",
]
.as_slice(),
),
(
Family::Frame,
["hazard_warning", "intervention", "request_intervention"].as_slice(),
),
(Family::Frame, ["hazard_warning", "intervention"].as_slice()),
] {
for (i, gloss) in glosses.iter().enumerate() {
entries.push(InventoryEntry {

View file

@ -17,6 +17,14 @@
//! the target language, is refused: the concept word would say a different
//! thing than the name the packet cites.
//!
//! A request clause ("You asked Nibu to stop.") says what the addressee did, so
//! it is gated on the packet's own record of it: `Discourse.addressee_consent`
//! (set only by authoring or game telemetry, V15) must name that predication,
//! and its agent must be the addressee. Without it the lowerer refuses
//! ([`LowerError::ConsentMissing`], [`LowerError::AskerNotAddressee`]); it does
//! not read wording or guess who asked. A consent naming any other predication
//! is an unrendered slot.
//!
//! 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
//! means. `language-ontology` moves the rows into ontology documents.
@ -56,31 +64,31 @@ const CONCEPTS: &[Row] = &[
("concept:5", "ship_mind", "ship mind"),
// The Dao De Jing test bed (`daodejing.rs`). Nouns, then the verbs a
// `{verb}` frame speaks.
("concept:6", "sage", "sage"),
("concept:7", "mind", "minds"),
("concept:8", "belly", "bellies"),
("concept:9", "will", "wills"),
("concept:10", "bone", "bones"),
("concept:11", "empty", "empties"),
("concept:12", "fill", "fills"),
("concept:13", "weaken", "weakens"),
("concept:14", "strengthen", "strengthens"),
("concept:15", "heaven", "heaven"),
("concept:16", "earth", "earth"),
("concept:17", "is_long_enduring", "is long-enduring"),
("concept:18", "continues_long", "continues long"),
("concept:19", "highest_excellence", "highest excellence"),
("concept:20", "water", "water"),
("concept:21", "true_words", "words that are strictly true"),
("concept:22", "seem_paradoxical", "seem paradoxical"),
("concept:7", "sage", "sage"),
("concept:8", "mind", "minds"),
("concept:9", "belly", "bellies"),
("concept:10", "will", "wills"),
("concept:11", "bone", "bones"),
("concept:12", "empty", "empties"),
("concept:13", "fill", "fills"),
("concept:14", "weaken", "weakens"),
("concept:15", "strengthen", "strengthens"),
("concept:16", "heaven", "heaven"),
("concept:17", "earth", "earth"),
("concept:18", "is_long_enduring", "is long-enduring"),
("concept:19", "continues_long", "continues long"),
("concept:20", "highest_excellence", "highest excellence"),
("concept:21", "water", "water"),
("concept:22", "true_words", "words that are strictly true"),
("concept:23", "seem_paradoxical", "seem paradoxical"),
(
"concept:23",
"concept:24",
"space_between_heaven_and_earth",
"space between heaven and earth",
),
("concept:24", "bellows", "bellows"),
("concept:25", "compare", "compare"),
("concept:26", "resemble", "resemble"),
("concept:25", "bellows", "bellows"),
("concept:26", "compare", "compare"),
("concept:27", "resemble", "resemble"),
];
/// Frames: the clause a predication of that frame says. `{gloss}` is the filler
@ -92,23 +100,32 @@ const FRAMES: &[Row] = &[
"{agent} may endanger {patient} by touching {instrument}",
),
("frame:2", "intervention", "{agent} will stop {patient}"),
// The Dao De Jing test bed. Frame 3 was written from a Train chapter, 4 and
// 5 from Validation chapters, 6 and 7 from Test chapters.
("frame:3", "act", "{agent} {verb} {patient}"),
("frame:4", "intransitive", "{experiencer} {verb}"),
("frame:5", "likeness", "{experiencer} is like {goal}"),
(
"frame:6",
"frame:3",
"request_intervention",
"{agent} asked {patient} to stop",
),
// The Dao De Jing test bed. Frame 4 was written from a Train chapter, 5 and
// 6 from Validation chapters, 7 and 8 from Test chapters.
("frame:4", "act", "{agent} {verb} {patient}"),
("frame:5", "intransitive", "{experiencer} {verb}"),
("frame:6", "likeness", "{experiencer} is like {goal}"),
(
"frame:7",
"seems_paradoxical",
"{experiencer} seem paradoxical",
),
(
"frame:7",
"frame:8",
"may_be_compared",
"{experiencer} may be compared to {goal}",
),
];
/// The frame of "{agent} asked {patient} to stop": the one frame that reads
/// the discourse's addressee consent.
const REQUEST_FRAME: &str = "frame:3";
/// Speech acts: the opener of the first sentence.
const SPEECH_ACTS: &[Row] = &[
("speech_act:1", "assert", ""),
@ -138,6 +155,12 @@ pub enum LowerError {
NoPronunciation { entity: EntityId },
/// IPA was requested for a packet that cites no entity.
NoEntityReferent,
/// A request predication the packet does not carry the addressee's consent
/// to: no consent, or a consent that names another predication. The
/// lowerer does not guess who asked.
ConsentMissing { predication: NodeId },
/// A request predication whose agent is not the discourse addressee.
AskerNotAddressee { predication: NodeId },
/// The entity port failed to read.
EntityRead { entity: EntityId, why: String },
}
@ -182,9 +205,7 @@ pub fn lower(
{
return unrendered("features");
}
if input.discourse().addressee_consent.is_some() {
return unrendered("addressee consent");
}
request_gate(input, inv)?;
if !input.relations().is_empty() {
return unrendered("relations");
}
@ -231,6 +252,59 @@ pub fn lower(
Ok(out)
}
/// The one place consent is read. A request clause ([`REQUEST_FRAME`]) says what
/// the addressee did, so it needs the packet's own record of it: the discourse
/// `addressee_consent`, which validation lets only authoring or game telemetry
/// set (V15), must name that predication, and its agent must be the addressee.
/// Nothing here reads wording. A consent naming any other predication is a slot
/// the lowerer does not render.
fn request_gate(input: &LoweringInput, inv: &Inventory) -> Result<(), LowerError> {
let consent = input.discourse().addressee_consent.as_ref();
let requests = input
.predications()
.iter()
.filter(|p| p.frame.to_string() == REQUEST_FRAME);
for p in requests {
if consent != Some(&p.id) {
return Err(LowerError::ConsentMissing {
predication: p.id.clone(),
});
}
let agent = inv
.entries()
.find(|e| {
e.family() == Family::Role && e.gloss == "agent" && e.live_at(input.inventory_rev())
})
.ok_or_else(|| LowerError::UnknownRole {
frame: p.frame,
role: "agent".to_string(),
})?;
let asker = p
.roles
.iter()
.find(|r| r.role == agent.id)
.map(|r| &r.filler);
if asker.is_none() || asker != input.discourse().addressee.as_ref() {
return Err(LowerError::AskerNotAddressee {
predication: p.id.clone(),
});
}
}
match consent {
Some(_)
if !input
.predications()
.iter()
.any(|p| p.frame.to_string() == REQUEST_FRAME) =>
{
Err(LowerError::Unrendered {
what: "addressee consent",
})
}
_ => Ok(()),
}
}
/// The ruled IPA of every entity a packet cites, one per entity referent in
/// the packet's referent order, as stored: bare, stress-marked, nothing
/// derived. A rejected pronunciation is never read. An entity the port does not

View file

@ -436,3 +436,132 @@ fn ipa_needs_an_entity_the_port_holds_and_a_packet_that_cites_one() {
Err(LowerError::NoEntityReferent)
);
}
/// `nibu-proof-001` re-cut as the request: the addressee asked Nibu to stop,
/// one frame:3 predication (n4), consent naming it, and no other claim.
fn asked() -> Packet {
let mut p = proof_packet();
p.referents.remove(1);
let mut ask = p.predications[1].clone();
ask.id = nd("n4");
ask.concept = iv("concept:6");
ask.frame = iv("frame:3");
ask.roles = vec![
weksa::packet::RoleFill {
role: iv("role:1"),
filler: nd("n1"),
},
weksa::packet::RoleFill {
role: iv("role:2"),
filler: nd("n3"),
},
];
p.predications = vec![ask];
p.discourse.speech_act = Some(iv("speech_act:1"));
p.discourse.addressee_consent = Some(nd("n4"));
p.constraints.preserve = vec![nd("n1")];
p
}
/// The request plus a frame:2 predication (n5) the consent could wrongly name.
fn asked_and_stopped() -> Packet {
let mut p = asked();
let mut stop = proof_packet().predications.remove(1);
stop.roles[1].filler = nd("n4");
p.predications.push(stop);
p
}
#[test]
fn a_consented_request_lowers_to_what_the_addressee_asked() {
let (inv, _dir) = committed();
assert_eq!(lowered(&asked(), &inv).unwrap(), "You asked Nibu to stop.");
let mut p = asked();
p.provenance.source = weksa::packet::ProvenanceSource::GameTelemetry;
assert_eq!(lowered(&p, &inv).unwrap(), "You asked Nibu to stop.");
}
#[test]
fn a_request_without_its_consent_is_refused_not_invented() {
let (inv, _dir) = committed();
let mut p = asked();
p.discourse.addressee_consent = None;
assert_eq!(
lowered(&p, &inv),
Err(LowerError::ConsentMissing {
predication: nd("n4")
})
);
// Consent that names a different predication is no consent to the request.
let mut p = asked_and_stopped();
p.discourse.addressee_consent = Some(nd("n5"));
assert_eq!(
lowered(&p, &inv),
Err(LowerError::ConsentMissing {
predication: nd("n4")
})
);
}
#[test]
fn consent_to_one_of_two_requests_leaves_the_other_unconsented() {
let (inv, _dir) = committed();
let mut p = asked();
let mut second = p.predications[0].clone();
second.id = nd("n5");
p.predications.push(second);
assert_eq!(
lowered(&p, &inv),
Err(LowerError::ConsentMissing {
predication: nd("n5")
})
);
}
#[test]
fn a_request_by_someone_other_than_the_addressee_is_refused() {
let (inv, _dir) = committed();
let mut p = asked();
p.predications[0].roles[0].filler = nd("n3");
p.predications[0].roles[1].filler = nd("n1");
assert_eq!(
lowered(&p, &inv),
Err(LowerError::AskerNotAddressee {
predication: nd("n4")
})
);
}
#[test]
fn consent_on_a_claim_that_is_no_request_stays_unrendered() {
let (inv, _dir) = committed();
let mut p = proof_packet();
p.discourse.addressee_consent = Some(nd("n5"));
assert_eq!(
lowered(&p, &inv),
Err(LowerError::Unrendered {
what: "addressee consent"
})
);
}
#[test]
fn a_decomposition_or_import_cannot_reach_the_lowerer_with_consent() {
let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let inventory = InventoryStore::open(&root.join("data/interlingua/inventory.cc")).unwrap();
let corpus = CorpusStore::open(&root.join("data/corpus/corpus.cc")).unwrap();
let entities = EntityStore::open(&root.join("data/entity/entity.cc")).unwrap();
for source in [
weksa::packet::ProvenanceSource::ModelDecomposition,
weksa::packet::ProvenanceSource::ImportedCorpus,
] {
let mut p = asked();
p.provenance.source = source;
let dir = tempfile::tempdir().unwrap();
let refused = PacketStore::open(&dir.path().join("p.cc"))
.unwrap()
.admit(p, &inventory, &corpus, &entities)
.unwrap_err();
assert!(format!("{refused:?}").contains("V15"), "{source:?}");
}
}

Binary file not shown.

View file

@ -1 +1 @@
“²cultcache.store.v1‘—¸weksa.interlingua_packet¸weksa.interlingua_packet»weksa.interlingua_packet.v1¸weksa.interlingua_packetÙd{"schemaName":"weksa.interlingua_packet","schemaVersion":"weksa.interlingua_packet.v1","members":[]}‘¸weksa.interlingua_packet<EFBFBD>•”·packet:64616f2d30333032¸weksa.interlingua_packet´2026-11-09T10:13:02ZÅRž·packet:64616f2d30333032­CorpusExample”¨Authored°item:daodejing:1¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>••¢n1¯referent_kind:1©concept:6À<EFBFBD>•¢n2°referent_kind:11©concept:7À<EFBFBD>•¢n3¯referent_kind:3©concept:8À<EFBFBD>•¢n4°referent_kind:11©concept:9À<EFBFBD>•¢n5¯referent_kind:3ªconcept:10À<EFBFBD>”•¢n6ªconcept:11§frame:3’’¦role:1¢n1’¦role:2¢n2<EFBFBD>•¢n7ªconcept:12§frame:3’’¦role:1¢n1’¦role:2¢n3<EFBFBD>•¢n8ªconcept:13§frame:3’’¦role:1¢n1’¦role:2¢n4<EFBFBD>•¢n9ªconcept:14§frame:3’’¦role:1¢n1’¦role:2¢n5<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙXFour acts of one agent; 'in the exercise of his government' and 'their' are not carried.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30353032¸weksa.interlingua_packet´2026-11-09T10:13:02ZÅ^ž·packet:64616f2d30353032­CorpusExample”¨Authored°item:daodejing:5¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:2ÀÀ<EFBFBD>’•¢n1¯referent_kind:4ªconcept:23À<EFBFBD>•¢n2¯referent_kind:5ªconcept:24À<EFBFBD>‘•¢n3ªconcept:25§frame:7’’¦role:3¢n1’¦role:6¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙRA rhetorical question; the speech act is ask and the negated 'may not' is dropped.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30373031¸weksa.interlingua_packet´2026-11-09T10:13:02ZÅyž·packet:64616f2d30373031­CorpusExample”¨Authored°item:daodejing:2¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>’•¢n1¯referent_kind:4ªconcept:15À<EFBFBD>•¢n2¯referent_kind:4ªconcept:16À<EFBFBD>’•¢n3ªconcept:17§frame:4‘’¦role:3¢n1<EFBFBD>•¢n4ªconcept:18§frame:4‘’¦role:3¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙTHeaven and earth as places; whether they are entities is a ruling the ontology owes.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30383031¸weksa.interlingua_packet´2026-11-09T10:13:02ZÅwž·packet:64616f2d30383031­CorpusExample”¨Authored°item:daodejing:3¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>’•¢n1°referent_kind:11ªconcept:19À<EFBFBD>•¢n2°referent_kind:11ªconcept:20À<EFBFBD>‘•¢n3ªconcept:26§frame:5’’¦role:3¢n1’¦role:6¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙSThe metaphor is a plain likeness predication; the tenor and vehicle are not marked.<EFBFBD>‘’’ªfeature:18<EFBFBD>¥GradeÍ ’ªfeature:16<EFBFBD>¥GradeÍ,”·packet:64616f2d37383034¸weksa.interlingua_packet´2026-11-09T10:13:02ZÅNž·packet:64616f2d37383034­CorpusExample”¨Authored°item:daodejing:4¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>‘•¢n1°referent_kind:11ªconcept:21À<EFBFBD>‘•¢n2ªconcept:22§frame:6‘’¦role:3¢n1<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙmThe whole paradox is in the referent's concept and the frame; the packet holds no more than the surface does.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ
“²cultcache.store.v1‘—¸weksa.interlingua_packet¸weksa.interlingua_packet»weksa.interlingua_packet.v1¸weksa.interlingua_packetÙd{"schemaName":"weksa.interlingua_packet","schemaVersion":"weksa.interlingua_packet.v1","members":[]}‘¸weksa.interlingua_packet<EFBFBD>•”·packet:64616f2d30333032¸weksa.interlingua_packet´2026-11-09T10:16:16ZÅSž·packet:64616f2d30333032­CorpusExample”¨Authored°item:daodejing:1¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>••¢n1¯referent_kind:1©concept:7À<EFBFBD>•¢n2°referent_kind:11©concept:8À<EFBFBD>•¢n3¯referent_kind:3©concept:9À<EFBFBD>•¢n4°referent_kind:11ªconcept:10À<EFBFBD>•¢n5¯referent_kind:3ªconcept:11À<EFBFBD>”•¢n6ªconcept:12§frame:4’’¦role:1¢n1’¦role:2¢n2<EFBFBD>•¢n7ªconcept:13§frame:4’’¦role:1¢n1’¦role:2¢n3<EFBFBD>•¢n8ªconcept:14§frame:4’’¦role:1¢n1’¦role:2¢n4<EFBFBD>•¢n9ªconcept:15§frame:4’’¦role:1¢n1’¦role:2¢n5<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙXFour acts of one agent; 'in the exercise of his government' and 'their' are not carried.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30353032¸weksa.interlingua_packet´2026-11-09T10:16:16ZÅ^ž·packet:64616f2d30353032­CorpusExample”¨Authored°item:daodejing:5¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:2ÀÀ<EFBFBD>’•¢n1¯referent_kind:4ªconcept:24À<EFBFBD>•¢n2¯referent_kind:5ªconcept:25À<EFBFBD>‘•¢n3ªconcept:26§frame:8’’¦role:3¢n1’¦role:6¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙRA rhetorical question; the speech act is ask and the negated 'may not' is dropped.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30373031¸weksa.interlingua_packet´2026-11-09T10:16:16ZÅyž·packet:64616f2d30373031­CorpusExample”¨Authored°item:daodejing:2¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>’•¢n1¯referent_kind:4ªconcept:16À<EFBFBD>•¢n2¯referent_kind:4ªconcept:17À<EFBFBD>’•¢n3ªconcept:18§frame:5‘’¦role:3¢n1<EFBFBD>•¢n4ªconcept:19§frame:5‘’¦role:3¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙTHeaven and earth as places; whether they are entities is a ruling the ontology owes.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ ”·packet:64616f2d30383031¸weksa.interlingua_packet´2026-11-09T10:16:16ZÅwž·packet:64616f2d30383031­CorpusExample”¨Authored°item:daodejing:3¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>’•¢n1°referent_kind:11ªconcept:20À<EFBFBD>•¢n2°referent_kind:11ªconcept:21À<EFBFBD>‘•¢n3ªconcept:27§frame:6’’¦role:3¢n1’¦role:6¢n2<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙSThe metaphor is a plain likeness predication; the tenor and vehicle are not marked.<EFBFBD>‘’’ªfeature:18<EFBFBD>¥GradeÍ ’ªfeature:16<EFBFBD>¥GradeÍ,”·packet:64616f2d37383034¸weksa.interlingua_packet´2026-11-09T10:16:16ZÅNž·packet:64616f2d37383034­CorpusExample”¨Authored°item:daodejing:4¸encoder:636c617564652d73ÍX”ÀÀ<EFBFBD><EFBFBD>”¬speech_act:1ÀÀ<EFBFBD>‘•¢n1°referent_kind:11ªconcept:22À<EFBFBD>‘•¢n2ªconcept:23§frame:7‘’¦role:3¢n1<EFBFBD><EFBFBD>“<EFBFBD>ÂÀ<EFBFBD>’‘ÙmThe whole paradox is in the referent's concept and the frame; the packet holds no more than the surface does.<EFBFBD>‘‘’ªfeature:18<EFBFBD>¥GradeÍ

Binary file not shown.

View file

@ -195,9 +195,10 @@ and `features` carry source-side nuance on content (hedge, certainty, irony and
whatever the inventory grows). This is source-side communicative pressure, not
target-language register. `addressee_consent` is no feature: it names the
predication the addressee asked for or agreed to, a fact about what the
addressee did. The English lowerer renders no consent and refuses a packet that
carries one; a row that speaks for the request ("you asked her to") reads it
and refuses without it.
addressee did. The English lowerer's request row (`frame:3`, "{agent} asked
{patient} to stop") reads it: the consent must name that predication and its
agent must be the addressee, else `ConsentMissing` or `AskerNotAddressee`. A
consent naming any other predication is refused as unrendered.
### `stance`

View file

@ -342,7 +342,7 @@ measurable baseline from a packet: `lower` gives text, `score` gives numbers.
| Whether a packet exists | `validate` / `PacketStore::admit` (unchanged) | packet, inventory, corpus, entities | admitted packet or typed refusal | the lowerer |
| Wording of a packet in English | `crates/weksa/src/lower.rs`: `lower(&LoweringInput, &Inventory) -> Result<String, LowerError>` | the validated lowering view and the inventory at its revision | text, or a typed refusal naming the missing template | the corpus item, the scorer, any model |
| English template table (concept words, frame templates, speech-act openers) | the same module, as rows `(inventory id, gloss it speaks for, surface)` | none; it is data in code | rows the lowerer looks up | the inventory (it owns the ids and glosses, not the English) |
| The inventory's concepts and frames | an inventory revision; here `inventory::proof_revision()` (rev 2), hand-seeded as `seed()` is | none | the 5 concepts and 2 frames `nibu-proof-001` names | the lowerer |
| The inventory's concepts and frames | an inventory revision; here `inventory::proof_revision()` (rev 2), hand-seeded as `seed()` is | none | the 6 concepts and 3 frames `nibu-proof-001` and the consent-gated request packet name | the lowerer |
| What a score counts | `Scorer::score` (unchanged) | output text, reference text | `ItemScore` | `weksa score`, which only reads text and calls it |
| The proof packet | `packet::proof_packet()`, typed ids of rev 2, admitted by `weksa packet proof <store>` through `PacketStore::admit`. Not JSON: `Packet`'s serde is CultCache's positional tuple, and JSON in is the xenos boundary the cut 7 encoder owns | none | admitted packet | the CLI decides nothing about validity |