Skip to content

Commit 58cce20

Browse files
committed
feat(grammar): populate all 12 VerbFamily rows in default_table()
Seed TEKAMOLO slot priors for the 10 VerbFamily variants that were using uniform defaults (Supports, Contradicts, Refines, Grounds, Abstracts, Enables, Prevents, Transforms, Mirrors, Dissolves). Priors applied across all 12 Tense variants per family (144 cells). Semantic profiles per grammar-landscape.md S3: - Action verbs (Causes, Prevents, Transforms): high Kausal + Temporal - State verbs (Supports, Contradicts, Refines, Grounds): high Modal - Change verbs (Becomes, Abstracts, Mirrors, Dissolves): high Temporal + Modal - Discovery verbs (Enables): high Kausal + Lokal Also adds Tense::ALL const array and 13 new tests (one per family plus a sweep test). Total verb_table tests: 16. Contract suite: 319. Starter values -- tune empirically with corpus statistics. https://claude.ai/code/session_01NYGrxVopyszZYgLBxe4hgj
1 parent 77c6292 commit 58cce20

2 files changed

Lines changed: 245 additions & 19 deletions

File tree

crates/lance-graph-contract/src/grammar/role_keys.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,15 @@ pub enum Tense {
231231
Imperative = 11,
232232
}
233233

234+
impl Tense {
235+
pub const ALL: [Self; 12] = [
236+
Self::Present, Self::Past, Self::Future,
237+
Self::PresentContinuous, Self::PastContinuous, Self::FutureContinuous,
238+
Self::Perfect, Self::Pluperfect, Self::FuturePerfect,
239+
Self::Habitual, Self::Potential, Self::Imperative,
240+
];
241+
}
242+
234243
const TENSE_START: usize = 9910;
235244
#[allow(dead_code)]
236245
const TENSE_END: usize = 9970;

crates/lance-graph-contract/src/grammar/verb_table.rs

Lines changed: 236 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
//! 144-cell verb-role lookup table 12 semantic families × 12 tense/aspect/mood.
1+
//! 144-cell verb-role lookup table — 12 semantic families × 12 tense/aspect/mood.
22
//!
33
//! Each cell holds a TEKAMOLO slot prior: which slots a verb of this family
4-
//! and tense expects to be filled. Parsing reduces to (family, tense)
5-
//! row fill slots from morphology NARS-revise truth.
4+
//! and tense expects to be filled. Parsing reduces to (family, tense) →
5+
//! row → fill slots from morphology → NARS-revise truth.
66
//!
7-
//! Currently uniform priors; future PR populates from corpus statistics.
7+
//! Slot priors seeded from grammar-landscape.md §3 TEKAMOLO semantics.
8+
//! Starter values — tune empirically with corpus statistics.
89
//!
9-
//! See PR #279 outlook E3 + grammar-landscape.md §9.
10+
//! See PR #279 outlook E3 + grammar-landscape.md §9.
1011
//!
1112
//! META-AGENT: `pub mod verb_table;` to mod.rs.
1213
1314
use crate::grammar::role_keys::Tense;
1415

1516
/// Twelve top-level semantic families. The naming is deliberately
1617
/// process-oriented (verbs as transformations on configurations of
17-
/// the world) rather than syntax-oriented these are the "roles a
18+
/// the world) rather than syntax-oriented — these are the "roles a
1819
/// predicate plays" that disambiguate which TEKAMOLO slots get filled.
1920
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2021
pub enum VerbFamily {
@@ -66,24 +67,109 @@ impl VerbRoleTable {
6667
}
6768
}
6869

