Dao De Jing test bed: PublicDomain provenance fields, Legge slice, first golf-loop number #10

Merged
weksa merged 4 commits from weksa/dao-de-jing-test-bed into main 2026-11-09 10:22:55 +00:00
15 changed files with 824 additions and 3 deletions

View file

@ -29,10 +29,19 @@ pub enum Source {
OperatorApproved {
note: String,
},
/// A public-domain work, with everything a reader needs to check the claim:
/// the edition's licence and the jurisdiction the public-domain status is
/// asserted in, who translated it (the translation is the text's copyright,
/// not the original's) and when the edition appeared. A work missing any
/// is refused at admission.
PublicDomain {
work: String,
author: String,
edition_url: String,
licence: String,
jurisdiction: String,
translator: String,
edition_year: u16,
},
/// Labelled model output; never in the test split, never judged by its own family.
/// `family` is `Unrecorded` when nothing records one. `generator` is the

View file

@ -0,0 +1,326 @@
//! The Dao De Jing test bed: inventory revision 3 of the `data/daodejing`
//! stores and the packets for the slice of James Legge's chapters in its corpus.
//! It follows `proof_packet`'s precedent: a hand-authored packet the stores
//! admit through the same doors as any other.
//!
//! The ids carry the leak labels the golf loop needs. A frame minted while
//! reading a Train chapter is generic evidence; one minted for a Validation or
//! Test chapter was written with that chapter's reference in view, so a score
//! on it measures the lowerer table's reach and not the interlingua's.
use std::num::NonZeroU32;
use crate::corpus::CorpusItemId;
use crate::inventory::{Change, Family, InvId, InventoryEntry, InventoryRevision};
use crate::packet::{
Constraints, Context, Discourse, EncoderId, FeatValue, FeatureValue, Grade, NodeId, Packet,
PacketId, PacketKind, Predication, Provenance, ProvenanceSource, Referent, RoleFill,
SCHEMA_VERSION, Stance, Trace,
};
const CONCEPTS: &[&str] = &[
"sage",
"mind",
"belly",
"will",
"bone",
"empty",
"fill",
"weaken",
"strengthen",
"heaven",
"earth",
"is_long_enduring",
"continues_long",
"highest_excellence",
"water",
"true_words",
"seem_paradoxical",
"space_between_heaven_and_earth",
"bellows",
"compare",
"resemble",
];
/// 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",
"likeness",
"seems_paradoxical",
"may_be_compared",
];
/// Revision 3 of the Dao De Jing stores, after the seed and the proof revision.
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 { 7 } else { 4 };
for (i, gloss) in glosses.iter().enumerate() {
entries.push(InventoryEntry {
id: family.id(NonZeroU32::new(first + i as u32).expect("nonzero")),
gloss: (*gloss).to_string(),
value_kind: None,
applies_to: vec![],
introduced_rev: 3,
retired_rev: None,
});
}
}
let changes = entries.iter().map(|e| Change::Add(e.id)).collect();
(
InventoryRevision {
n: 3,
parent: Some(2),
changes,
frozen: false,
},
entries,
)
}
fn concept(gloss: &str) -> &'static str {
let at = CONCEPTS
.iter()
.position(|c| *c == gloss)
.expect("known concept");
Box::leak(format!("concept:{}", 7 + at).into_boxed_str())
}
fn frame(gloss: &str) -> &'static str {
let at = FRAMES
.iter()
.position(|c| *c == gloss)
.expect("known frame");
Box::leak(format!("frame:{}", 4 + at).into_boxed_str())
}
fn hex8(ascii: &str) -> String {
assert_eq!(ascii.len(), 8);
ascii.bytes().map(|b| format!("{b:02x}")).collect()
}
struct Spec {
/// Eight ASCII characters; the packet id is their hex.
id: &'static str,
item: &'static str,
speech_act: &'static str,
/// `(node, referent kind id, concept gloss)`.
referents: &'static [(&'static str, &'static str, &'static str)],
/// `(node, concept gloss, frame gloss, [(role id, filler node)])`.
predications: &'static [(
&'static str,
&'static str,
&'static str,
&'static [(&'static str, &'static str)],
)],
/// The author's reading of the speaker's felt state: `(feature gloss, permille)`.
stance: &'static [(&'static str, u16)],
note: &'static str,
}
const AGENT: &str = "role:1";
const PATIENT: &str = "role:2";
const EXPERIENCER: &str = "role:3";
const GOAL: &str = "role:6";
const PERSON: &str = "referent_kind:1";
const ORGANISM: &str = "referent_kind:3";
const PLACE: &str = "referent_kind:4";
const ABSTRACT: &str = "referent_kind:11";
/// Feature ids of the seed: restraint is the tenth stance feature.
fn stance_feature(gloss: &str) -> InvId {
let n = [
"anger",
"fear",
"sadness",
"joy",
"disgust",
"surprise",
"contempt",
"affection",
"shame",
"restraint",
]
.iter()
.position(|g| *g == gloss)
.expect("stance feature");
// Features before the stance block: polarity, tense, aspect, modality,
// evidentiality, hedge, certainty, irony.
InvId::parse(&format!("feature:{}", 9 + n)).expect("feature id")
}
const SPECS: &[Spec] = &[
// Chapter 3 section 2. Train.
Spec {
id: "dao-0302",
item: "item:daodejing:1",
speech_act: "speech_act:1",
referents: &[
("n1", PERSON, "sage"),
("n2", ABSTRACT, "mind"),
("n3", ORGANISM, "belly"),
("n4", ABSTRACT, "will"),
("n5", ORGANISM, "bone"),
],
predications: &[
("n6", "empty", "act", &[(AGENT, "n1"), (PATIENT, "n2")]),
("n7", "fill", "act", &[(AGENT, "n1"), (PATIENT, "n3")]),
("n8", "weaken", "act", &[(AGENT, "n1"), (PATIENT, "n4")]),
("n9", "strengthen", "act", &[(AGENT, "n1"), (PATIENT, "n5")]),
],
stance: &[("restraint", 800)],
note: "Four acts of one agent; 'in the exercise of his government' and 'their' are not carried.",
},
// Chapter 7 section 1, first sentence. Validation.
Spec {
id: "dao-0701",
item: "item:daodejing:2",
speech_act: "speech_act:1",
referents: &[("n1", PLACE, "heaven"), ("n2", PLACE, "earth")],
predications: &[
(
"n3",
"is_long_enduring",
"intransitive",
&[(EXPERIENCER, "n1")],
),
(
"n4",
"continues_long",
"intransitive",
&[(EXPERIENCER, "n2")],
),
],
stance: &[("restraint", 800)],
note: "Heaven and earth as places; whether they are entities is a ruling the ontology owes.",
},
// Chapter 8 section 1, first sentence. Validation.
Spec {
id: "dao-0801",
item: "item:daodejing:3",
speech_act: "speech_act:1",
referents: &[
("n1", ABSTRACT, "highest_excellence"),
("n2", ABSTRACT, "water"),
],
predications: &[(
"n3",
"resemble",
"likeness",
&[(EXPERIENCER, "n1"), (GOAL, "n2")],
)],
stance: &[("restraint", 800), ("affection", 300)],
note: "The metaphor is a plain likeness predication; the tenor and vehicle are not marked.",
},
// Chapter 78 section 4. Test.
Spec {
id: "dao-7804",
item: "item:daodejing:4",
speech_act: "speech_act:1",
referents: &[("n1", ABSTRACT, "true_words")],
predications: &[(
"n2",
"seem_paradoxical",
"seems_paradoxical",
&[(EXPERIENCER, "n1")],
)],
stance: &[("restraint", 800)],
note: "The whole paradox is in the referent's concept and the frame; the packet holds no more than the surface does.",
},
// Chapter 5 section 2, first sentence. Test.
Spec {
id: "dao-0502",
item: "item:daodejing:5",
speech_act: "speech_act:2",
referents: &[
("n1", PLACE, "space_between_heaven_and_earth"),
("n2", ARTIFACT, "bellows"),
],
predications: &[(
"n3",
"compare",
"may_be_compared",
&[(EXPERIENCER, "n1"), (GOAL, "n2")],
)],
stance: &[("restraint", 800)],
note: "A rhetorical question; the speech act is ask and the negated 'may not' is dropped.",
},
];
const ARTIFACT: &str = "referent_kind:5";
/// The packets of the slice, each minted for its corpus item.
pub fn packets() -> Vec<Packet> {
SPECS.iter().map(build).collect()
}
fn build(spec: &Spec) -> Packet {
let id = |s: &str| InvId::parse(s).expect("ids are well formed");
let node = |s: &str| NodeId::parse(s).expect("nodes are well formed");
Packet {
id: PacketId::parse(&format!("packet:{}", hex8(spec.id))).expect("packet id"),
schema_version: SCHEMA_VERSION,
inventory_rev: 3,
kind: PacketKind::CorpusExample,
provenance: Provenance {
source: ProvenanceSource::Authored,
corpus_item: CorpusItemId::parse(spec.item).expect("item key"),
encoder: EncoderId::parse(&format!("encoder:{}", hex8("claude-s"))).expect("encoder"),
confidence: Grade::new(600).expect("grade"),
},
context: Context::default(),
discourse: Discourse {
speech_act: Some(id(spec.speech_act)),
addressee: None,
addressee_consent: None,
features: vec![],
},
referents: spec
.referents
.iter()
.map(|(n, kind, gloss)| Referent {
id: node(n),
kind: id(kind),
concept: id(concept(gloss)),
entity: None,
features: vec![],
})
.collect(),
predications: spec
.predications
.iter()
.map(|(n, c, f, roles)| Predication {
id: node(n),
concept: id(concept(c)),
frame: id(frame(f)),
roles: roles
.iter()
.map(|(role, filler)| RoleFill {
role: id(role),
filler: node(filler),
})
.collect(),
features: vec![],
})
.collect(),
relations: vec![],
constraints: Constraints::default(),
extensions: vec![],
trace: Trace {
notes: vec![spec.note.to_string()],
rejected_readings: vec![],
},
stance: Stance {
features: spec
.stance
.iter()
.map(|(g, v)| FeatureValue {
feature: stance_feature(g),
value: FeatValue::Grade(Grade::new(*v).expect("grade")),
})
.collect(),
},
}
}

