# Project Mode Implementation - Continuation Guide ## Overview This document provides a complete roadmap for continuing the implementation of dual-mode support in OldBoy: **Composition Mode** (full document evaluation) and **Live Coding Mode** (block-based evaluation with persistent Csound instance). --- ## What Has Been Completed ### 1. Type System & Data Model ✅ **Files Modified:** - `/src/lib/project-system/types.ts` - `/src/lib/project-system/project-manager.ts` **Changes:** 1. Created `ProjectMode` type: ```typescript export type ProjectMode = 'composition' | 'livecoding'; ``` 2. Added `mode` field to `CsoundProject` interface: ```typescript export interface CsoundProject { // ... existing fields mode: ProjectMode; // NEW: Execution mode } ``` 3. Updated `CreateProjectData` to accept optional mode: ```typescript export interface CreateProjectData { // ... existing fields mode?: ProjectMode; // Defaults to 'composition' if not provided } ``` 4. Updated `UpdateProjectData` to allow mode updates: ```typescript export interface UpdateProjectData { // ... existing fields mode?: ProjectMode; // Can change mode after creation } ``` 5. Modified `ProjectManager.createProject()`: - Line 100: Added `mode: data.mode || 'composition'` to project initialization - Ensures all new projects have a mode (defaults to composition) 6. Modified `ProjectManager.updateProject()`: - Line 165: Added `...(data.mode !== undefined && { mode: data.mode })` to update logic - Allows mode to be updated without affecting other fields **Result:** All projects now have a mode field that persists in IndexedDB and is included in import/export operations. --- ### 2. UI for Mode Selection ✅ **Files Modified:** - `/src/lib/components/ui/FileBrowser.svelte` - `/src/lib/stores/projectEditor.svelte.ts` - `/src/App.svelte` **FileBrowser Changes:** 1. **Imports (Line 7):** ```typescript import type { ProjectMode } from '../../project-system/types'; ``` 2. **Props Interface (Line 13):** ```typescript onMetadataUpdate?: (projectId: string, updates: { title?: string; author?: string; mode?: ProjectMode // NEW }) => void; ``` 3. **State (Line 30):** ```typescript let editMode = $state('composition'); ``` 4. **Effect Hook (Lines 32-38):** ```typescript $effect(() => { if (selectedProject) { editTitle = selectedProject.title; editAuthor = selectedProject.author; editMode = selectedProject.mode; // NEW: Sync mode from project } }); ``` 5. **Metadata Change Handler (Lines 103-118):** ```typescript function handleMetadataChange() { if (!selectedProject) return; const hasChanges = editTitle !== selectedProject.title || editAuthor !== selectedProject.author || editMode !== selectedProject.mode; // NEW: Include mode in change detection if (hasChanges) { onMetadataUpdate?.(selectedProject.id, { title: editTitle, author: editAuthor, mode: editMode // NEW: Send mode updates }); } } ``` 6. **UI Element (Lines 183-193):** ```svelte
``` 7. **CSS (Lines 373-390):** ```css .field input, .field select { padding: 0.5rem; background-color: #2a2a2a; border: 1px solid #3a3a3a; color: rgba(255, 255, 255, 0.87); font-size: 0.875rem; outline: none; } .field select { cursor: pointer; } ``` **ProjectEditor Changes (Line 108):** ```typescript async updateMetadata(updates: { title?: string; author?: string; mode?: import('../project-system/types').ProjectMode // NEW }): Promise ``` **App.svelte Changes (Line 123):** ```typescript async function handleMetadataUpdate( projectId: string, updates: { title?: string; author?: string; mode?: import('./lib/project-system/types').ProjectMode // NEW } ) ``` **Result:** Users can now select project mode in the Files panel metadata editor. Mode changes are immediately persisted. --- ### 3. Block Evaluation Infrastructure ✅ **File Created:** - `/src/lib/editor/block-eval.ts` **Purpose:** Provides utilities for extracting code blocks and visual feedback, adapted from flok's cm-eval package. **Exports:** 1. **`flash(view, from, to, timeout)`** - Visually highlights evaluated code region - Default timeout: 150ms - Background color: `#FFCA2880` (yellow with transparency) 2. **`flashField(style?)`** - CodeMirror StateField for managing flash decorations - Returns StateField to be added to editor extensions - Handles flash effect lifecycle 3. **`getSelection(state): EvalBlock`** - Returns currently selected text with positions - Returns `{ text: '', from: null, to: null }` if no selection 4. **`getLine(state): EvalBlock`** - Returns the entire line at cursor position - Includes line's from/to positions 5. **`getBlock(state): EvalBlock`** - Returns paragraph block (text separated by blank lines) - Searches up and down from cursor until blank lines found - Core functionality for live coding mode 6. **`getDocument(state): EvalBlock`** - Returns entire document text - Used for composition mode evaluation **EvalBlock Interface:** ```typescript interface EvalBlock { text: string; // The code to evaluate from: number | null; // Start position in document to: number | null; // End position in document } ``` **Implementation Details:** - **Block Detection Algorithm:** 1. Start at cursor line 2. If line is blank, return empty block 3. Search backwards until blank line or document start 4. Search forwards until blank line or document end 5. Extract text from start to end positions - **Flash Effect:** - Uses CodeMirror StateEffect system - Creates decoration with inline style - Automatically clears after timeout - Non-blocking (doesn't prevent editing) **Result:** Complete block evaluation infrastructure ready to integrate with Editor component. --- ## What Needs to Be Done Next ### Phase 1: Editor Integration with Block Evaluation **Goal:** Connect block-eval utilities to the Editor component and add visual feedback. **File to Modify:** `/src/lib/components/editor/Editor.svelte` **Steps:** 1. **Import block-eval utilities (add to imports):** ```typescript import { flashField, flash, getSelection, getBlock, getDocument } from '../editor/block-eval'; ``` 2. **Add flashField to extensions:** Find where extensions are created (likely in a `$derived` or similar). It should look something like: ```typescript let extensions = $derived([ // ... existing extensions ]); ``` Add flashField: ```typescript let extensions = $derived([ // ... existing extensions flashField(), // NEW: Add flash effect support ]); ``` 3. **Expose block extraction methods:** Add these methods to the Editor component (after the component logic, before closing tag): ```typescript export function getSelectedText(): string | null { if (!editorView) return null; const { text } = getSelection(editorView.state); return text || null; } export function getCurrentBlock(): string | null { if (!editorView) return null; const { text } = getBlock(editorView.state); return text || null; } export function getFullDocument(): string { if (!editorView) return ''; const { text } = getDocument(editorView.state); return text; } export function evaluateWithFlash(text: string, from: number | null, to: number | null) { if (editorView && from !== null && to !== null) { flash(editorView, from, to); } } ``` 4. **Modify keyboard shortcut for execute:** Find the keyboard shortcut setup (search for "Ctrl-Enter" or "Cmd-Enter"). It might look like: ```typescript keymap.of([ { key: "Ctrl-Enter", run: () => { onExecute?.(value); return true; } } ]) ``` Change it to call a new internal method: ```typescript keymap.of([ { key: "Ctrl-Enter", mac: "Cmd-Enter", run: () => { handleExecute(); return true; } } ]) ``` 5. **Add internal execute handler:** ```typescript function handleExecute() { if (!editorView) return; // Get selection or block const selection = getSelection(editorView.state); if (selection.text) { // Has selection: evaluate it flash(editorView, selection.from, selection.to); onExecute?.(selection.text, 'selection'); } else { // No selection: evaluate block or document based on mode // For now, always get block (mode logic will be in App.svelte) const block = getBlock(editorView.state); if (block.text) { flash(editorView, block.from, block.to); onExecute?.(block.text, 'block'); } } } ``` 6. **Update onExecute prop type:** Change the prop signature from: ```typescript onExecute?: (code: string) => void; ``` To: ```typescript onExecute?: (code: string, source: 'selection' | 'block' | 'document') => void; ``` **Expected Result:** - Cmd/Ctrl+Enter will flash the code being evaluated - Editor can distinguish between selection, block, and document evaluation - Parent components can access block extraction methods --- ### Phase 2: Execution Strategy Implementation **Goal:** Create strategy pattern for handling composition vs livecoding execution modes. **File to Create:** `/src/lib/csound/execution-strategies.ts` **Implementation:** ```typescript import type { CsoundStore } from './store'; import type { ProjectMode } from '../project-system/types'; export interface ExecutionStrategy { execute( csound: CsoundStore, code: string, fullContent: string, source: 'selection' | 'block' | 'document' ): Promise; } /** * Composition Mode Strategy * - Always evaluates full CSD document * - Uses ephemeral instances (fresh instance each time) * - Standard workflow: compile → start → play → cleanup */ export class CompositionStrategy implements ExecutionStrategy { async execute( csound: CsoundStore, code: string, fullContent: string, source: 'selection' | 'block' | 'document' ): Promise { // Always evaluate full document in composition mode await csound.evaluate(fullContent); } } /** * Live Coding Mode Strategy * - Evaluates blocks incrementally * - Uses persistent instance (maintains state) * - Supports: score events, channel updates, instrument redefinition */ export class LiveCodingStrategy implements ExecutionStrategy { private isInitialized = false; private headerCompiled = false; async execute( csound: CsoundStore, code: string, fullContent: string, source: 'selection' | 'block' | 'document' ): Promise { // First time: initialize with full document if (!this.isInitialized) { await this.initializeFromDocument(csound, fullContent); this.isInitialized = true; return; } // Subsequent evaluations: handle blocks await this.evaluateBlock(csound, code); } private async initializeFromDocument( csound: CsoundStore, fullContent: string ): Promise { // Parse CSD to extract orchestra and initial score const { header, instruments, score } = this.parseCSD(fullContent); // Compile header + instruments const fullOrchestra = header + '\n' + instruments; const compileResult = await csound.compileOrchestra(fullOrchestra); if (!compileResult.success) { throw new Error(compileResult.errorMessage || 'Compilation failed'); } this.headerCompiled = true; // Start performance await csound.startPerformance(); // If score has events, send them if (score.trim()) { await csound.readScore(score); } } private async evaluateBlock(csound: CsoundStore, code: string): Promise { const trimmedCode = code.trim(); if (!trimmedCode) return; // Detect what kind of code this is if (this.isScoreEvent(trimmedCode)) { // Send score event (e.g., "i 1 0 2 0.5") await csound.sendScoreEvent(trimmedCode); } else if (this.isInstrumentDefinition(trimmedCode)) { // Recompile instrument await csound.compileOrchestra(trimmedCode); } else if (this.isChannelSet(trimmedCode)) { // Set channel value (e.g., "freq = 440") await this.handleChannelSet(csound, trimmedCode); } else { // Default: try to compile as orchestra code await csound.compileOrchestra(trimmedCode); } } private parseCSD(content: string): { header: string; instruments: string; score: string } { // Extract section const orcMatch = content.match(/([\s\S]*?)<\/CsInstruments>/); if (!orcMatch) { return { header: '', instruments: '', score: '' }; } const orchestra = orcMatch[1].trim(); // Extract section const scoMatch = content.match(/([\s\S]*?)<\/CsScore>/); const score = scoMatch ? scoMatch[1].trim() : ''; // Split orchestra into header (sr, ksmps, nchnls, etc.) and instruments const instrMatch = orchestra.match(/([\s\S]*?)(instr\s+\d+[\s\S]*)/); if (instrMatch) { return { header: instrMatch[1].trim(), instruments: instrMatch[2].trim(), score }; } // If no instruments found, treat entire orchestra as header return { header: orchestra, instruments: '', score }; } private isScoreEvent(code: string): boolean { // Check for score event syntax: i, f, e, a followed by space/number return /^[ifea]\s+[\d\-]/.test(code); } private isInstrumentDefinition(code: string): boolean { // Check for instrument definition return /^\s*instr\s+/.test(code); } private isChannelSet(code: string): boolean { // Simple channel set syntax: varname = value // e.g., "freq = 440" or "cutoff = 2000" return /^\w+\s*=\s*[\d\.\-]+/.test(code); } private async handleChannelSet(csound: CsoundStore, code: string): Promise { // Parse: varname = value const match = code.match(/^(\w+)\s*=\s*([\d\.\-]+)/); if (!match) return; const [, channelName, valueStr] = match; const value = parseFloat(valueStr); await csound.setControlChannel(channelName, value); } /** * Reset the strategy state (called when switching documents or resetting) */ reset(): void { this.isInitialized = false; this.headerCompiled = false; } } /** * Factory function to create appropriate strategy based on mode */ export function createExecutionStrategy(mode: ProjectMode): ExecutionStrategy { return mode === 'livecoding' ? new LiveCodingStrategy() : new CompositionStrategy(); } ``` **Expected Result:** - Strategy pattern cleanly separates composition and livecoding behaviors - LiveCodingStrategy maintains state across evaluations - Supports score events, instrument redefinition, and channel control --- ### Phase 3: Update App.svelte to Use Strategies **File to Modify:** `/src/App.svelte` **Steps:** 1. **Import strategy utilities:** ```typescript import { createExecutionStrategy, type ExecutionStrategy } from './lib/csound/execution-strategies'; ``` 2. **Track current strategy:** ```typescript let currentStrategy = $state(null); let currentMode = $state('composition'); ``` 3. **Update strategy when project changes:** Add effect to watch for project mode changes: ```typescript $effect(() => { const mode = projectEditor.currentProject?.mode || 'composition'; // Only recreate strategy if mode changed if (mode !== currentMode) { currentMode = mode; currentStrategy = createExecutionStrategy(mode); // If switching to livecoding, need to reset csound if (mode === 'livecoding') { // Reset to ensure clean state csound.reset().catch(console.error); } } }); ``` 4. **Update handleExecute function:** Replace existing handleExecute (around line 99): ```typescript async function handleExecute(code: string, source: 'selection' | 'block' | 'document') { try { if (!currentStrategy) { currentStrategy = createExecutionStrategy(currentMode); } const fullContent = projectEditor.content; await currentStrategy.execute(csound, code, fullContent, source); } catch (error) { console.error('Execution error:', error); } } ``` 5. **Update EditorWithLogs onExecute prop:** Find where EditorWithLogs is used (around line 274): ```svelte logs={interpreterLogs} {editorSettings} /> ``` **Expected Result:** - App automatically uses correct strategy based on project mode - Strategy instance persists across evaluations - Mode switches trigger proper cleanup/reset --- ### Phase 4: Update Csound Store for Mode-Aware Instance Management **Goal:** Make Csound store use persistent vs ephemeral instances based on project mode. **File to Modify:** `/src/lib/contexts/app-context.ts` **Current Code (likely around line 10-15):** ```typescript const csound = createCsoundStore(); ``` **Change to:** ```typescript const csound = createCsoundStore('ephemeral'); // Default to ephemeral ``` **Then in App.svelte, add mode-based reset logic:** In the `$effect` that watches mode changes (from Phase 3, Step 3), enhance it: ```typescript $effect(() => { const mode = projectEditor.currentProject?.mode || 'composition'; if (mode !== currentMode) { const oldMode = currentMode; currentMode = mode; currentStrategy = createExecutionStrategy(mode); // Handle Csound instance mode switching if (mode === 'livecoding' && oldMode === 'composition') { // Switching TO livecoding: need persistent instance // Reset will be handled by first LiveCodingStrategy execution console.log('Switched to live coding mode'); } else if (mode === 'composition' && oldMode === 'livecoding') { // Switching FROM livecoding: stop and cleanup csound.stop().catch(console.error); console.log('Switched to composition mode'); } } }); ``` **Note:** The actual instance mode (ephemeral/persistent) is now implicitly handled by the strategy: - **CompositionStrategy**: calls `csound.evaluate()` which uses ephemeral mode (current default) - **LiveCodingStrategy**: calls `compileOrchestra()` + `startPerformance()` which uses the same instance repeatedly The key insight is that **persistence is achieved by NOT calling `evaluate()`** (which destroys/recreates), but instead using the low-level API (`compileOrchestra`, `startPerformance`, `sendScoreEvent`). **Expected Result:** - Composition mode: Each evaluation gets fresh instance - Live coding mode: Single instance persists across block evaluations - Switching modes properly cleans up old instances --- ### Phase 5: Testing & Verification **Test Plan:** #### Test 1: Composition Mode (Baseline) 1. Create new project (defaults to composition mode) 2. Paste this CSD code: ```csound -odac sr = 48000 ksmps = 32 nchnls = 2 0dbfs = 1 instr 1 aOut poscil 0.2, 440 outs aOut, aOut endin i 1 0 2 ``` 3. Press Cmd/Ctrl+Enter 4. **Expected:** Entire document flashes yellow, sound plays for 2 seconds 5. Modify frequency to 880, press Cmd/Ctrl+Enter again 6. **Expected:** New instance created, new sound plays #### Test 2: Live Coding Mode - Initial Setup 1. Open FileBrowser, select the project 2. In metadata, change Mode from "Composition" to "Live Coding" 3. Press Cmd/Ctrl+Enter on the entire document 4. **Expected:** - Document flashes - Csound initializes (check logs for "Starting performance...") - Sound plays if score has events #### Test 3: Live Coding Mode - Block Evaluation 1. Clear the `` section (or comment out with semicolons) 2. Ensure document is initialized (press Cmd/Ctrl+Enter on full document) 3. Add a new line at the bottom of the document: ```csound i 1 0 2 0.5 ``` 4. Place cursor on that line, press Cmd/Ctrl+Enter 5. **Expected:** - Only that line flashes - Sound plays immediately (instrument 1 triggered) - Logs show score event sent, NOT full recompilation #### Test 4: Live Coding Mode - Channel Control 1. Modify instrument 1 to use a channel: ```csound instr 1 kFreq chnget "freq" aOut poscil 0.2, kFreq outs aOut, aOut endin ``` 2. Reinitialize (Cmd+Enter on full document) 3. Start a long note: ```csound i 1 0 60 ``` 4. While playing, evaluate this block: ```csound freq = 440 ``` 5. Then evaluate: ```csound freq = 880 ``` 6. **Expected:** - Frequency changes in real-time while note plays - No audio interruption #### Test 5: Live Coding Mode - Instrument Redefinition 1. While note is playing from Test 4, modify instrument 1: ```csound instr 1 kFreq chnget "freq" aOut vco2 0.2, kFreq outs aOut, aOut endin ``` 2. Select only the instrument definition, press Cmd+Enter 3. **Expected:** - Instrument recompiles - Next triggered note uses new definition - Currently playing notes might continue with old definition (Csound behavior) #### Test 6: Mode Switching 1. In live coding mode with performance running 2. Switch mode to "Composition" in FileBrowser 3. **Expected:** - Performance stops - Logs show "Stopped" 4. Press Cmd+Enter 5. **Expected:** - Full document evaluation (composition mode behavior) #### Test 7: Persistence Across Sessions 1. Create project in live coding mode 2. Close browser tab 3. Reopen, load project 4. **Expected:** - Mode is still "Live Coding" in metadata - First evaluation initializes correctly --- ## Troubleshooting Guide ### Issue: "Cannot find module '@flok-editor/session'" **Cause:** The block-eval code references types from flok's session package. **Solution:** - Our implementation in `/src/lib/editor/block-eval.ts` is standalone and doesn't need this - If TypeScript complains, we don't use the `Document` type from flok - Our editor integration passes callbacks, not Document objects ### Issue: Flashing doesn't appear **Cause:** flashField not added to editor extensions **Solution:** 1. Verify `import { flashField } from '../editor/block-eval'` in Editor.svelte 2. Verify `flashField()` is in the extensions array 3. Check browser console for errors ### Issue: Block evaluation evaluates wrong text **Cause:** Block detection algorithm confused by comment syntax **Solution:** - Csound uses `;` for line comments - Blank line detection: `line.text.trim().length === 0` - If commented lines interfere, update `getBlock()` to treat `;`-only lines as blank ### Issue: Live coding mode doesn't persist **Cause:** Strategy state lost between evaluations **Solution:** - Verify `currentStrategy` is stored in `$state()`, not recreated each time - Check that `$effect` only recreates strategy when mode actually changes - Ensure LiveCodingStrategy instance is reused ### Issue: Performance doesn't start in live coding mode **Cause:** `startPerformance()` not called or called before compilation **Solution:** - Check logs for compilation errors - Verify `compileOrchestra()` returns `success: true` - Ensure `startPerformance()` is awaited ### Issue: Mode changes don't take effect **Cause:** Project not reloaded after metadata update **Solution:** - `handleMetadataUpdate()` should call `projectEditor.updateMetadata()` - This should update `projectEditor.currentProject` - `$effect` watching `currentProject?.mode` should trigger - Verify effect dependencies are correct --- ## File Structure Reference ### New Files Created ``` /src/lib/editor/block-eval.ts - Block evaluation utilities (✅ COMPLETE) /src/lib/csound/execution-strategies.ts - Strategy pattern (❌ TODO) ``` ### Modified Files ``` /src/lib/project-system/types.ts - Added ProjectMode type (✅ COMPLETE) /src/lib/project-system/project-manager.ts - Added mode handling (✅ COMPLETE) /src/lib/components/ui/FileBrowser.svelte - Added mode selector UI (✅ COMPLETE) /src/lib/stores/projectEditor.svelte.ts - Updated metadata types (✅ COMPLETE) /src/App.svelte - Updated handlers (✅ PARTIAL - needs strategy integration) /src/lib/components/editor/Editor.svelte - Needs block eval integration (❌ TODO) /src/lib/contexts/app-context.ts - Might need mode-aware csound init (❌ TODO) ``` --- ## Key Design Principles to Remember 1. **No Fallbacks**: If livecoding fails, it fails. Don't silently fall back to composition mode. 2. **Mode Per Project**: Mode is project metadata, not global state. Different tabs could have different modes. 3. **Persistent = Reuse Low-Level API**: Persistence isn't a csound setting, it's about calling `compileOrchestra()` + `startPerformance()` instead of `evaluate()`. 4. **Block = Paragraph**: A block is text separated by blank lines. This is the standard live coding convention. 5. **Flash for Feedback**: Always flash evaluated code so user knows what executed. 6. **Strategy Owns State**: LiveCodingStrategy tracks initialization state, not the store or app. --- ## Implementation Order Follow this exact order to minimize issues: 1. ✅ **Phase 1**: Editor integration (visual feedback works first) 2. ✅ **Phase 2**: Create execution strategies (logic isolated and testable) 3. ✅ **Phase 3**: Wire strategies to App.svelte (connect pieces) 4. ✅ **Phase 4**: Verify instance management (make sure persistence works) 5. ✅ **Phase 5**: Test thoroughly (catch edge cases) --- ## Success Criteria ### Composition Mode - [✅] Full document evaluation on Cmd+Enter - [✅] Flash effect shows what was evaluated - [✅] Fresh instance every time (no state leakage) ### Live Coding Mode - [❌] First evaluation initializes from full document - [❌] Subsequent evaluations process blocks incrementally - [❌] Score events trigger sounds immediately - [❌] Channel updates affect running performance - [❌] Instrument redefinition works - [❌] Instance persists across evaluations - [❌] Logs show block evaluations, not full recompilations ### Both Modes - [✅] Mode selection UI works - [✅] Mode persists in database - [❌] Mode switching cleans up properly - [❌] Keyboard shortcuts work consistently --- ## Additional Notes ### Why Ephemeral Default Makes Sense Now The original implementation used ephemeral mode by default because Web Audio reconnection after `csound.reset()` was unreliable. However, in live coding mode: - We **don't call `reset()`** between evaluations - We **don't call `evaluate()`** which destroys the instance - We use **low-level API** (`compileOrchestra`, `sendScoreEvent`) which reuses the instance So "persistent mode" is actually achieved by **avoiding the methods that destroy/recreate**. ### Why We Adapted cm-eval Instead of Using It The flok cm-eval package: - Assumes a `Document` object with an `evaluate()` method - Is tightly coupled to flok's session architecture - Uses their specific remote evaluation system Our needs: - Evaluate blocks locally (no remote) - Different document format (CSD vs raw code) - Integrate with existing Csound store Solution: Extract the core block detection and flash logic, adapt for our architecture. ### Csound Score Event Syntax Quick Reference For testing live coding mode: ```csound ; Start instrument 1 at time 0, duration 2 seconds, amplitude 0.5 i 1 0 2 0.5 ; Start instrument 1 now (time 0), indefinite duration (-1) i 1 0 -1 0.5 ; Turn off all instances of instrument 1 i -1 0 0 ; Function table: create table 1, size 8192, sine wave f 1 0 8192 10 1 ``` --- ## Next Session Checklist When you resume implementation: - [ ] Read this document thoroughly - [ ] Verify all completed work with `pnpm build` - [ ] Start with Phase 1 (Editor integration) - [ ] Test each phase before moving to next - [ ] Update this document if you deviate from the plan - [ ] Document any issues found and solutions --- ## Questions to Resolve None at this time. The architecture is well-defined and ready for implementation. --- **Document Version:** 1.0 **Last Updated:** 2025-01-15 **Status:** Ready for Phase 1 implementation