# 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:

1. **Template Merging Support** (instead of all-or-nothing replacement)
2. **Dual Operator Support** (`==` and `is` both work)

---

## 1. Template Merging Design

### 1.1 The Problem

**Original Design (Rejected):**
```storybook
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:**
```storybook
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 to `X` is 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: true` for 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**
```storybook
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**
```storybook
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**
```storybook
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:

```storybook
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:**
1. Start with deepest template (LivingBeing)
2. Merge next template (Worker) on top
3. Merge character on top
4. 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:

```storybook
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?

```storybook
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

```rust
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:**

1. **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)
   ```

2. **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**
```storybook
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**
```storybook
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**
```storybook
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:**
```storybook
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 huge
- `current_size is tiny` → true if current_size equals tiny
- No distinction between "identity" and "equality" (like Python's `is` vs `==`)
- They're syntactic alternatives for readability

### 2.3 Grammar Update

```lalrpop
// 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:**
```rust
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)

```storybook
when: current_size is not huge      // Python style
when: current_size != huge          // C style
```

**Recommendation:** **Yes**, support `is not` for consistency with Python:

```lalrpop
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:**
```storybook
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:
>
> ```storybook
> 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 inequality
> ```
>
> Both `==` and `is` mean equality. Both `!=` and `is not` mean 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:**
1. Implement `BehaviorLinkStmt` and `ScheduleLinkStmt` grammar
2. Implement `BehaviorLinkSpec` and `ScheduleLinkSpec` parsing
3. Add link parsing to character, institution, template productions
4. Write parser tests for all link variations

**Updated:**
1. Implement `BehaviorLinkStmt` and `ScheduleLinkStmt` grammar
2. Implement `BehaviorLinkSpec` and `ScheduleLinkSpec` parsing
3. Add link parsing to character, institution, template productions
4. **Add `is` and `is not` to `CompOp` production** ← NEW
5. Write parser tests for all link variations
6. **Write tests for both `==`/`is` and `!=`/`is not`** ← NEW

### Phase 3: Resolution (Week 2) - UPDATED

**Original:**
1. Implement behavior/schedule name resolution in `resolve/names.rs`
2. Add priority validation
3. Add condition expression validation
4. Implement template merge logic for links in `resolve/merge.rs`
5. Write resolution tests

**Updated:**
1. Implement behavior/schedule name resolution in `resolve/names.rs`
2. Add priority validation
3. Add condition expression validation
4. **Implement template merge algorithm with override-by-name** ← UPDATED
5. **Add multi-level template merge support** ← NEW
6. **Add validation warnings for default/priority conflicts** ← NEW
7. Write resolution tests
8. **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:**
1. Implement semantic validation (single default, etc.)
2. Add helpful error messages with fuzzy matching
3. Add warnings for incomplete condition coverage
4. Write validation tests

**Updated:**
1. Implement semantic validation (single default, etc.)
2. Add helpful error messages with fuzzy matching
3. Add warnings for incomplete condition coverage
4. **Add warnings for merge conflicts (defaults, priorities)** ← NEW
5. Write validation tests

### Phase 6: Integration & Documentation (Week 3) - UPDATED

**Original:**
1. Update examples to use new linking syntax
2. Update language documentation
3. Run full test suite
4. Create migration examples (if backward compatibility breaks)

**Updated:**
1. Update examples to use new linking syntax
2. **Update examples to show template merging** ← NEW
3. **Update examples to show both `==` and `is` operators** ← NEW
4. Update language documentation
5. **Document merge algorithm for users** ← NEW
6. Run full test suite
7. 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
- [x] Unified `uses` keyword for behaviors and schedules
- [x] Single-link syntax works (`uses behavior: Name`)
- [x] Multi-link syntax works (`uses behaviors: [...]`)
- [x] Conditions supported (`when: expression`)
- [x] **Both `==` and `is` operators supported** ← NEW
- [x] **Both `!=` and `is not` operators supported** ← NEW
- [x] Priorities supported for behaviors
- [x] Default fallback supported (`default: true`)
- [x] **Template merging works (concatenation + override)** ← UPDATED
- [x] **Multi-level template inheritance works** ← NEW
- [x] Character linking works
- [x] Institution linking works
- [x] Parser produces correct AST
- [x] Resolver validates references
- [x] **Warnings for merge conflicts** ← NEW
- [x] Clear error messages
- [x] SBIR format defined

---

## 5. Open Questions for Sienna (Checkpoint 2)

### Question 1: Empty Array Semantics ("not defined)

What should this mean?
```storybook
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?

```storybook
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: `is` as synonym for `==`
- ✅ Added: `is not` as 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).
