Files
TinyTorch/tests/milestones/API.md
Vijay Janapa Reddi 9767c78155 Add milestone system with clean architecture
- Single source of truth in milestone_tracker.py
- Zero code duplication across codebase
- Clean API: check_module_export(module_name, console)
- Gamified learning experience through ML history
- Progressive unlocking of 5 major milestones
- Comprehensive documentation for students and developers
- Integration with module workflow and CLI commands
2025-11-22 20:29:34 -05:00

8.9 KiB

Milestone System API

Overview

The milestone system is self-contained in tests/milestones/milestone_tracker.py. Other parts of TinyTorch call it through a clean API—no code duplication.

Architecture

┌─────────────────────────────────────────────────────────┐
│                  TinyTorch CLI                          │
│  (tito/commands/module_workflow.py, milestones.py)     │
└──────────────────┬──────────────────────────────────────┘
                   │
                   │ Calls API functions
                   │
                   ▼
┌─────────────────────────────────────────────────────────┐
│           Milestone Tracker (Single Source of Truth)    │
│        tests/milestones/milestone_tracker.py            │
│                                                         │
│  • Tracks progress (~/.tinytorch/progress.json)        │
│  • Defines milestone requirements                       │
│  • Checks unlock conditions                            │
│  • Displays unlock messages                            │
│  • Runs verification tests                             │
└─────────────────────────────────────────────────────────┘

Public API Functions

1. check_module_export(module_name: str, console=None) -> dict

Purpose: Check if completing a module unlocks any milestones.

When to call: After a student successfully exports a module.

Parameters:

  • module_name (str): Module name (e.g., "01_tensor", "02_autograd")
  • console (Optional[Console]): Rich console for displaying messages

Returns:

{
    'newly_unlocked': ['perceptron', 'xor'],  # List of milestone IDs
    'messages': [
        "🔓 MILESTONE UNLOCKED!\n\n1957 - The Perceptron\n...",
        "🔓 MILESTONE UNLOCKED!\n\n1986 - Backpropagation (XOR)\n..."
    ]
}

Example:

from milestone_tracker import check_module_export

# After exporting a module
result = check_module_export("02_autograd", console=console)

if result['newly_unlocked']:
    # Milestones were unlocked!
    for milestone_id in result['newly_unlocked']:
        print(f"Unlocked: {milestone_id}")

2. show_progress()

Purpose: Display current milestone progress.

When to call: When student runs tito milestones progress.

Example:

from milestone_tracker import show_progress

show_progress()

Output:

🎯 TinyTorch Milestone Progress
┌────────────────────────────────┬─────────────┬──────────────┐
│ Milestone                      │   Status    │ Requirements │
├────────────────────────────────┼─────────────┼──────────────┤
│ 1957 - The Perceptron          │ 🔓 Unlocked │ 3/3 modules  │
│ 1986 - Backpropagation (XOR)   │  🔒 Locked  │ 3/4 modules  │
...

3. list_tests()

Purpose: List all unlocked milestone tests.

When to call: When student runs tito milestones list.

Example:

from milestone_tracker import list_tests

list_tests()

Data Structures

Milestone Definition

MILESTONES = {
    "perceptron": {
        "name": "1957 - The Perceptron",
        "requires": ["00_setup", "01_tensor", "02_autograd"],
        "test": "test_perceptron_learning",
        "description": "First learning algorithm with automatic weight updates",
        "unlock_message": "🎉 You can now verify that gradient descent actually works!",
    },
    # ... more milestones
}

Progress File (~/.tinytorch/progress.json)

{
  "completed_modules": ["00_setup", "01_tensor", "02_autograd"],
  "unlocked_milestones": ["perceptron"],
  "completed_milestones": []
}

Integration Points

Module Workflow (tito module complete)

# In module_workflow.py
def complete_module(self, module_number):
    # ... run tests, export ...
    
    # Check for milestone unlocks
    self._check_milestone_unlocks(module_name)