69-
/// Default table with hand-set families per the plan's table:
70-
/// BECOMES → Temporal + Modal high
71-
/// CAUSES → Subject + Object + Kausal high
72-
/// ...
70+
/// Default table with hand-set families per the plan's table and
71+
/// grammar-landscape.md §3 TEKAMOLO slot semantics.
7372
///
74-
/// Currently a starter — only a few cells are seeded; uniform fills the
75-
/// rest. The numbers are *priors*, not facts: a future PR replaces them
76-
/// with corpus-derived statistics. Mark this `// starter — tune empirically`
73+
/// Semantic profiles — starter — tune empirically:
74+
/// BECOMES → Change verb: high Temporal + Modal
75+
/// CAUSES → Action verb: high Kausal + Instrument
76+
/// SUPPORTS → State verb: high Modal, low Temporal
77+
/// CONTRADICTS → State verb: high Modal + Kausal
78+
/// REFINES → State verb: high Modal, moderate Kausal
79+
/// GROUNDS → State verb: high Lokal + Modal
80+
/// ABSTRACTS → Change verb: high Modal + Temporal
81+
/// ENABLES → Discovery verb: high Kausal + Lokal
82+
/// PREVENTS → Action verb: high Kausal + Temporal
83+
/// TRANSFORMS → Action verb: high Kausal + Temporal + Instrument
84+
/// MIRRORS → Change verb: high Temporal + Modal + Lokal
85+
/// DISSOLVES → Change verb: high Temporal + Modal
86+
///
87+
/// The numbers are *priors*, not facts: a future PR replaces them
88+
/// with corpus-derived statistics. Mark this `// starter — tune empirically`
7789
/// in any consumer that depends on specific values.
7890
pub fn default_table() -> VerbRoleTable {
7991
let mut t = VerbRoleTable::new_uniform();
80-
let high = SlotPrior { temporal: 0.9, kausal: 0.2, modal: 0.7, lokal: 0.3, instrument: 0.2 };
92+
93+
// --- Change verbs: high Temporal + Modal ---
94+
95+
// BECOMES: state-change, strongly temporal + modal
96+
let becomes = SlotPrior { temporal: 0.9, kausal: 0.2, modal: 0.7, lokal: 0.3, instrument: 0.2 };
97+
for tense in Tense::ALL {
98+
t.set(VerbFamily::Becomes, tense, becomes);
99+
}
100+
101+
// DISSOLVES: destruction-as-change, high temporal + modal
102+
let dissolves = SlotPrior { temporal: 0.85, kausal: 0.3, modal: 0.7, lokal: 0.25, instrument: 0.2 };
103+
for tense in Tense::ALL {
104+
t.set(VerbFamily::Dissolves, tense, dissolves);
105+
}
106+
107+
// ABSTRACTS: conceptual transformation, high modal + temporal
108+
let abstracts = SlotPrior { temporal: 0.7, kausal: 0.25, modal: 0.85, lokal: 0.15, instrument: 0.2 };
109+
for tense in Tense::ALL {
110+
t.set(VerbFamily::Abstracts, tense, abstracts);
111+
}
112+
113+
// MIRRORS: reflection/symmetry, temporal + modal + lokal
114+
let mirrors = SlotPrior { temporal: 0.75, kausal: 0.2, modal: 0.7, lokal: 0.6, instrument: 0.15 };
115+
for tense in Tense::ALL {
116+
t.set(VerbFamily::Mirrors, tense, mirrors);
117+
}
118+
119+
// --- Action verbs: high Kausal + Temporal ---
120+
121+
// CAUSES: strong causal agency, high kausal + instrument
81122
let causes = SlotPrior { temporal: 0.4, kausal: 0.95, modal: 0.4, lokal: 0.3, instrument: 0.5 };
82-
// populate per the plan's family table; mark "starter — tune empirically"
83-
// ... apply for each (family, tense) combination ...
84-
t.set(VerbFamily::Becomes, Tense::Present, high);
85-
t.set(VerbFamily::Causes, Tense::Present, causes);
86-
// (etc — only seed a few; uniform fills the rest)
123+
for tense in Tense::ALL {
124+
t.set(VerbFamily::Causes, tense, causes);
125+
}
126+
127+
// PREVENTS: blocking action, high kausal + temporal
128+
let prevents = SlotPrior { temporal: 0.7, kausal: 0.9, modal: 0.4, lokal: 0.25, instrument: 0.35 };
129+
for tense in Tense::ALL {
130+
t.set(VerbFamily::Prevents, tense, prevents);
131+
}
132+
133+
// TRANSFORMS: active change, high kausal + temporal + instrument
134+
let transforms = SlotPrior { temporal: 0.8, kausal: 0.85, modal: 0.35, lokal: 0.3, instrument: 0.6 };
135+
for tense in Tense::ALL {
136+
t.set(VerbFamily::Transforms, tense, transforms);
137+
}
138+
139+
// --- State verbs: high Modal, low Temporal ---
140+
141+
// SUPPORTS: epistemic backing, high modal
142+
let supports = SlotPrior { temporal: 0.2, kausal: 0.35, modal: 0.85, lokal: 0.2, instrument: 0.3 };
143+
for tense in Tense::ALL {
144+
t.set(VerbFamily::Supports, tense, supports);
145+
}
146+
147+
// CONTRADICTS: logical opposition, high modal + kausal
148+
let contradicts = SlotPrior { temporal: 0.15, kausal: 0.7, modal: 0.9, lokal: 0.15, instrument: 0.1 };
149+
for tense in Tense::ALL {
150+
t.set(VerbFamily::Contradicts, tense, contradicts);
151+
}
152+
153+
// REFINES: iterative improvement, high modal, moderate kausal
154+
let refines = SlotPrior { temporal: 0.3, kausal: 0.4, modal: 0.8, lokal: 0.2, instrument: 0.35 };
155+
for tense in Tense::ALL {
156+
t.set(VerbFamily::Refines, tense, refines);
157+
}
158+
159+
// GROUNDS: anchoring to context, high lokal + modal
160+
let grounds = SlotPrior { temporal: 0.25, kausal: 0.3, modal: 0.75, lokal: 0.85, instrument: 0.2 };
161+
for tense in Tense::ALL {
162+
t.set(VerbFamily::Grounds, tense, grounds);
163+
}
164+
165+
// --- Discovery/enablement verbs: high Kausal + Lokal ---
166+
167+
// ENABLES: facilitation, high kausal + lokal
168+
let enables = SlotPrior { temporal: 0.35, kausal: 0.8, modal: 0.4, lokal: 0.7, instrument: 0.45 };
169+
for tense in Tense::ALL {
170+
t.set(VerbFamily::Enables, tense, enables);
171+
}
172+
87173
t
88174
}
89175

