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
659 lines
18 KiB
Markdown
659 lines
18 KiB
Markdown
# 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).
|