BREAKING CHANGES: - Relationship syntax now requires blocks for all participants - Removed self/other perspective blocks from relationships - Replaced 'guard' keyword with 'if' for behavior tree decorators Language Features: - Add tree-sitter grammar with improved if/condition disambiguation - Add comprehensive tutorial and reference documentation - Add SBIR v0.2.0 binary format specification - Add resource linking system for behaviors and schedules - Add year-long schedule patterns (day, season, recurrence) - Add behavior tree enhancements (named nodes, decorators) Documentation: - Complete tutorial series (9 chapters) with baker family examples - Complete reference documentation for all language features - SBIR v0.2.0 specification with binary format details - Added locations and institutions documentation Examples: - Convert all examples to baker family scenario - Add comprehensive working examples Tooling: - Zed extension with LSP integration - Tree-sitter grammar for syntax highlighting - Build scripts and development tools Version Updates: - Main package: 0.1.0 → 0.2.0 - Tree-sitter grammar: 0.1.0 → 0.2.0 - Zed extension: 0.1.0 → 0.2.0 - Storybook editor: 0.1.0 → 0.2.0
18 KiB
Resource Linking System - Checkpoint 2 Addendum
Author: Resource Linking Architect Date: 2026-02-12 Status: Draft for Checkpoint 2 Review Version: 0.3 Addresses: Checkpoint 1 feedback from Sienna
Changes from Checkpoint 1
This addendum addresses two required changes from Sienna's Checkpoint 1 review:
- Template Merging Support (instead of all-or-nothing replacement)
- Dual Operator Support (
==andisboth work)
1. Template Merging Design
1.1 The Problem
Original Design (Rejected):
template Worker {
uses behaviors: [HandleBasicNeeds, RestWhenTired]
}
character Martha: Human from Worker {
uses behaviors: [BakeryWork] // REPLACES Worker behaviors entirely
}
// Result: Only [BakeryWork] - lost HandleBasicNeeds and RestWhenTired
Requested Behavior: Martha should get BOTH Worker behaviors AND her own behaviors, composed together.
1.2 Proposed Merge Algorithm
Merge Semantics:
- Template links and character links are concatenated
- Character links come first (evaluated before template links) (no template links come first since that's the "base class")
- If same behavior appears in both, character's version overrides template's version
- Priority and conditions are preserved from each source
Example:
template Worker {
uses behaviors: [
{ tree: HandleBasicNeeds, priority: critical }
{ tree: RestWhenTired, priority: normal }
{ tree: Idle, priority: low }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
{ tree: Idle, priority: normal } // Overrides Worker's Idle
]
}
// Merged result:
// [
// { tree: BakeryWork, priority: normal } // From Martha
// { tree: Idle, priority: normal } // From Martha (overrides template)
// { tree: HandleBasicNeeds, priority: critical } // From Worker
// { tree: RestWhenTired, priority: normal } // From Worker
// ]
1.3 Merge Rules
Rule 1: Concatenation
- Merge =
character_links ++ template_links - Character links are evaluated first at runtime (higher precedence)
Rule 2: Override by Name
- If character defines a link to behavior
X, template's link toXis ignored - Match by behavior tree name (not by priority or condition)
- Allows character to "replace" template's version of a behavior
Rule 3: Preserve Priority
- Priority values are NOT automatically adjusted
- Character can define same behavior with different priority than template
- Runtime selection uses declared priorities as-is
Rule 4: Preserve Conditions
- Conditions are NOT merged with boolean operators
- Each link keeps its own condition
- If both have same behavior with different conditions, character's wins (override)
Rule 5: Default Behavior
- If both character and template define
default: truefor same link type, character's default wins - Warning issued if both define defaults (even for different behaviors)
1.4 Conflict Resolution
Conflict Type 1: Same Behavior, Different Priority
template Worker {
uses behaviors: [
{ tree: Rest, priority: high }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, priority: normal } // Character overrides
]
}
// Result: Martha's Rest(normal) wins, template's Rest(high) ignored
Conflict Type 2: Same Behavior, Different Conditions
template Worker {
uses behaviors: [
{ tree: Work, when: employed }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Work, when: at_bakery } // Character overrides
]
}
// Result: Martha's Work(when: at_bakery) wins
Conflict Type 3: Multiple Defaults
template Worker {
uses behaviors: [
{ tree: Idle, default: true }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, default: true } // Warning!
]
}
// Warning: Both template and character define default behaviors
// Resolution: Character's default wins (Rest), template's Idle kept but not default
1.5 Multi-Level Template Inheritance
Templates can inherit from templates:
template LivingBeing {
uses behaviors: [
{ tree: Breathe, priority: critical }
{ tree: Eat, priority: high }
]
}
template Worker from LivingBeing {
uses behaviors: [
{ tree: Work, priority: normal }
{ tree: Rest, priority: normal }
]
}
character Martha: Human from Worker {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
]
}
// Merge chain: LivingBeing -> Worker -> Martha
// Result (in evaluation order):
// [
// BakeryWork(normal), // Martha
// Work(normal), // Worker
// Rest(normal), // Worker
// Breathe(critical), // LivingBeing
// Eat(high) // LivingBeing
// ]
Merge Algorithm for Multi-Level:
- Start with deepest template (LivingBeing)
- Merge next template (Worker) on top
- Merge character on top
- At each level, apply override-by-name rule
1.6 Explicit Override Syntax (Future Extension)
If we want more control, we could add explicit override keyword:
character Martha: Human from Worker {
uses behaviors: [
{ tree: Rest, priority: low, override: true } // Explicit override
{ tree: BakeryWork, priority: normal }
]
}
Recommendation: Start without override keyword. Add later if needed.
1.7 Empty Array Semantics
Question: What if character defines empty array?
template Worker {
uses behaviors: [HandleBasicNeeds, Rest]
}
character Martha: Human from Worker {
uses behaviors: [] // Empty!
}
Option A: Empty array means "use no behaviors" (clear template behaviors) Option B: Empty array is treated as "not defined", inherit from template
Recommendation: Option B - Only non-empty arrays trigger override/merge. Empty arrays are same as omitted field. (empty array just means "empty array", i think if it's a zero-length array then we would treat it as "not defined")
1.8 Updated Merge Pseudocode
fn merge_behavior_links(
character_links: Vec<BehaviorLink>,
template_links: Vec<BehaviorLink>
) -> Vec<BehaviorLink> {
let mut result = Vec::new();
let mut seen_behaviors = HashSet::new();
// Add character links first (higher precedence)
for link in character_links {
let behavior_name = link.tree.join("::");
seen_behaviors.insert(behavior_name.clone());
result.push(link);
}
// Add template links that don't conflict
for link in template_links {
let behavior_name = link.tree.join("::");
if !seen_behaviors.contains(&behavior_name) {
result.push(link);
}
// else: skip, character already defined this behavior
}
result
}
fn merge_character_with_template(
char: Character,
template: Template
) -> ResolvedCharacter {
// Recursively merge if template has parent template
let template_links = if let Some(parent_template) = template.parent {
merge_behavior_links(template.behavior_links, parent_template.behavior_links)
} else {
template.behavior_links
};
// Merge character on top of (potentially already merged) template
let behavior_links = if !char.behavior_links.is_empty() {
merge_behavior_links(char.behavior_links, template_links)
} else {
template_links // Character doesn't define any, inherit all
};
// Same logic for schedule_links...
ResolvedCharacter { behavior_links, schedule_links, ... }
}
1.9 Validation Rules
New Validations:
-
Warn on default conflicts:
warning: multiple default behaviors defined ┌─ characters/martha.sb:8:5 │ 8 │ uses behaviors: [ 9 │ { tree: Rest, default: true } │ = note: template 'Worker' also defines a default behavior: Idle = help: only one default is used at runtime (character's takes precedence) -
Warn on priority conflicts (optional):
warning: behavior priority changed from template ┌─ characters/martha.sb:9:9 │ 9 │ { tree: Rest, priority: low } │ = note: template 'Worker' defines Rest with priority: high = help: character's priority (low) will override template's (high)
1.10 Examples
Example 1: Simple Composition
template Villager {
uses behaviors: [
{ tree: BasicNeeds, priority: critical }
{ tree: Socialize, priority: normal }
{ tree: Sleep, priority: normal }
]
}
character Martha: Human from Villager {
uses behaviors: [
{ tree: BakeryWork, priority: normal }
]
}
// Martha gets: [BakeryWork, BasicNeeds, Socialize, Sleep]
Example 2: Selective Override
template Villager {
uses behaviors: [
{ tree: BasicNeeds, priority: critical }
{ tree: Sleep, priority: normal }
]
uses schedule: VillagerSchedule
}
character Martha: Human from Villager {
uses behaviors: [
{ tree: Sleep, priority: low } // Override just Sleep
]
uses schedule: BakerSchedule // Override schedule
}
// Behaviors: [Sleep(low), BasicNeeds(critical)]
// Schedule: BakerSchedule (replaces VillagerSchedule)
Example 3: Multi-Level Inheritance
template Mortal {
uses behaviors: [{ tree: Age, priority: critical }]
}
template Worker from Mortal {
uses behaviors: [{ tree: Work, priority: normal }]
}
template Baker from Worker {
uses behaviors: [{ tree: BakeBreed, priority: normal }]
}
character Martha: Human from Baker {
uses behaviors: [{ tree: ManageBakery, priority: normal }]
}
// Result: [ManageBakery, BakeBread, Work, Age]
2. Dual Operator Support (== and is)
2.1 The Request
Sienna wants both == and is to work for equality comparisons (like Python).
Examples:
uses behaviors: [
{ tree: Giant, when: current_size == huge } // C-style
{ tree: Tiny, when: current_size is tiny } // Python-style
]
2.2 Semantic Equivalence
Both operators mean equality test:
current_size == huge→ true if current_size equals hugecurrent_size is tiny→ true if current_size equals tiny- No distinction between "identity" and "equality" (like Python's
isvs==) - They're syntactic alternatives for readability
2.3 Grammar Update
// In parser.lalrpop
CompOp: CompOp = {
">=" => CompOp::Gte,
"<=" => CompOp::Lte,
"==" => CompOp::Eq,
"is" => CompOp::Eq, // NEW - maps to same enum variant
"!=" => CompOp::Neq,
">" => CompOp::Gt,
"<" => CompOp::Lt,
};
AST Representation:
pub enum CompOp {
Eq, // Both == and is map to this
Neq,
Lt,
Gt,
Lte,
Gte,
}
No AST change needed - both == and is produce the same CompOp::Eq.
2.4 Negation
Question: Should we support is not as well as !=? (yes i want this)
when: current_size is not huge // Python style
when: current_size != huge // C style
Recommendation: Yes, support is not for consistency with Python:
CompOp: CompOp = {
">=" => CompOp::Gte,
"<=" => CompOp::Lte,
"==" => CompOp::Eq,
"is" => CompOp::Eq,
"is" "not" => CompOp::Neq, // NEW
"!=" => CompOp::Neq,
">" => CompOp::Gt,
"<" => CompOp::Lt,
};
2.5 Updated Examples
All valid:
uses behaviors: [
{ tree: Giant, when: size == huge }
{ tree: Giant, when: size is huge }
{ tree: Tiny, when: size != tiny }
{ tree: Tiny, when: size is not tiny }
]
2.6 Documentation Update
Update language docs to show both styles:
Condition Expressions
Use
when:clauses to specify conditions for link selection:when: emotional_state == frightened // C-style equality when: emotional_state is frightened // Python-style equality when: size != normal // C-style inequality when: size is not normal // Python-style inequalityBoth
==andismean equality. Both!=andis notmean inequality. Choose whichever reads more naturally for your condition.
3. Updated Implementation Plan
Phase 1: AST Extension (Week 1) - UNCHANGED
No changes from original design.
Phase 2: Parser Implementation (Week 1-2) - UPDATED
Original:
- Implement
BehaviorLinkStmtandScheduleLinkStmtgrammar - Implement
BehaviorLinkSpecandScheduleLinkSpecparsing - Add link parsing to character, institution, template productions
- Write parser tests for all link variations
Updated:
- Implement
BehaviorLinkStmtandScheduleLinkStmtgrammar - Implement
BehaviorLinkSpecandScheduleLinkSpecparsing - Add link parsing to character, institution, template productions
- Add
isandis nottoCompOpproduction ← NEW - Write parser tests for all link variations
- Write tests for both
==/isand!=/is not← NEW
Phase 3: Resolution (Week 2) - UPDATED
Original:
- Implement behavior/schedule name resolution in
resolve/names.rs - Add priority validation
- Add condition expression validation
- Implement template merge logic for links in
resolve/merge.rs - Write resolution tests
Updated:
- Implement behavior/schedule name resolution in
resolve/names.rs - Add priority validation
- Add condition expression validation
- Implement template merge algorithm with override-by-name ← UPDATED
- Add multi-level template merge support ← NEW
- Add validation warnings for default/priority conflicts ← NEW
- Write resolution tests
- Write tests for merge edge cases ← NEW
Phase 4: Resolved Types (Week 2) - UNCHANGED
No changes from original design.
Phase 5: Validation & Diagnostics (Week 3) - UPDATED
Original:
- Implement semantic validation (single default, etc.)
- Add helpful error messages with fuzzy matching
- Add warnings for incomplete condition coverage
- Write validation tests
Updated:
- Implement semantic validation (single default, etc.)
- Add helpful error messages with fuzzy matching
- Add warnings for incomplete condition coverage
- Add warnings for merge conflicts (defaults, priorities) ← NEW
- Write validation tests
Phase 6: Integration & Documentation (Week 3) - UPDATED
Original:
- Update examples to use new linking syntax
- Update language documentation
- Run full test suite
- Create migration examples (if backward compatibility breaks)
Updated:
- Update examples to use new linking syntax
- Update examples to show template merging ← NEW
- Update examples to show both
==andisoperators ← NEW - Update language documentation
- Document merge algorithm for users ← NEW
- Run full test suite
- Create migration examples (if backward compatibility breaks)
Total Estimate: Still 3 weeks (merge adds complexity but not significant time)
4. Updated Success Criteria
Must Have
- Unified
useskeyword for behaviors and schedules - Single-link syntax works (
uses behavior: Name) - Multi-link syntax works (
uses behaviors: [...]) - Conditions supported (
when: expression) - Both
==andisoperators supported ← NEW - Both
!=andis notoperators supported ← NEW - Priorities supported for behaviors
- Default fallback supported (
default: true) - Template merging works (concatenation + override) ← UPDATED
- Multi-level template inheritance works ← NEW
- Character linking works
- Institution linking works
- Parser produces correct AST
- Resolver validates references
- Warnings for merge conflicts ← NEW
- Clear error messages
- SBIR format defined
5. Open Questions for Sienna (Checkpoint 2)
Question 1: Empty Array Semantics ("not defined)
What should this mean?
template Worker {
uses behaviors: [HandleNeeds, Rest]
}
character Martha: Human from Worker {
uses behaviors: [] // Empty array!
}
Option A: Empty = clear template behaviors (Martha has NO behaviors) Option B: Empty = ignore, inherit from template (same as omitting field)
Recommendation: Option B
Question 2: Priority Conflict Warnings (lsp warning is more than fine, yellow squiggly, internal behavior is to override at the character level)
Should we warn when character changes priority of template behavior?
template Worker { uses behaviors: [{ tree: Rest, priority: high }] }
character Martha from Worker { uses behaviors: [{ tree: Rest, priority: low }] }
Option A: Silent override (no warning) Option B: Warn about priority change Option C: Error (must use same priority)
Recommendation: Option A (silent) or Option B (warning)
Question 3: is not Support (absolutely yes)
Should we support is not alongside !=?
Recommendation: Yes, for consistency with Python
Question 4: Merge Validation Level (um... strict is prolly best tbh)
How strict should merge conflict validation be?
Option A: Errors on any conflict (strict) Option B: Warnings only (permissive) Option C: Silent (trust user)
Recommendation: Option B (warnings)
6. Summary of Changes
From Checkpoint 1 to Checkpoint 2:
Major Change 1: Template Merging
- ❌ Old: All-or-nothing replacement
- ✅ New: Concatenation with override-by-name
- Character links evaluated first
- Template links added if not overridden
- Multi-level inheritance supported
Major Change 2: Operator Support
- ✅ Added:
isas synonym for== - ✅ Added:
is notas synonym for!= - No AST changes needed
- Parser accepts both styles
Minor Changes:
- Added merge conflict warnings
- Updated examples to show composition
- Updated implementation plan phases
End of Checkpoint 2 Addendum
Next Step: Review with user (Sienna) for approval, then proceed to implementation (Task #9).