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
1017 lines
26 KiB
Markdown
1017 lines
26 KiB
Markdown
# Year-Long Composable Schedule System Design
|
|
**Author:** Resource Linking Architect (Schedule System Designer)
|
|
**Date:** 2026-02-12
|
|
**Status:** Draft for Review
|
|
**Version:** 0.1
|
|
**Related:** Resource Linking System Design (Task #8)
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
This document proposes a **year-long, composable schedule system** for the Storybook DSL that extends the current simple daily schedules to support:
|
|
|
|
- **Temporal composition**: Days → Weeks → Months → Seasons → Year
|
|
- **Template inheritance**: Schedules extend and override like behavior templates
|
|
- **Seasonal variations**: Winter/summer hours, holiday schedules
|
|
- **Event overrides**: Special occasions, one-off modifications
|
|
- **Integration with resource linking**: Works seamlessly with `uses schedule:` syntax
|
|
|
|
The design enables both simple daily routines and complex year-long patterns while maintaining readability and composability.
|
|
|
|
---
|
|
|
|
## 1. Current State & Limitations
|
|
|
|
### 1.1 Existing Schedule Syntax
|
|
|
|
**Current (Simple Daily Schedule):**
|
|
```storybook
|
|
schedule MadTeaPartyRotation {
|
|
18:00 -> 18:01: TeaRound {
|
|
---narrative
|
|
Begin a new rotation...
|
|
---
|
|
}
|
|
18:01 -> 18:02: RiddlePhase { ... }
|
|
18:02 -> 18:03: ContradictionPhase { ... }
|
|
}
|
|
```
|
|
|
|
**Current AST:**
|
|
```rust
|
|
pub struct Schedule {
|
|
pub name: String,
|
|
pub blocks: Vec<ScheduleBlock>, // Flat list
|
|
pub span: Span,
|
|
}
|
|
|
|
pub struct ScheduleBlock {
|
|
pub start: Time, // HH:MM
|
|
pub end: Time, // HH:MM
|
|
pub activity: String,
|
|
pub fields: Vec<Field>,
|
|
pub span: Span,
|
|
}
|
|
```
|
|
|
|
### 1.2 Limitations
|
|
|
|
1. **No composition**: Can't build a weekly schedule from daily templates
|
|
2. **No inheritance**: Can't extend a base schedule and customize
|
|
3. **No temporal hierarchy**: Can't express "weekday vs weekend" patterns
|
|
4. **No seasonal variation**: Can't say "summer hours vs winter hours"
|
|
5. **No override system**: Can't modify specific blocks while keeping others
|
|
6. **No year-long support**: Limited to repeating daily patterns
|
|
|
|
### 1.3 Use Cases Not Supported
|
|
|
|
**Use Case 1: Seasonal Business Hours**
|
|
```
|
|
Bakery is open 6:00-20:00 in summer, 7:00-18:00 in winter
|
|
```
|
|
|
|
**Use Case 2: Weekday vs Weekend**
|
|
```
|
|
Martha works Monday-Friday, rests Saturday-Sunday
|
|
```
|
|
|
|
**Use Case 3: Holiday Override**
|
|
```
|
|
Martha follows BakerSchedule normally, but FullRest on Christmas
|
|
```
|
|
|
|
**Use Case 4: Life Arc Changes**
|
|
```
|
|
Martha's schedule changes when she becomes Elder (retires)
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Design Goals
|
|
|
|
### 2.1 Primary Goals
|
|
|
|
1. **Hierarchical Composition**: Build complex schedules from simple parts
|
|
2. **Template Inheritance**: Extend and customize like behavior templates
|
|
3. **Temporal Flexibility**: Express daily, weekly, seasonal, yearly patterns
|
|
4. **Override System**: Modify specific aspects while keeping others
|
|
5. **Backward Compatible**: Current simple schedules still work
|
|
6. **Integration**: Seamless with `uses schedule:` linking
|
|
|
|
### 2.2 Non-Goals
|
|
|
|
1. **Real-time scheduling**: Schedules are static patterns, not dynamic
|
|
2. **Calendar systems**: Focus on patterns, not specific date handling
|
|
3. **Time zones**: All times are game-world local
|
|
4. **Procedural generation**: Schedules are authored, not generated
|
|
|
|
---
|
|
|
|
## 3. Proposed Architecture
|
|
|
|
### 3.1 Time Hierarchy (yes, but i want to make this user-composable so they're not locked into gregorian, euro-centric calendars. idk how we would do that, but like Lonni wants 8 seasons... maybe the schedule constants (years/months/days/weeks/seasons/etc) can be configured in the storybook.toml? idk how to handle this)
|
|
|
|
```
|
|
Year (365 days)
|
|
├─ Season (Winter, Spring, Summer, Fall)
|
|
│ └─ Month (Jan, Feb, ..., Dec)
|
|
│ └─ Week (7-day cycle)
|
|
│ └─ Day (24-hour period)
|
|
│ └─ Block (time range + activity)
|
|
```
|
|
|
|
### 3.2 Schedule Types
|
|
|
|
**Daily Schedule** - Single 24-hour pattern:
|
|
```storybook
|
|
schedule SimpleDay {
|
|
block sleep { 0:00 - 6:00, activity: sleep }
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
block sleep { 22:00 - 24:00, activity: sleep }
|
|
}
|
|
```
|
|
|
|
**Weekly Schedule** - 7-day pattern with day variations:
|
|
```storybook
|
|
schedule WorkWeek {
|
|
weekday (mon, tue, wed, thu, fri) {
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
}
|
|
|
|
weekend (sat, sun) {
|
|
block leisure { 10:00 - 22:00, activity: leisure }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Seasonal Schedule** - Patterns that change by season:
|
|
```storybook
|
|
schedule BakeryHours {
|
|
season summer {
|
|
block open { 6:00 - 20:00, activity: work }
|
|
}
|
|
|
|
season winter {
|
|
block open { 7:00 - 18:00, activity: work }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Yearly Schedule** - Full year with events and overrides:
|
|
```storybook
|
|
schedule AnnualPattern extends WorkWeek {
|
|
event Christmas on Dec 25 {
|
|
block rest { 0:00 - 24:00, activity: rest }
|
|
}
|
|
|
|
event NewYear on Jan 1 {
|
|
block celebration { 0:00 - 24:00, activity: celebrate }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Composition System (i just want `override` support, we can yank `remove` and `append` and `remove all`, but `extends` is good)
|
|
|
|
### 4.1 Template Inheritance with `extends`
|
|
|
|
**Base Schedule:**
|
|
```storybook
|
|
schedule BaseWorkday {
|
|
block sleep { 0:00 - 6:00, activity: sleep }
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
block sleep { 22:00 - 24:00, activity: sleep }
|
|
}
|
|
```
|
|
|
|
**Extended Schedule:**
|
|
```storybook
|
|
schedule BakerSchedule extends BaseWorkday {
|
|
override work { 5:00 - 13:00 } // Earlier hours
|
|
append baking { 3:00 - 5:00, activity: prepare }
|
|
}
|
|
```
|
|
|
|
**Result:**
|
|
```
|
|
Block baking: 3:00 - 5:00 (prepare)
|
|
Block work: 5:00 - 13:00 (work) ← overridden
|
|
Block leisure: 17:00 - 22:00 (leisure) ← inherited
|
|
Block sleep: 22:00 - 24:00 + 0:00 - 6:00 (sleep) ← inherited
|
|
```
|
|
|
|
### 4.2 Override Operators
|
|
|
|
**`override <block> { fields }`** - Replace specific block properties:
|
|
```storybook
|
|
schedule BakerSchedule extends BaseWorkday {
|
|
override work {
|
|
time: 5:00 - 13:00,
|
|
location: Bakery
|
|
}
|
|
}
|
|
```
|
|
|
|
**`remove <block>`** - Delete inherited block:
|
|
```storybook
|
|
schedule RetiredSchedule extends BaseWorkday {
|
|
remove work // No more work!
|
|
}
|
|
```
|
|
|
|
**`append <block> { fields }`** - Add new block:
|
|
```storybook
|
|
schedule ExtendedDay extends BaseWorkday {
|
|
append meditation { 5:00 - 5:30, activity: meditate }
|
|
}
|
|
```
|
|
|
|
**`replace all`** - Complete replacement (no inheritance):
|
|
```storybook
|
|
schedule FullRest {
|
|
replace all
|
|
block rest { 0:00 - 24:00, activity: rest }
|
|
}
|
|
```
|
|
|
|
### 4.3 Multi-Level Inheritance
|
|
|
|
```storybook
|
|
schedule Base {
|
|
block work { 9:00 - 17:00, activity: work }
|
|
}
|
|
|
|
schedule WorkerSchedule extends Base {
|
|
override work { 8:00 - 16:00 }
|
|
}
|
|
|
|
schedule SeniorWorkerSchedule extends WorkerSchedule {
|
|
override work { 9:00 - 15:00 } // Shorter hours
|
|
}
|
|
|
|
// Result: work is 9:00 - 15:00 (SeniorWorker's version wins)
|
|
```
|
|
|
|
**Merge Rules (Same as Behavior Linking):**
|
|
- Character schedules override template schedules by block name
|
|
- Most specific schedule wins
|
|
- Concatenation + override-by-name
|
|
|
|
---
|
|
|
|
## 5. Temporal Patterns
|
|
|
|
### 5.1 Day-of-Week Patterns (not `activity` but `action` or `behavior` references)
|
|
|
|
**Simple Weekday/Weekend Split:**
|
|
```storybook
|
|
schedule WorkWeek {
|
|
weekday (mon, tue, wed, thu, fri) extends BaseWorkday {
|
|
// Monday-Friday use BaseWorkday
|
|
}
|
|
|
|
weekend (sat, sun) {
|
|
block leisure { 8:00 - 22:00, activity: leisure }
|
|
block sleep { 22:00 - 8:00, activity: sleep }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Day-Specific Customization:**
|
|
```storybook
|
|
schedule DetailedWeek {
|
|
on monday extends WorkdaySchedule {
|
|
append meeting { 9:00 - 10:00, activity: meeting }
|
|
}
|
|
|
|
on friday extends WorkdaySchedule {
|
|
override work { 9:00 - 15:00 } // Early finish!
|
|
}
|
|
|
|
on saturday {
|
|
block market { 8:00 - 12:00, activity: shopping }
|
|
block leisure { 12:00 - 22:00, activity: leisure }
|
|
}
|
|
|
|
on sunday {
|
|
block church { 10:00 - 11:00, activity: worship }
|
|
block family { 11:00 - 18:00, activity: social }
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.2 Seasonal Patterns
|
|
|
|
**Basic Seasonal Split:**
|
|
```storybook
|
|
schedule SeasonalWork {
|
|
season (spring, summer) {
|
|
block work { 6:00 - 14:00, activity: outdoor_work }
|
|
}
|
|
|
|
season (fall, winter) {
|
|
block work { 8:00 - 16:00, activity: indoor_work }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Season-Specific Schedules:**
|
|
```storybook
|
|
schedule FarmerSchedule {
|
|
season spring {
|
|
on weekday { block planting { 5:00 - 18:00, activity: plant } }
|
|
}
|
|
|
|
season summer {
|
|
on weekday { block tending { 6:00 - 16:00, activity: tend } }
|
|
}
|
|
|
|
season fall {
|
|
on weekday { block harvest { 5:00 - 19:00, activity: harvest } }
|
|
}
|
|
|
|
season winter {
|
|
on weekday { block planning { 9:00 - 15:00, activity: plan } }
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.3 Event Overrides (`event` is interesting)
|
|
|
|
**Holiday Definitions:**
|
|
```storybook
|
|
schedule AnnualSchedule extends WorkWeek {
|
|
event Christmas on Dec 25 {
|
|
block family { 0:00 - 24:00, activity: family_time }
|
|
}
|
|
|
|
event NewYear on Jan 1 {
|
|
block celebration { 0:00 - 24:00, activity: celebrate }
|
|
}
|
|
|
|
event Birthday on Jun 15 {
|
|
block party { 18:00 - 22:00, activity: celebrate }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Recurring Events:** (hmmmmmmmmmm sell me on this one.)
|
|
```storybook
|
|
schedule MarketSchedule extends BaseSchedule {
|
|
every saturday {
|
|
block market { 8:00 - 13:00, activity: sell_at_market }
|
|
}
|
|
|
|
every first_monday_of_month {
|
|
block guild_meeting { 19:00 - 21:00, activity: meeting }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. AST Design
|
|
|
|
### 6.1 Extended Schedule Structure
|
|
|
|
```rust
|
|
// In src/syntax/ast.rs
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Schedule {
|
|
pub name: String,
|
|
pub extends: Option<Vec<String>>, // NEW: extends BaseSchedule
|
|
pub items: Vec<ScheduleItem>, // NEW: blocks, patterns, events
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum ScheduleItem {
|
|
Block(ScheduleBlock), // Direct block definition
|
|
Override(ScheduleOverride), // override block_name { ... }
|
|
Remove(String), // remove block_name
|
|
Append(ScheduleBlock), // append new_block { ... }
|
|
ReplaceAll, // replace all
|
|
WeekdayPattern(WeekdayPattern), // weekday (...) { ... }
|
|
DayPattern(DayPattern), // on monday { ... }
|
|
SeasonPattern(SeasonPattern), // season summer { ... }
|
|
EventPattern(EventPattern), // event Name on Date { ... }
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ScheduleBlock {
|
|
pub name: Option<String>, // Optional block name
|
|
pub start: Time,
|
|
pub end: Time,
|
|
pub activity: String,
|
|
pub fields: Vec<Field>,
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct ScheduleOverride {
|
|
pub block_name: String,
|
|
pub fields: Vec<OverrideField>, // time, activity, location, etc.
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct WeekdayPattern {
|
|
pub days: Vec<DayOfWeek>, // [mon, tue, wed]
|
|
pub extends: Option<Vec<String>>, // Optional base schedule
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct DayPattern {
|
|
pub day: DayOfWeek, // monday
|
|
pub extends: Option<Vec<String>>,
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct SeasonPattern {
|
|
pub seasons: Vec<Season>, // [spring, summer]
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct EventPattern {
|
|
pub name: String, // "Christmas"
|
|
pub date: DateSpec, // Dec 25 or every saturday
|
|
pub blocks: Vec<ScheduleBlock>,
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum DayOfWeek {
|
|
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum Season {
|
|
Spring, Summer, Fall, Winter,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum DateSpec {
|
|
SpecificDate { month: u8, day: u8 }, // Dec 25
|
|
Recurring(RecurringPattern), // every saturday
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub enum RecurringPattern {
|
|
EveryWeekday(DayOfWeek), // every saturday
|
|
FirstDayOfMonth(DayOfWeek), // first monday of month
|
|
LastDayOfMonth(DayOfWeek), // last friday of month
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Grammar Design (LALRPOP)
|
|
|
|
### 7.1 Schedule Productions
|
|
|
|
```lalrpop
|
|
// In parser.lalrpop
|
|
|
|
pub Schedule: Schedule = {
|
|
"schedule" <name:Ident> <extends:ExtendsClause?> "{"
|
|
<items:ScheduleItem*>
|
|
"}" => Schedule { name, extends, items, span }
|
|
};
|
|
|
|
ExtendsClause: Vec<String> = {
|
|
"extends" <QualifiedPath>
|
|
};
|
|
|
|
ScheduleItem: ScheduleItem = {
|
|
<ScheduleBlock> => ScheduleItem::Block(<>),
|
|
<ScheduleOverride> => ScheduleItem::Override(<>),
|
|
<RemoveStmt> => ScheduleItem::Remove(<>),
|
|
<AppendStmt> => ScheduleItem::Append(<>),
|
|
<ReplaceAllStmt> => ScheduleItem::ReplaceAll,
|
|
<WeekdayPattern> => ScheduleItem::WeekdayPattern(<>),
|
|
<DayPattern> => ScheduleItem::DayPattern(<>),
|
|
<SeasonPattern> => ScheduleItem::SeasonPattern(<>),
|
|
<EventPattern> => ScheduleItem::EventPattern(<>),
|
|
};
|
|
|
|
// Basic block: 9:00 - 17:00: Work { activity: work }
|
|
ScheduleBlock: ScheduleBlock = {
|
|
<start:Time> "-" <end:Time> ":" <name:Ident?> "{"
|
|
<fields:Field*>
|
|
"}" => ScheduleBlock { name, start, end, fields, span }
|
|
};
|
|
|
|
// Override: override work { time: 5:00 - 13:00 }
|
|
ScheduleOverride: ScheduleOverride = {
|
|
"override" <block_name:Ident> "{"
|
|
<fields:OverrideField*>
|
|
"}" => ScheduleOverride { block_name, fields, span }
|
|
};
|
|
|
|
// Remove: remove block_name
|
|
RemoveStmt: String = {
|
|
"remove" <Ident>
|
|
};
|
|
|
|
// Append: append new_block { 5:00 - 6:00, activity: meditate }
|
|
AppendStmt: ScheduleBlock = {
|
|
"append" <ScheduleBlock>
|
|
};
|
|
|
|
// Replace all blocks
|
|
ReplaceAllStmt = {
|
|
"replace" "all"
|
|
};
|
|
|
|
// Weekday pattern: weekday (mon, tue, wed) { blocks }
|
|
WeekdayPattern: WeekdayPattern = {
|
|
"weekday" "(" <days:Comma<DayOfWeek>> ")" <extends:ExtendsClause?> "{"
|
|
<blocks:ScheduleBlock*>
|
|
"}" => WeekdayPattern { days, extends, blocks, span }
|
|
};
|
|
|
|
// Day pattern: on monday { blocks }
|
|
DayPattern: DayPattern = {
|
|
"on" <day:DayOfWeek> <extends:ExtendsClause?> "{"
|
|
<blocks:ScheduleBlock*>
|
|
"}" => DayPattern { day, extends, blocks, span }
|
|
};
|
|
|
|
// Season pattern: season summer { blocks }
|
|
SeasonPattern: SeasonPattern = {
|
|
"season" "(" <seasons:Comma<Season>> ")" "{"
|
|
<blocks:ScheduleBlock*>
|
|
"}" => SeasonPattern { seasons, blocks, span }
|
|
};
|
|
|
|
// Event pattern: event Christmas on Dec 25 { blocks }
|
|
EventPattern: EventPattern = {
|
|
"event" <name:Ident> "on" <date:DateSpec> "{"
|
|
<blocks:ScheduleBlock*>
|
|
"}" => EventPattern { name, date, blocks, span }
|
|
};
|
|
|
|
DayOfWeek: DayOfWeek = {
|
|
"monday" => DayOfWeek::Monday,
|
|
"tuesday" => DayOfWeek::Tuesday,
|
|
"wednesday" => DayOfWeek::Wednesday,
|
|
"thursday" => DayOfWeek::Thursday,
|
|
"friday" => DayOfWeek::Friday,
|
|
"saturday" => DayOfWeek::Saturday,
|
|
"sunday" => DayOfWeek::Sunday,
|
|
"mon" => DayOfWeek::Monday, // Short forms
|
|
"tue" => DayOfWeek::Tuesday,
|
|
"wed" => DayOfWeek::Wednesday,
|
|
"thu" => DayOfWeek::Thursday,
|
|
"fri" => DayOfWeek::Friday,
|
|
"sat" => DayOfWeek::Saturday,
|
|
"sun" => DayOfWeek::Sunday,
|
|
};
|
|
|
|
Season: Season = {
|
|
"spring" => Season::Spring,
|
|
"summer" => Season::Summer,
|
|
"fall" => Season::Fall,
|
|
"winter" => Season::Winter,
|
|
};
|
|
|
|
DateSpec: DateSpec = {
|
|
<month:Month> <day:Integer> => DateSpec::SpecificDate { month, day },
|
|
"every" <DayOfWeek> => DateSpec::Recurring(RecurringPattern::EveryWeekday(<>)),
|
|
"every" "first" <DayOfWeek> "of" "month" =>
|
|
DateSpec::Recurring(RecurringPattern::FirstDayOfMonth(<>)),
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Resolution & Merging
|
|
|
|
### 8.1 Schedule Merge Algorithm
|
|
|
|
**Same as Behavior Merging:**
|
|
1. Resolve `extends` reference to base schedule
|
|
2. Collect base schedule's blocks
|
|
3. Apply overrides/removes/appends from extending schedule
|
|
4. Override by block name (not by time)
|
|
5. Handle multi-level inheritance recursively
|
|
|
|
```rust
|
|
fn merge_schedules(
|
|
child: &Schedule,
|
|
parent: &Schedule,
|
|
) -> ResolvedSchedule {
|
|
let mut blocks = HashMap::new();
|
|
|
|
// Step 1: Add parent blocks
|
|
for block in &parent.blocks {
|
|
if let Some(name) = &block.name {
|
|
blocks.insert(name.clone(), block.clone());
|
|
}
|
|
}
|
|
|
|
// Step 2: Apply child modifications
|
|
for item in &child.items {
|
|
match item {
|
|
ScheduleItem::Block(block) => {
|
|
if let Some(name) = &block.name {
|
|
blocks.insert(name.clone(), block.clone());
|
|
}
|
|
}
|
|
ScheduleItem::Override(ovr) => {
|
|
if let Some(block) = blocks.get_mut(&ovr.block_name) {
|
|
apply_override(block, ovr);
|
|
}
|
|
}
|
|
ScheduleItem::Remove(name) => {
|
|
blocks.remove(name);
|
|
}
|
|
ScheduleItem::ReplaceAll => {
|
|
blocks.clear();
|
|
}
|
|
// ... handle patterns
|
|
}
|
|
}
|
|
|
|
ResolvedSchedule { blocks: blocks.into_values().collect() }
|
|
}
|
|
```
|
|
|
|
### 8.2 Pattern Resolution
|
|
|
|
**Weekday Patterns** expand to 7 day-specific schedules: (we have to account for user-defined story constants)
|
|
```storybook
|
|
weekday (mon, tue, wed, thu, fri) {
|
|
block work { 9:00 - 17:00 }
|
|
}
|
|
|
|
// Expands to:
|
|
// monday: { work { 9:00 - 17:00 } }
|
|
// tuesday: { work { 9:00 - 17:00 } }
|
|
// ...
|
|
```
|
|
|
|
**Season Patterns** apply conditionally at runtime based on current season.
|
|
|
|
**Event Patterns** override specific days when event matches.
|
|
|
|
---
|
|
|
|
## 9. Integration with Resource Linking
|
|
|
|
### 9.1 Simple Case
|
|
|
|
```storybook
|
|
schedule BakerSchedule {
|
|
block work { 5:00 - 13:00, activity: work }
|
|
block lunch { 13:00 - 14:00, activity: eat }
|
|
block rest { 14:00 - 22:00, activity: rest }
|
|
}
|
|
|
|
character Martha: Human {
|
|
uses schedule: BakerSchedule
|
|
}
|
|
```
|
|
|
|
### 9.2 Conditional Schedule Linking
|
|
|
|
```storybook
|
|
schedule WorkdaySchedule {
|
|
block work { 9:00 - 17:00, activity: work }
|
|
}
|
|
|
|
schedule WeekendSchedule {
|
|
block leisure { 10:00 - 22:00, activity: leisure }
|
|
}
|
|
|
|
character Martha: Human {
|
|
uses schedules: [
|
|
{ schedule: WorkdaySchedule, when: day_of_week is weekday } (hmmmm i like this but we need to scope how we handle abstract constructs like `day_of_week` because that's arbitrary)
|
|
{ schedule: WeekendSchedule, when: day_of_week is weekend }
|
|
]
|
|
}
|
|
```
|
|
|
|
### 9.3 Seasonal Schedules
|
|
|
|
```storybook
|
|
schedule SummerHours {
|
|
block open { 6:00 - 20:00, activity: work }
|
|
}
|
|
|
|
schedule WinterHours {
|
|
block open { 7:00 - 18:00, activity: work }
|
|
}
|
|
|
|
institution Bakery {
|
|
uses schedules: [
|
|
{ schedule: SummerHours, when: season == summer } (we have to figure out how to define seasons)
|
|
{ schedule: WinterHours, when: season == winter }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Examples
|
|
|
|
### Example 1: Simple Daily Schedule (Backward Compatible)
|
|
|
|
```storybook
|
|
schedule SimpleDay {
|
|
block sleep { 0:00 - 6:00, activity: sleep }
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
block sleep { 22:00 - 24:00, activity: sleep }
|
|
}
|
|
```
|
|
|
|
### Example 2: Schedule with Override
|
|
|
|
```storybook
|
|
schedule BaseWorkday {
|
|
block sleep { 0:00 - 6:00, activity: sleep }
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
block sleep { 22:00 - 24:00, activity: sleep }
|
|
}
|
|
|
|
schedule BakerSchedule extends BaseWorkday {
|
|
override work { time: 5:00 - 13:00, location: Bakery }
|
|
append prep { time: 3:00 - 5:00, activity: bake_prep }
|
|
}
|
|
```
|
|
|
|
### Example 3: Weekly Pattern
|
|
|
|
```storybook
|
|
schedule WorkWeek {
|
|
weekday (mon, tue, wed, thu, fri) {
|
|
block work { 9:00 - 17:00, activity: work }
|
|
block leisure { 17:00 - 22:00, activity: leisure }
|
|
}
|
|
|
|
weekend (sat, sun) {
|
|
block leisure { 10:00 - 22:00, activity: leisure }
|
|
}
|
|
}
|
|
```
|
|
|
|
### Example 4: Seasonal Business Hours
|
|
|
|
```storybook
|
|
schedule BakeryHours {
|
|
season (spring, summer) {
|
|
block open { 6:00 - 20:00, activity: serve_customers }
|
|
block prep { 4:00 - 6:00, activity: bake_bread }
|
|
}
|
|
|
|
season (fall, winter) {
|
|
block open { 7:00 - 18:00, activity: serve_customers }
|
|
block prep { 5:00 - 7:00, activity: bake_bread }
|
|
}
|
|
}
|
|
```
|
|
|
|
### Example 5: Full Year with Events
|
|
|
|
```storybook
|
|
schedule AnnualSchedule extends WorkWeek {
|
|
event Christmas on Dec 25 {
|
|
block family { 0:00 - 24:00, activity: family_time }
|
|
}
|
|
|
|
event NewYear on Jan 1 {
|
|
block celebration { 0:00 - 24:00, activity: celebrate }
|
|
}
|
|
|
|
every saturday {
|
|
block market { 8:00 - 12:00, activity: sell_at_market }
|
|
}
|
|
}
|
|
```
|
|
|
|
### Example 6: Complex Multi-Level Inheritance
|
|
|
|
```storybook
|
|
schedule BaseHuman {
|
|
block sleep { 0:00 - 6:00, activity: sleep }
|
|
block breakfast { 6:00 - 7:00, activity: eat }
|
|
block dinner { 18:00 - 19:00, activity: eat }
|
|
block sleep { 22:00 - 24:00, activity: sleep }
|
|
}
|
|
|
|
schedule Worker extends BaseHuman {
|
|
block work { 9:00 - 17:00, activity: work }
|
|
}
|
|
|
|
schedule Baker extends Worker {
|
|
override work { time: 5:00 - 13:00, location: Bakery }
|
|
override breakfast { time: 13:30 - 14:00 } // Late breakfast
|
|
append prep { time: 3:00 - 5:00, activity: bake }
|
|
}
|
|
|
|
schedule RetiredBaker extends BaseHuman {
|
|
// No work, just keep eating/sleeping schedule
|
|
append hobby { time: 10:00 - 16:00, activity: hobby }
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 11. SBIR Representation
|
|
|
|
### 11.1 SCHEDULES Section Extension
|
|
|
|
```
|
|
SCHEDULES Section:
|
|
- count: u32
|
|
- schedules: [Schedule...]
|
|
|
|
Schedule:
|
|
- name: String
|
|
- parent_schedule_id: Option<u32> // extends reference
|
|
- blocks: [ScheduleBlock...]
|
|
- patterns: [SchedulePattern...] // weekday, season, event
|
|
|
|
ScheduleBlock:
|
|
- name: Option<String>
|
|
- start: Time (u16 minutes since midnight)
|
|
- end: Time (u16 minutes since midnight)
|
|
- activity: String
|
|
- fields: Map<String, Value>
|
|
|
|
SchedulePattern:
|
|
- kind: PatternKind (Weekday, Season, Event)
|
|
- specification: bytes (encoded pattern details)
|
|
- blocks: [ScheduleBlock...]
|
|
|
|
PatternKind:
|
|
- Weekday(days: [DayOfWeek])
|
|
- Season(seasons: [Season])
|
|
- Event(date: DateSpec)
|
|
```
|
|
|
|
### 11.2 Runtime Evaluation
|
|
|
|
**At runtime**, the engine:
|
|
1. Resolves character's schedule links (conditional selection)
|
|
2. Merges inherited schedules
|
|
3. Evaluates patterns for current day/season
|
|
4. Produces final 24-hour schedule for today
|
|
|
|
**Example Flow:**
|
|
```
|
|
Character Martha uses BakerSchedule
|
|
↓
|
|
BakerSchedule extends BaseWorkday
|
|
↓
|
|
Merge: BaseWorkday blocks + Baker overrides
|
|
↓
|
|
Result: Martha's schedule for today
|
|
```
|
|
|
|
---
|
|
|
|
## 12. Implementation Plan
|
|
|
|
### Phase 1: AST Extension (Week 1)
|
|
1. Add extended Schedule struct with `extends` and `items`
|
|
2. Add ScheduleItem enum (Block, Override, Remove, etc.)
|
|
3. Add pattern types (WeekdayPattern, SeasonPattern, EventPattern)
|
|
4. Add DayOfWeek, Season, DateSpec enums
|
|
5. Update existing ScheduleBlock to support optional names
|
|
|
|
### Phase 2: Parser Implementation (Week 1-2)
|
|
1. Implement `extends` clause parsing
|
|
2. Implement override/remove/append operators
|
|
3. Implement weekday/day patterns
|
|
4. Implement season patterns
|
|
5. Implement event patterns
|
|
6. Write parser tests for all patterns
|
|
|
|
### Phase 3: Resolution & Merging (Week 2)
|
|
1. Implement schedule inheritance resolution
|
|
2. Implement merge algorithm (same as behavior merging)
|
|
3. Implement pattern expansion
|
|
4. Implement multi-level inheritance
|
|
5. Write resolution tests
|
|
|
|
### Phase 4: Integration (Week 2-3)
|
|
1. Update schedule linking in resource linking system
|
|
2. Implement runtime schedule evaluation
|
|
3. Update SBIR format
|
|
4. Write integration tests
|
|
|
|
### Phase 5: Documentation & Examples (Week 3)
|
|
1. Update language documentation
|
|
2. Create comprehensive schedule examples
|
|
3. Update Alice in Wonderland example with patterns
|
|
4. Create migration guide
|
|
|
|
**Total Estimate:** 3 weeks
|
|
|
|
---
|
|
|
|
## 13. Open Questions
|
|
|
|
### Question 1: Block Naming (yes)
|
|
Should all blocks require names?
|
|
|
|
**Current:** Blocks can be anonymous
|
|
**Proposed:** Blocks need names for override system
|
|
|
|
**Recommendation:** Require names for override-ability
|
|
|
|
### Question 2: Time Overlap Detection (ummmmmmm... yeah prolly.)
|
|
Should parser/validator detect time overlaps?
|
|
|
|
```storybook
|
|
schedule Broken {
|
|
block work { 9:00 - 17:00 }
|
|
block lunch { 12:00 - 13:00 } // Overlaps with work!
|
|
}
|
|
```
|
|
|
|
**Recommendation:** Warning (not error) for overlaps
|
|
|
|
### Question 3: Default Block Duration (must throw an error)
|
|
What if user writes just `block lunch`?
|
|
|
|
**Option A:** Error (must specify time)
|
|
**Option B:** Default duration (e.g., 1 hour)
|
|
|
|
**Recommendation:** Option A (explicit is better)
|
|
|
|
### Question 4: Seasonal Calendar (configurable per world)
|
|
Which calendar system?
|
|
|
|
**Option A:** Simple 4 seasons (Spring, Summer, Fall, Winter)
|
|
**Option B:** Month-specific (Jan is winter, etc.)
|
|
**Option C:** Configurable per world
|
|
|
|
**Recommendation:** Option A, with Option C as future extension
|
|
|
|
---
|
|
|
|
## 14. Success Criteria
|
|
|
|
### Must Have
|
|
- [x] Backward compatible with current simple schedules
|
|
- [x] Template inheritance with `extends`
|
|
- [x] Override/remove/append operators
|
|
- [x] Weekday patterns (weekday/weekend)
|
|
- [x] Day-specific patterns (on monday)
|
|
- [x] Seasonal patterns
|
|
- [x] Event overrides
|
|
- [x] Integration with `uses schedule:` linking
|
|
- [x] Multi-level inheritance
|
|
- [x] Merge algorithm defined
|
|
- [x] SBIR representation specified
|
|
|
|
### Should Have
|
|
- [ ] Recurring event patterns (every saturday)
|
|
- [ ] Time overlap warnings
|
|
- [ ] Pattern validation
|
|
- [ ] Comprehensive examples
|
|
- [ ] Runtime evaluation algorithm
|
|
|
|
### Nice to Have
|
|
- [ ] Calendar abstraction for different worlds
|
|
- [ ] Behavior references in schedule blocks
|
|
- [ ] Visual schedule editor design
|
|
- [ ] Performance optimization for large schedules
|
|
|
|
---
|
|
|
|
## 15. Comparison with Behavior Linking
|
|
|
|
| Aspect | Behavior Linking | Schedule Linking |
|
|
|--------|------------------|------------------|
|
|
| **Inheritance** | `from Template` | `extends Base` |
|
|
| **Merge Rule** | Concatenation + override by name | Same |
|
|
| **Override** | Character's behavior replaces template's | Child's block replaces parent's |
|
|
| **Selection** | Priority + conditions | Temporal + conditions |
|
|
| **Multi-level** | Supported | Supported |
|
|
| **Empty Array** | Inherit all | Inherit all |
|
|
|
|
**Design Principle:** Keep schedule composition consistent with behavior composition for user familiarity.
|
|
|
|
---
|
|
|
|
**End of Design Document**
|
|
|
|
**Next Step:** Review and approval before implementation (Task #12).
|