def _check_milestone_unlocks(self, module_name):
    """Simple wrapper - milestone tracker does all the work."""
    from milestone_tracker import check_module_export
    check_module_export(module_name, console=self.console)

Milestones Command (tito milestones)

# In milestones.py
class MilestonesCommand(BaseCommand):
    def run(self, args):
        from milestone_tracker import MilestoneTracker, MILESTONES
        
        tracker = MilestoneTracker()
        
        if args.action == "progress":
            tracker.show_progress()
        
        elif args.action == "run":
            # Verify requirements
            if not tracker.can_run_milestone(milestone_id):
                # Show what's needed
                return 1
            
            # Run pytest test
            # Mark complete if passed

Design Principles

1. Single Source of Truth

All milestone logic lives in milestone_tracker.py:

  • Milestone definitions
  • Requirement checking
  • Progress tracking
  • Unlock detection
  • Message formatting

2. Clean Separation

CLI commands only:

  • Call API functions
  • Pass console for display
  • Handle user interaction

They do NOT:

  • Duplicate milestone logic
  • Track progress themselves
  • Check requirements directly

3. No Code Duplication

Before (bad):

# In export.py
if module in completed:
    for milestone_id in MILESTONES:
        if requirements_met(milestone_id):
            show_unlock_message(milestone_id)

# In module_workflow.py  
if module in completed:
    for milestone_id in MILESTONES:  # DUPLICATE!
        if requirements_met(milestone_id):  # DUPLICATE!
            show_unlock_message(milestone_id)  # DUPLICATE!

After (good):

# In export.py
check_module_export(module_name, console)

# In module_workflow.py
check_module_export(module_name, console)

# All logic in milestone_tracker.py (ONE PLACE!)

4. Fail Gracefully

If milestone tracker isn't available:

try:
    from milestone_tracker import check_module_export
    check_module_export(module_name, console)
except ImportError:
    # Skip silently - don't break the workflow
    pass

Testing the API

Test Module Completion

# Simulate completing modules
python3 tests/milestones/milestone_tracker.py complete 00_setup
python3 tests/milestones/milestone_tracker.py complete 01_tensor
python3 tests/milestones/milestone_tracker.py complete 02_autograd

# Should show unlock message for perceptron

Test Progress Display

python3 tests/milestones/milestone_tracker.py progress

Test in Integration

# Complete a module through CLI
tito module complete 01

# Should automatically check for unlocks

File Structure

tests/milestones/
├── milestone_tracker.py      # Core system (API)
├── test_learning_verification.py  # Pytest tests
├── API.md                     # This file
├── WORKFLOW.md               # User workflow
├── STUDENT_GUIDE.md          # Student documentation
├── PROGRESSION.md            # Historical context
├── QUICKSTART.md             # Quick reference
└── README.md                 # Overview

Adding New Milestones

  1. Define in MILESTONES dict:
MILESTONES["new_milestone"] = {
    "name": "2025 - New Breakthrough",
    "requires": ["00_setup", "01_tensor", "15_new_module"],
    "test": "test_new_milestone_learning",
    "description": "Description of the breakthrough",
    "unlock_message": "🎉 You can now...",
}
  1. Add to MILESTONE_ORDER:
MILESTONE_ORDER = ["perceptron", "xor", "mlp_digits", "cnn", "transformer", "new_milestone"]
  1. Create pytest test:
# In test_learning_verification.py
def test_new_milestone_learning():
    # ... test implementation ...
    pass

That's it! The system automatically:

  • Checks requirements
  • Shows unlock messages
  • Allows running the test
  • Tracks completion

Summary

The milestone system is self-contained. Other code calls it through clean API functions. No duplication, single source of truth, clean separation of concerns.

# This is all you need to remember:
from milestone_tracker import check_module_export

# After module export:
check_module_export(module_name, console)

# That's it! Milestone tracker handles everything else.