@@ -117,4 +203,135 @@ mod tests {
117203
let p = t.lookup(VerbFamily::Causes, Tense::Present);
118204
assert!(p.kausal > 0.8);
119205
}
206+
207+
// --- Per-family tests: verify priors are non-zero for at least 2 TEKAMOLO slots ---
208+
209+
/// Helper: count slots that are non-uniform (differ from 0.5 by > 0.05).
210+
fn count_non_uniform(p: &SlotPrior) -> usize {
211+
let slots = [p.temporal, p.kausal, p.modal, p.lokal, p.instrument];
212+
slots.iter().filter(|&&v| (v - 0.5).abs() > 0.05).count()
213+
}
214+
215+
#[test]
216+
fn becomes_change_verb_temporal_modal() {
217+
let t = default_table();
218+
let p = t.lookup(VerbFamily::Becomes, Tense::Present);
219+
assert!(p.temporal > 0.7, "Becomes should have high temporal");
220+
assert!(p.modal > 0.6, "Becomes should have high modal");
221+
assert!(count_non_uniform(&p) >= 2);
222+
}
223+
224+
#[test]
225+
fn causes_action_verb_kausal_instrument() {
226+
let t = default_table();
227+
let p = t.lookup(VerbFamily::Causes, Tense::Past);
228+
assert!(p.kausal > 0.8, "Causes should have high kausal");
229+
assert!(p.instrument > 0.4, "Causes should have elevated instrument");
230+
assert!(count_non_uniform(&p) >= 2);
231+
}
232+
233+
#[test]
234+
fn supports_state_verb_modal_high() {
235+
let t = default_table();
236+
let p = t.lookup(VerbFamily::Supports, Tense::Present);
237+
assert!(p.modal > 0.7, "Supports should have high modal");
238+
assert!(p.temporal < 0.4, "Supports should have low temporal");
239+
assert!(count_non_uniform(&p) >= 2);
240+
}
241+
242+
#[test]
243+
fn contradicts_state_verb_modal_kausal() {
244+
let t = default_table();
245+
let p = t.lookup(VerbFamily::Contradicts, Tense::Future);
246+
assert!(p.modal > 0.8, "Contradicts should have high modal");
247+
assert!(p.kausal > 0.6, "Contradicts should have elevated kausal");
248+
assert!(count_non_uniform(&p) >= 2);
249+
}
250+
251+
#[test]
252+
fn refines_state_verb_modal() {
253+
let t = default_table();
254+
let p = t.lookup(VerbFamily::Refines, Tense::Perfect);
255+
assert!(p.modal > 0.7, "Refines should have high modal");
256+
assert!(p.temporal < 0.4, "Refines should have low temporal");
257+
assert!(count_non_uniform(&p) >= 2);
258+
}
259+
260+
#[test]
261+
fn grounds_state_verb_lokal_modal() {
262+
let t = default_table();
263+
let p = t.lookup(VerbFamily::Grounds, Tense::Habitual);
264+
assert!(p.lokal > 0.7, "Grounds should have high lokal");
265+
assert!(p.modal > 0.6, "Grounds should have elevated modal");
266+
assert!(count_non_uniform(&p) >= 2);
267+
}
268+
269+
#[test]
270+
fn abstracts_change_verb_modal_temporal() {
271+
let t = default_table();
272+
let p = t.lookup(VerbFamily::Abstracts, Tense::PresentContinuous);
273+
assert!(p.modal > 0.7, "Abstracts should have high modal");
274+
assert!(p.temporal > 0.6, "Abstracts should have elevated temporal");
275+
assert!(count_non_uniform(&p) >= 2);
276+
}
277+
278+
#[test]
279+
fn enables_discovery_verb_kausal_lokal() {
280+
let t = default_table();
281+
let p = t.lookup(VerbFamily::Enables, Tense::Potential);
282+
assert!(p.kausal > 0.7, "Enables should have high kausal");
283+
assert!(p.lokal > 0.6, "Enables should have elevated lokal");
284+
assert!(count_non_uniform(&p) >= 2);
285+
}
286+
287+
#[test]
288+
fn prevents_action_verb_kausal_temporal() {
289+
let t = default_table();
290+
let p = t.lookup(VerbFamily::Prevents, Tense::Past);
291+
assert!(p.kausal > 0.8, "Prevents should have high kausal");
292+
assert!(p.temporal > 0.6, "Prevents should have elevated temporal");
293+
assert!(count_non_uniform(&p) >= 2);
294+
}
295+
296+
#[test]
297+
fn transforms_action_verb_kausal_temporal_instrument() {
298+
let t = default_table();
299+
let p = t.lookup(VerbFamily::Transforms, Tense::FuturePerfect);
300+
assert!(p.kausal > 0.7, "Transforms should have high kausal");
301+
assert!(p.temporal > 0.7, "Transforms should have high temporal");
302+
assert!(p.instrument > 0.5, "Transforms should have elevated instrument");
303+
assert!(count_non_uniform(&p) >= 3);
304+
}
305+
306+
#[test]
307+
fn mirrors_change_verb_temporal_modal_lokal() {
308+
let t = default_table();
309+
let p = t.lookup(VerbFamily::Mirrors, Tense::Pluperfect);
310+
assert!(p.temporal > 0.6, "Mirrors should have elevated temporal");
311+
assert!(p.modal > 0.6, "Mirrors should have elevated modal");
312+
assert!(p.lokal > 0.5, "Mirrors should have elevated lokal");
313+
assert!(count_non_uniform(&p) >= 2);
314+
}
315+
316+
#[test]
317+
fn dissolves_change_verb_temporal_modal() {
318+
let t = default_table();
319+
let p = t.lookup(VerbFamily::Dissolves, Tense::Imperative);
320+
assert!(p.temporal > 0.7, "Dissolves should have high temporal");
321+
assert!(p.modal > 0.6, "Dissolves should have elevated modal");
322+
assert!(count_non_uniform(&p) >= 2);
323+
}
324+
325+
#[test]
326+
fn all_families_have_non_uniform_priors() {
327+
let t = default_table();
328+
for family in VerbFamily::ALL {
329+
let p = t.lookup(family, Tense::Present);
330+
assert!(
331+
count_non_uniform(&p) >= 2,
332+
"{:?} should have at least 2 non-uniform TEKAMOLO slots",
333+
family
334+
);
335+
}
336+
}
120337
}

0 commit comments

Comments
 (0)