View file

@ -4,6 +4,7 @@
//! (chrF, meaning cosine, leak diagnostics).
pub mod corpus;
pub mod daodejing;
pub mod entity;
pub mod form;
pub mod inventory;

View file

@ -65,6 +65,33 @@ const CONCEPTS: &[Row] = &[
("concept:3", "player", "player"),
("concept:4", "control", "control"),
("concept:5", "ship_mind", "ship mind"),
// The Dao De Jing test bed (`daodejing.rs`). Nouns, then the verbs a
// `{verb}` frame speaks.
("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:24",
"space_between_heaven_and_earth",
"space between heaven and earth",
),
("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
@ -81,6 +108,21 @@ const FRAMES: &[Row] = &[
"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:8",
"may_be_compared",
"{experiencer} may be compared to {goal}",
),
];
/// The frame of "{agent} asked {patient} to stop": the one frame that reads
@ -90,6 +132,7 @@ const REQUEST_FRAME: &str = "frame:3";
/// Speech acts: the opener of the first sentence.
const SPEECH_ACTS: &[Row] = &[
("speech_act:1", "assert", ""),
("speech_act:2", "ask", ""),
("speech_act:5", "warn", "Warning: "),
];
@ -353,6 +396,10 @@ fn clause(
let close = rest[open..].find('}').map_or(rest.len(), |c| open + c);
let name = &rest[open + 1..close];
rest = &rest[(close + 1).min(rest.len())..];
if name == "verb" {
out.push_str(row(CONCEPTS, p.concept, inv, rev)?);
continue;
}
let role = inv
.entries()
.find(|e| e.family() == Family::Role && e.gloss == name && e.live_at(rev))

View file

@ -76,6 +76,8 @@ enum Command {
enum PacketCommand {
/// Admit the nibu-proof-001 packet through `PacketStore::admit`.
Proof { store: PathBuf },
/// Admit the Dao De Jing slice's packets through `PacketStore::admit`.
Dao { store: PathBuf },
}
#[derive(Args)]
@ -110,6 +112,8 @@ enum InventoryCommand {
Seed,
/// Admit revision 2, the concepts and frames the nibu-proof-001 packet names.
Proof,
/// Admit revision 3 of the Dao De Jing test bed stores (after seed and proof).
Dao,
}
#[derive(Subcommand)]
@ -288,6 +292,16 @@ struct AddArgs {
author: Option<String>,
#[arg(long)]
edition_url: Option<String>,
/// The edition's licence, for `public-domain`.
#[arg(long)]
licence: Option<String>,
/// Where the public-domain status is asserted, for `public-domain`.
#[arg(long)]
jurisdiction: Option<String>,
#[arg(long)]
translator: Option<String>,
#[arg(long)]
edition_year: Option<u16>,
#[arg(long = "model-family", value_enum)]
family: Option<ModelFamilyArg>,
/// The generator string the fixture or run wrote, verbatim.
@ -312,7 +326,15 @@ impl AddArgs {
SourceKind::CastAuthored => &["persona", "fixture", "author"],
SourceKind::OperatorWritten => &[],
SourceKind::OperatorApproved => &["note"],
SourceKind::PublicDomain => &["work", "author", "edition-url"],
SourceKind::PublicDomain => &[
"work",
"author",
"edition-url",
"licence",
"jurisdiction",
"translator",
"edition-year",
],
SourceKind::ModelWritten => &["model-family", "generator", "prompt-digest"],
};
let given = [
@ -322,6 +344,10 @@ impl AddArgs {
("note", self.note.is_some()),
("work", self.work.is_some()),
("edition-url", self.edition_url.is_some()),
("licence", self.licence.is_some()),
("jurisdiction", self.jurisdiction.is_some()),
("translator", self.translator.is_some()),
("edition-year", self.edition_year.is_some()),
("model-family", self.family.is_some()),
("generator", self.generator.is_some()),
("prompt-digest", self.prompt_digest.is_some()),
@ -348,6 +374,12 @@ impl AddArgs {
work: get(&self.work, "work")?,
author: get(&self.author, "author")?,
edition_url: get(&self.edition_url, "edition-url")?,
licence: get(&self.licence, "licence")?,
jurisdiction: get(&self.jurisdiction, "jurisdiction")?,
translator: get(&self.translator, "translator")?,
edition_year: self
.edition_year
.context("this source needs --edition-year")?,
},
SourceKind::ModelWritten => Source::ModelWritten {
family: self
@ -519,6 +551,27 @@ fn main() -> Result<()> {
.map_err(refused)?;
println!("admitted rev:2 with {count} entries");
}
Command::Inventory(InventoryCommand::Dao) => {
let (rev, entries) = weksa::daodejing::revision();
let count = entries.len();
InventoryStore::open(&cli.inventory)?
.admit_revision(rev, entries)
.map_err(refused)?;
println!("admitted rev:3 with {count} entries");
}
Command::Packet(PacketCommand::Dao { store }) => {
let mut packets = PacketStore::open(&store)?;
let inventory = InventoryStore::open(&cli.inventory)?;
let corpus = CorpusStore::open(&cli.corpus)?;
let entities = EntityStore::open(&cli.entities)?;
for packet in weksa::daodejing::packets() {
let key = packet.id.to_string();
packets
.admit(packet, &inventory, &corpus, &entities)
.map_err(refused)?;
println!("admitted {key}");
}
}
Command::Packet(PacketCommand::Proof { store }) => {
let packet = proof_packet();
let key = packet.id.to_string();

View file

@ -402,6 +402,18 @@ fn empty_attestation(source: &Source) -> Option<&'static str> {
Source::PublicDomain { edition_url, .. } if empty(edition_url) => {
Some("a public-domain source names its edition url")
}
Source::PublicDomain { licence, .. } if empty(licence) => {
Some("a public-domain source names its licence")
}
Source::PublicDomain { jurisdiction, .. } if empty(jurisdiction) => {
Some("a public-domain source names its jurisdiction")
}
Source::PublicDomain { translator, .. } if empty(translator) => {
Some("a public-domain source names its translator")
}
Source::PublicDomain {
edition_year: 0, ..
} => Some("a public-domain source names its edition year"),
Source::ModelWritten { generator, .. } if empty_some(generator) => {
Some("a model-written source names a non-empty generator")
}

View file

@ -210,6 +210,14 @@ fn model_written_and_public_domain_sources_name_their_provenance() {
"a",
"--edition-url",
"https://example.org/w",
"--licence",
"Public domain",
"--jurisdiction",
"US",
"--translator",
"T. Translator",
"--edition-year",
"1891",
]);
assert!(pd.status.success(), "{}", out(&pd));
let bad_turn = run(&[
@ -566,6 +574,14 @@ fn source_flags_must_match_the_source() {
"a",
"--edition-url",
"u",
"--licence",
"l",
"--jurisdiction",
"j",
"--translator",
"t",
"--edition-year",
"1891",
"--note",
"n",
],
@ -618,6 +634,78 @@ fn source_flags_must_match_the_source() {
&["--work", "w", "--edition-url", "u"],
"--author",
),
(
"public-domain",
&[
"--work",
"w",
"--author",
"a",
"--edition-url",
"u",
"--jurisdiction",
"j",
"--translator",
"t",
"--edition-year",
"1891",
],
"--licence",
),
(
"public-domain",
&[
"--work",
"w",
"--author",
"a",
"--edition-url",
"u",
"--licence",
"l",
"--translator",
"t",
"--edition-year",
"1891",
],
"--jurisdiction",
),
(
"public-domain",
&[
"--work",
"w",
"--author",
"a",
"--edition-url",
"u",
"--licence",
"l",
"--jurisdiction",
"j",
"--edition-year",
"1891",
],
"--translator",
),
(
"public-domain",
&[
"--work",
"w",
"--author",
"a",
"--edition-url",
"u",
"--licence",
"l",
"--jurisdiction",
"j",
"--translator",
"t",
],
"--edition-year",
),
// Empty provenance strings.
(
"model-written",

View file

@ -0,0 +1,71 @@
//! The Dao De Jing test bed (`data/daodejing`): its Legge items carry full
//! public-domain provenance, and its packets are admitted and lower to the
//! English the first golf-loop run scored (`docs/targets/dao-de-jing-test-bed.md`).
use std::path::Path;
use weksa::daodejing::packets;
use weksa::{CorpusStore, EntityStore, InventoryStore, PacketStore, Source, lower};
fn root() -> std::path::PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../data/daodejing")
}
#[test]
fn every_legge_item_names_licence_jurisdiction_translator_and_edition_year() {
let items = CorpusStore::open(&root().join("corpus.cc"))
.unwrap()
.all()
.unwrap();
assert_eq!(items.len(), 5);
for item in items {
let Source::PublicDomain {
licence,
jurisdiction,
translator,
edition_year,
..
} = item.source
else {
panic!("{} is not a public-domain item", item.id);
};
assert!(
!licence.is_empty() && !jurisdiction.is_empty(),
"{}",
item.id
);
assert_eq!((translator.as_str(), edition_year), ("James Legge", 1891));
}
}
#[test]
fn the_slice_packets_are_admitted_and_lower_to_the_scored_english() {
let inventory = InventoryStore::open(&root().join("inventory.cc")).unwrap();
let corpus = CorpusStore::open(&root().join("corpus.cc")).unwrap();
let entities = EntityStore::open(&root().join("entity.cc")).unwrap();
let dir = tempfile::tempdir().unwrap();
let mut store = PacketStore::open(&dir.path().join("p.cc")).unwrap();
let inv = inventory.inventory().unwrap();
let lowered: Vec<String> = packets()
.into_iter()
.map(|p| {
let view = store.admit(p, &inventory, &corpus, &entities).unwrap();
lower(&view, &inv, &entities).unwrap()
})
.collect();
assert_eq!(
lowered,
[
"The sage empties the minds. The sage fills the bellies. The sage weakens the wills. The sage strengthens the bones.",
"The heaven is long-enduring. The earth continues long.",
"The highest excellence is like the water.",
"The words that are strictly true seem paradoxical.",
"The space between heaven and earth may be compared to the bellows.",
]
);
// The committed packet store holds exactly what the module builds.
let stored = PacketStore::open(&root().join("packets.cc")).unwrap();
for p in packets() {
assert_eq!(stored.get(&p.id.to_string()).unwrap(), Some(p));
}
}

View file

@ -371,7 +371,7 @@ fn an_attestation_holds_something_readable() {
let mut store = CorpusStore::open(&d.path().join("c.cc")).unwrap();
let s = |x: &str| x.to_string();
type Build = fn(String) -> Source;
let builders: [(Build, &'static str); 9] = [
let builders: [(Build, &'static str); 12] = [
(
|v| Source::CastAuthored {
persona: v,
@ -405,6 +405,10 @@ fn an_attestation_holds_something_readable() {
work: v,
author: "a".into(),
edition_url: "u".into(),
licence: "l".into(),
jurisdiction: "j".into(),
translator: "t".into(),
edition_year: 1891,
},
"a public-domain source names its work",
),
@ -413,6 +417,10 @@ fn an_attestation_holds_something_readable() {
work: "w".into(),
author: v,
edition_url: "u".into(),
licence: "l".into(),
jurisdiction: "j".into(),
translator: "t".into(),
edition_year: 1891,
},
"a public-domain source names its author",
),
@ -421,9 +429,49 @@ fn an_attestation_holds_something_readable() {
work: "w".into(),
author: "a".into(),
edition_url: v,
licence: "l".into(),
jurisdiction: "j".into(),
translator: "t".into(),
edition_year: 1891,
},
"a public-domain source names its edition url",
),
(
|v| Source::PublicDomain {
work: "w".into(),
author: "a".into(),
edition_url: "u".into(),
licence: v,
jurisdiction: "j".into(),
translator: "t".into(),
edition_year: 1891,
},
"a public-domain source names its licence",
),
(
|v| Source::PublicDomain {
work: "w".into(),
author: "a".into(),
edition_url: "u".into(),
licence: "l".into(),
jurisdiction: v,
translator: "t".into(),
edition_year: 1891,
},
"a public-domain source names its jurisdiction",
),
(
|v| Source::PublicDomain {
work: "w".into(),
author: "a".into(),
edition_url: "u".into(),
licence: "l".into(),
jurisdiction: "j".into(),
translator: v,
edition_year: 1891,
},
"a public-domain source names its translator",
),
(
|v| Source::ModelWritten {
family: ModelFamily::Unrecorded,
@ -528,6 +576,10 @@ fn an_item_source_attests_with_non_empty_strings() {
work: s(work),
author: s(author),
edition_url: s(url),
licence: s("l"),
jurisdiction: s("j"),
translator: s("t"),
edition_year: 1891,
};
let cases: [(Source, &'static str); 9] = [
(
@ -1292,3 +1344,26 @@ fn seed_reseeded() {
replay.add(i, &entities).unwrap();
}
}
#[test]
fn a_public_domain_source_without_an_edition_year_is_refused() {
let d = dir();
let mut store = CorpusStore::open(&d.path().join("c.cc")).unwrap();
let key = "item:pd:1";
let source = |edition_year| Source::PublicDomain {
work: "w".into(),
author: "a".into(),
edition_url: "u".into(),
licence: "l".into(),
jurisdiction: "j".into(),
translator: "t".into(),
edition_year,
};
assert_eq!(
refusal(store.add(item_in(key, "line", "scene-1", source(0)), &ents(&d))),
malformed(key, "a public-domain source names its edition year")
);
store
.add(item_in(key, "line", "scene-1", source(1891)), &ents(&d))
.unwrap();
}

1
data/daodejing/corpus.cc Normal file
View file

@ -0,0 +1 @@
“²cultcache.store.v1‘—±weksa.corpus_item±weksa.corpus_item´weksa.corpus_item.v1±weksa.corpus_itemÙV{"schemaName":"weksa.corpus_item","schemaVersion":"weksa.corpus_item.v1","members":[]}‘±weksa.corpus_item<EFBFBD>•”°item:daodejing:1±weksa.corpus_item´2026-11-07T02:09:00ZÅ4›°item:daodejing:1Ù’Therefore the sage, in the exercise of his government, empties their minds, fills their bellies, weakens their wills, and strengthens their bones.¥en-US¬entity:laozi³daodejing-legge-ch3<EFBFBD><EFBFBD>¬PublicDomain—ÙBThe Tao Teh King, or the Tao and its Characteristics (Dao De Jing)¥LaoziÙ$https://www.gutenberg.org/ebooks/216Ù<36>Public domain (author d. c. 5th century BCE; translator d. 1897); Project Gutenberg eBook 216 text used without its trademark or licence matterÙ7United States and life+70 jurisdictions (Legge d. 1897)«James LeggeÍcª2026-11-07ÀÂ<C380>”°item:daodejing:2±weksa.corpus_item´2026-11-07T02:09:00ZÅÓ›°item:daodejing:2Ù1Heaven is long-enduring and earth continues long.¥en-US¬entity:laozi³daodejing-legge-ch7<68><37>¬PublicDomain—ÙBThe Tao Teh King, or the Tao and its Characteristics (Dao De Jing)¥LaoziÙ$https://www.gutenberg.org/ebooks/216Ù<36>Public domain (author d. c. 5th century BCE; translator d. 1897); Project Gutenberg eBook 216 text used without its trademark or licence matterÙ7United States and life+70 jurisdictions (Legge d. 1897)«James LeggeÍcª2026-11-07ÀÂ<C380>”°item:daodejing:3±weksa.corpus_item´2026-11-07T02:09:00ZÅÑ›°item:daodejing:3Ù/The highest excellence is like (that of) water.¥en-US¬entity:laozi³daodejing-legge-ch8<68><38>¬PublicDomain—ÙBThe Tao Teh King, or the Tao and its Characteristics (Dao De Jing)¥LaoziÙ$https://www.gutenberg.org/ebooks/216Ù<36>Public domain (author d. c. 5th century BCE; translator d. 1897); Project Gutenberg eBook 216 text used without its trademark or licence matterÙ7United States and life+70 jurisdictions (Legge d. 1897)«James LeggeÍcª2026-11-07ÀÂ<C380>”°item:daodejing:4±weksa.corpus_item´2026-11-07T02:09:00ZÅ×›°item:daodejing:4Ù4Words that are strictly true seem to be paradoxical.¥en-US¬entity:laozi´daodejing-legge-ch78<37><38>¬PublicDomain—ÙBThe Tao Teh King, or the Tao and its Characteristics (Dao De Jing)¥LaoziÙ$https://www.gutenberg.org/ebooks/216Ù<36>Public domain (author d. c. 5th century BCE; translator d. 1897); Project Gutenberg eBook 216 text used without its trademark or licence matterÙ7United States and life+70 jurisdictions (Legge d. 1897)«James LeggeÍcª2026-11-07ÀÂ<C380>”°item:daodejing:5±weksa.corpus_item´2026-11-07T02:09:00ZÅæ›°item:daodejing:5ÙDMay not the space between heaven and earth be compared to a bellows?¥en-US¬entity:laozi³daodejing-legge-ch5<68><35>¬PublicDomain—ÙBThe Tao Teh King, or the Tao and its Characteristics (Dao De Jing)¥LaoziÙ$https://www.gutenberg.org/ebooks/216Ù<36>Public domain (author d. c. 5th century BCE; translator d. 1897); Project Gutenberg eBook 216 text used without its trademark or licence matterÙ7United States and life+70 jurisdictions (Legge d. 1897)«James LeggeÍcª2026-11-07ÀÂ<C380>

1
data/daodejing/entity.cc Normal file
View file

@ -0,0 +1 @@
“²cultcache.store.v1‘—¬weksa.entity¬weksa.entity¯weksa.entity.v1¬weksa.entityÙL{"schemaName":"weksa.entity","schemaVersion":"weksa.entity.v1","members":[]}‘¬weksa.entity<EFBFBD>‘”¬entity:laozi¬weksa.entity´2026-11-07T02:09:00ZÄb“¬entity:laozi‘’¥en-US‘¥Laozi<EFBFBD>¬PublicDomain‘Ù4The Tao Teh King, or the Tao and its Characteristics

BIN
data/daodejing/inventory.cc Normal file

Binary file not shown.

View file

@ -0,0 +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: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Í

View file

@ -0,0 +1,116 @@
# Dao De Jing test bed
A lowering test bed on James Legge's public-domain translation of the Dao De
Jing, from Meta's analogy: the Dao has many varied human translations, so it is
a ready-made field of precedents for what one meaning can be lowered to. Meta
proposed it in #weksa:gamecult.org on 2026-11-06 (Matrix event
`$2_P0mbtbnnsP4I61UhVMlatuDSTjFXMOuGa4SSbhGmc`: public-domain translations only
as the scoring corpus, copyrighted ones cited without copying) and noted the
ontology consequence (event `$E4VHwS-zFEk9Fa-daFX8MkfoySn0iX0m1grltEJ9A8Y`:
model an imperial native term as a term with several context-tagged readings
plus a separately recorded chosen gloss per lowering).
## What is here
- `data/daodejing/`: its own stores (inventory revisions 1 to 3, one entity, five
corpus items, five packets), apart from the production stores in `data/`.
Revision 3 is `weksa::daodejing::revision()`; the packets are
`weksa::daodejing::packets()`. The scene revision (`scene_revision()`, also
numbered 3) is not applied in these stores and will need renumbering when it
is applied anywhere both meet.
- Rebuild: `weksa --corpus C --inventory I --entities E` with `inventory seed`,
`inventory proof`, `inventory dao`, `entity put entity:laozi ...`,
`corpus add ... --source public-domain` per item, then `packet dao <store>`.
- Source: Project Gutenberg eBook 216, "The Tao Teh King, or the Tao and its
Characteristics", Laozi, tr. James Legge (Sacred Books of the East 39, 1891).
Gutenberg's licence (1.E.2) lets a work derived from texts not protected by US
copyright be used with no fee provided every Project Gutenberg reference is
removed from the work. The items hold only Legge's words, one numbered section
or sentence each; no Gutenberg header, licence text or trademark is stored,
and the eBook file itself is not committed. `edition_url` names the page the
text was retrieved from, as a citation of provenance and not as part of any
item's text. The legal-root question of whether a citation counts as a
"reference" is not ruled; if Gutenberg says it does, the field moves to the
Sacred Books of the East print edition.
- `Source::PublicDomain` now carries `licence`, `jurisdiction`, `translator` and
`edition_year`, and the store refuses an item missing any of them (an empty
string, or year 0).
## The slice
Corpus groups are chapters, so the derived split spreads the slice:
| item | Legge | split |
|---|---|---|
| `item:daodejing:1` | ch. 3 s. 2 | Train |
| `item:daodejing:2` | ch. 7 s. 1, first sentence | Validation |
| `item:daodejing:3` | ch. 8 s. 1, first sentence | Validation |
| `item:daodejing:4` | ch. 78 s. 4 | Test |
| `item:daodejing:5` | ch. 5 s. 2, first sentence | Test |
Each packet states neutral facts (referents, predications, a speech act) and a
stance (restraint 800 on all; affection 300 on the water likeness). The stance is
my reading of the sage's voice, not data.
## First closeness number
Scored with `weksa score` (chrF, and meaning as cosine under `qwen3-embedding:0.6b`
through the local Ollama), one lowered output against its own item.
| item | split | chrF | meaning | lowered |
|---|---|---|---|---|
| 1 | Train | 44.18 | 0.831 | The sage empties the minds. The sage fills the bellies. The sage weakens the wills. The sage strengthens the bones. |
| 2 | Validation | 82.12 | 0.976 | The heaven is long-enduring. The earth continues long. |
| 3 | Validation | 74.99 | 0.974 | The highest excellence is like the water. |
| 4 | Test | 82.50 | 0.949 | The words that are strictly true seem paradoxical. |
| 5 | Test | 75.99 | 0.894 | The space between heaven and earth may be compared to the bellows. |
Mean over the five: chrF 71.96, meaning 0.925. Mismatched baseline (each output
against the other four references, 20 pairs): chrF 14.1, meaning 0.458. So the
scorer separates the right reference from a wrong one by a wide margin; that is
all it shows here.
**Do not read 72 as a measure of the interlingua.** The five outputs are the
ceiling of an author who saw the reference:
- One author wrote the packets, the inventory entries and the lowerer rows with
Legge's sentence open. Frame 3 (`act`) was written from the Train item. Frames
4 and 5 came from Validation items and frames 6 and 7 from Test items, each
written while reading that item. The Train item, the only one lowered by a
frame minted from Train, scored lowest (chrF 44.18). The scores rise with
how bespoke the frame is, the reverse of generalisation. The Validation and
Test numbers measure the lowerer table, not what the interlingua can carry.
- n = 5, one translation as reference, one embedding model, no variance.
## What the scorer cannot see
- **Stance.** The stance features are in the packets and the lowerer does not
render them, so the number is blind to the packet's voice entirely. It would
not change if every stance were deleted.
- **Dropped meaning.** Item 5 is a negated rhetorical question ("May not ... be
compared"); the lowering is a plain statement with no question mark and no
"not". Item 1 loses "Therefore", "in the exercise of his government" and "their".
Item 4 loses "to be". chrF scores the overlap and cannot say that the speech
act changed. The embedding cosine of 0.894 for item 5 is not much lower than
for the statement-for-statement items.
- **Table defects it forgives.** "The heaven" and "the water" are wrong English
(the lowerer prefixes "the" to every referent and has no proper-noun,
mass-noun or entity rendering). chrF takes a small penalty only.
- **Register and meaning of the Chinese.** The packets were read off Legge's
English, not the Chinese, so this is a round trip English to interlingua to
English. It measures how well the packet kept Legge's wording, not whether Legge
or the packet is right about the Dao. The term "Tao" never appears in the slice.
The multi-reading term modelling Meta described is untested.
- **Leak.** `weksa score` scores the whole output against the whole reference
with no mask, as the leak ruling says. Nothing here enforces that the
author did not use the reference; only the labels above say so.
## What the run showed the interlingua needs
- Negation and question force: `polarity` is refused by the lowerer ("features")
and `ask` has no punctuation row, so two of Laozi's habitual moves, the negated
claim and the rhetorical question, cannot be lowered at all.
- A frame per sentence shape is the lowerer's cost model today: each new shape
is one more table row and one more inventory frame. The Dao's aphorisms are
mostly copular and paradoxical, which suggests the next frames to mint
(attribution, contrast, negated identity) before more chapters are added.

View file

@ -170,6 +170,7 @@
]
},
{
"description": "A public-domain work, with everything a reader needs to check the claim:\nthe edition's licence and the jurisdiction the public-domain status is\nasserted in, who translated it (the translation is the text's copyright,\nnot the original's) and when the edition appeared. A work missing any\nis refused at admission.",
"type": "object",
"properties": {
"PublicDomain": {
@ -181,6 +182,21 @@
"edition_url": {
"type": "string"
},
"edition_year": {
"type": "integer",
"format": "uint16",
"maximum": 65535,
"minimum": 0
},
"jurisdiction": {
"type": "string"
},
"licence": {
"type": "string"
},
"translator": {
"type": "string"
},
"work": {
"type": "string"
}
@ -188,7 +204,11 @@
"required": [
"work",
"author",
"edition_url"
"edition_url",
"licence",
"jurisdiction",
"translator",
"edition_year"
]
}
},