# Copy-on-Update Versioning Pattern **Version**: 1.0.0 **Purpose**: Non-destructive component and screen modifications **Applies to**: component-creator, screen-scaffolder, enhancer **Does NOT apply to**: component-expander (uses in-place updates) --- ## Overview When modifying existing components or screens, create versioned copies instead of overwriting originals. This ensures non-destructive editing and preserves component history. **Core Principle**: Always start with UXM file, even if user mentions `.md` file. --- ## When to Use Copy-on-Update ### ✅ Use Copy-on-Update For: 1. **Creating component that already exists** (component-creator) - User: "Create a submit button" - Existing: `submit-button.uxm` already exists - Action: Ask user, offer to create versioned copy 2. **Enhancing component fidelity** (enhancer) - User: "Enhance button to production fidelity" - Existing: `button.uxm` (fidelity=sketch) - Action: Create `button-v2.uxm` (fidelity=production) 3. **Creating screen that already exists** (screen-scaffolder) - User: "Create a login screen" - Existing: `login-screen.uxm` already exists - Action: Ask user, offer to create versioned copy 4. **Modifying layout/structure** (any skill) - User: "Change button.md to use different colors" - Existing: `button.uxm` exists - Action: Create `button-v2.uxm` and `button-v2.md` with changes ### ❌ Do NOT Use Copy-on-Update For: 1. **Adding states to components** (component-expander only) - User: "Add hover state to my button" - Action: Modify `button.uxm` in place (same component, enhanced) - Reason: Adding states enhances the same component ID --- ## Version Numbering ### File Naming Pattern ``` Original: {base-name}.uxm (e.g., submit-button.uxm) Version 2: {base-name}-v2.uxm (e.g., submit-button-v2.uxm) Version 3: {base-name}-v3.uxm (e.g., submit-button-v3.uxm) ``` **Rules**: - Original file has NO version suffix - Versions start at `-v2` (not `-v1`) - Version number matches across `.uxm` and `.md` files - For screens: All three files use same suffix (`.uxm`, `.md`, `.rendered.md`) ### Component ID Pattern The `id` field in the `.uxm` file must match the filename: ```json // Original: submit-button.uxm { "id": "submit-button", "version": "1.0.0" } // Version 2: submit-button-v2.uxm { "id": "submit-button-v2", "version": "1.1.0" } ``` ### Semantic Versioning **Format**: `MAJOR.MINOR.PATCH` (e.g., `1.2.3`) **Increment rules**: - **Minor version** (1.X.0): New features, fidelity enhancements, layout changes - Original: 1.0.0 → First copy: 1.1.0 → Second copy: 1.2.0 - **Major version** (X.0.0): Breaking changes (manual only, not auto-incremented) - **Patch version** (1.0.X): Not used in copy-on-update pattern **Copy-on-update always increments minor version**. --- ## Detection Algorithm ### Step 1: Parse Component/Screen Name Extract the base name from user request, ignoring `.uxm` or `.md` extensions: ```bash # Examples: "Update submit-button.md" → componentName="submit-button" "Enhance button to production" → componentName="button" "Create a login screen" → screenName="login-screen" ``` ### Step 2: Check if Original Exists ```bash # For components: if [[ -f "./fluxwing/components/${componentName}.uxm" ]]; then echo "Component exists - entering copy-on-update mode" else echo "Component does not exist - entering create mode" fi # For screens: if [[ -f "./fluxwing/screens/${screenName}.uxm" ]]; then echo "Screen exists - entering copy-on-update mode" else echo "Screen does not exist - entering create mode" fi ``` ### Step 3: Find Highest Existing Version If original exists, find the highest versioned copy: ```bash # Initialize maxVersion=1 # Original is considered v1 # Find all versioned files for file in ./fluxwing/components/${componentName}-v*.uxm; do if [[ -f "$file" ]]; then # Extract version number (e.g., submit-button-v3.uxm → 3) version=$(echo "$file" | grep -oP 'v\K\d+') if [[ $version -gt $maxVersion ]]; then maxVersion=$version fi fi done # Calculate next version nextVersion=$((maxVersion + 1)) newId="${componentName}-v${nextVersion}" echo "Creating version: ${newId}" ``` **Edge case - Version gaps**: If v2 is missing but v3 and v5 exist, use MAX(versions)+1 = v6. Gaps are acceptable. ### Step 4: Load Source for Copying Determine which file to base the new version on: ```bash # Check if highest version exists if [[ -f "./fluxwing/components/${componentName}-v${maxVersion}.uxm" ]]; then # Copy from highest version (e.g., v3 if it exists) sourceFile="${componentName}-v${maxVersion}.uxm" else # Copy from original (v1) sourceFile="${componentName}.uxm" fi echo "Basing new version on: ${sourceFile}" ``` --- ## Metadata Updates ### Required Changes in .uxm File When creating a versioned copy, update these fields: ```json { "id": "submit-button-v2", // Add -v{N} suffix "version": "1.1.0", // Increment minor version "metadata": { "created": "2024-10-11T12:00:00Z", // Preserve from original "modified": "2024-10-12T15:30:00Z", // Update to current timestamp "fidelity": "detailed" // Update if enhancing } } ``` ### Field-by-Field Rules | Field | Action | Example | |-------|--------|---------| | `id` | Add `-v{N}` suffix | `submit-button` → `submit-button-v2` | | `version` | Increment minor | `1.0.0` → `1.1.0` → `1.2.0` | | `metadata.created` | **Preserve** from original | `2024-10-11T12:00:00Z` (unchanged) | | `metadata.modified` | **Update** to current time | `2024-10-12T15:30:00Z` (new) | | `metadata.fidelity` | Update if enhancing | `sketch` → `detailed` | | `metadata.name` | Keep same display name | `Submit Button` (unchanged) | | `metadata.description` | Preserve or enhance | May be improved | ### Current Timestamp Format Use ISO 8601 format: ```bash # Generate current timestamp currentTimestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # Example: 2024-10-12T15:30:45Z ``` --- ## User Communication ### Clear Messaging Patterns Always inform user about versioning actions: **✅ Good examples**: ``` "Found existing submit-button (v1.0.0). Creating submit-button-v2..." "Created submit-button-v2 (v1.1.0) with production fidelity. Original preserved." "Enhanced login-screen → login-screen-v2. Files created: - ./fluxwing/screens/login-screen-v2.uxm - ./fluxwing/screens/login-screen-v2.md - ./fluxwing/screens/login-screen-v2.rendered.md" ``` **❌ Bad examples**: ``` "Updated submit-button" (doesn't mention versioning) "Modified button.md" (implies in-place change) "Created new component" (vague, no version info) ``` ### Interactive Prompts When component/screen already exists, ask user for choice: ``` Component 'submit-button' already exists (v1.0.0). Options: (a) Create new version (submit-button-v2) (b) Create with different name (c) Cancel operation What would you like to do? ``` **Handle user responses**: - **(a)**: Proceed with copy-on-update (create v2) - **(b)**: Ask for new name, create with that name - **(c)**: Cancel, no files created --- ## File System Layout ### Components Example ``` ./fluxwing/components/ ├── submit-button.uxm # Original (v1.0.0, fidelity=sketch) ├── submit-button.md ├── submit-button-v2.uxm # First update (v1.1.0, fidelity=detailed) ├── submit-button-v2.md ├── submit-button-v3.uxm # Second update (v1.2.0, fidelity=production) └── submit-button-v3.md ``` ### Screens Example ``` ./fluxwing/screens/ ├── login-screen.uxm # Original (v1.0.0) ├── login-screen.md ├── login-screen.rendered.md ├── login-screen-v2.uxm # First update (v1.1.0) ├── login-screen-v2.md └── login-screen-v2.rendered.md ``` **Important**: Screens have THREE files per version, all with matching suffix. --- ## Edge Cases ### Edge Case 1: User Mentions .md File Only **Request**: "Update submit-button.md to use darker colors" **Handling**: 1. Parse component name: `submit-button` 2. Check for `submit-button.uxm` (ALWAYS start with UXM, not .md) 3. If `.uxm` exists: Enter copy-on-update mode 4. Create `submit-button-v2.uxm` AND `submit-button-v2.md` 5. Apply color changes to BOTH files 6. Inform user: "Updated both submit-button-v2.uxm and .md (UXM-first approach)" **Why**: UXM file is source of truth. Changes to .md alone would break synchronization. ### Edge Case 2: Multiple Rapid Updates **Requests**: 1. User: "Enhance button to detailed fidelity" 2. User: "Now enhance to production fidelity" **Handling**: 1. First request: Create `button-v2.uxm` (detailed fidelity) 2. Second request: - Find highest version (v2) - Create `button-v3.uxm` (production fidelity) - Base v3 on v2 content **Result**: Three versions exist (original, v2, v3), each preserved. **Note**: If user says "Add hover state" then "Add focus state", component-expander handles this with in-place updates (NO versioning). ### Edge Case 3: Version Number Gaps **Scenario**: `button.uxm` exists, `button-v3.uxm` exists, but `button-v2.uxm` is missing **Handling**: 1. Find ALL versions: v1 (original), v3 2. MAX(versions) = 3 3. Next version = 4 4. Create `button-v4.uxm` **Result**: Gaps in sequence are acceptable. Always use MAX+1. ### Edge Case 4: Mixing Versioned and Original References **Scenario**: User creates `button-v2`, then says "enhance button to production" **Handling**: 1. "enhance button" likely refers to latest version 2. Check for highest version: v2 3. Base new version (v3) on v2 4. User can explicitly reference: "enhance button-v1 to production" if they want original **Guideline**: Default to highest version when ambiguous. --- ## Integration with Skills ### For component-creator **Load this module**: ✅ Yes **When to use**: - Before invoking designer agent - Check if `./fluxwing/components/{component-id}.uxm` exists - If exists: Ask user, offer copy-on-update - If creating version: Pass base component info to agent **Agent prompt addition**: ``` If creating versioned copy: 1. Read existing {component-id}.uxm 2. Find highest version using algorithm above 3. Generate new ID: {component-id}-v{N+1} 4. Copy content from source version 5. Apply requested changes 6. Update metadata (created, modified, version) 7. Save as {component-id}-v{N+1}.uxm and .md ``` ### For screen-scaffolder **Load this module**: ✅ Yes **When to use**: - Before Phase 1 (component creation) - Check if `./fluxwing/screens/{screen-name}.uxm` exists - If exists: Ask user, offer copy-on-update - If creating version: Pass to composer agent **Agent prompt addition**: ``` If creating versioned screen: 1. Read existing {screen-name}.uxm 2. Find highest version 3. Generate new ID: {screen-name}-v{N+1} 4. Create THREE files: - {screen-name}-v{N+1}.uxm - {screen-name}-v{N+1}.md - {screen-name}-v{N+1}.rendered.md 5. All files use same version suffix ``` ### For enhancer **Load this module**: ✅ Yes **When to use**: - Always use copy-on-update for fidelity enhancements - Each fidelity level creates new version - Original fidelity preserved **Agent prompt addition**: ``` When enhancing component: 1. Read current {component-id}.uxm 2. Note current fidelity level 3. Find highest version 4. Create {component-id}-v{N+1}.uxm and .md 5. Apply fidelity enhancements to new version 6. Update metadata.fidelity field 7. Update metadata.version (increment minor) 8. DO NOT overwrite original ``` ### For component-expander **Load this module**: ❌ **NO - Do not load** **Reason**: component-expander uses in-place updates. Adding states enhances the same component ID, not creating a new version. **Keep existing behavior**: ``` When adding states: 1. Read {component-name}.uxm 2. Modify in place (same file) 3. Add new states to behavior.states array 4. Append state sections to .md file 5. Update metadata.modified timestamp 6. Save (overwrite existing files) ``` --- ## Validation Checklist After creating versioned copy, verify: - [ ] Filename has `-v{N}` suffix (e.g., `submit-button-v2.uxm`) - [ ] `id` field matches filename (e.g., `"id": "submit-button-v2"`) - [ ] `version` field incremented correctly (e.g., `1.0.0` → `1.1.0`) - [ ] `metadata.created` preserved from original - [ ] `metadata.modified` set to current timestamp - [ ] Both `.uxm` and `.md` created with same version suffix - [ ] For screens: All three files created (`.uxm`, `.md`, `.rendered.md`) - [ ] Original files unchanged - [ ] JSON schema validation passes - [ ] Variables match between `.uxm` and `.md` --- ## Quick Reference ### Version Suffix Rules | Item | Format | Example | |------|--------|---------| | Original filename | `{name}.uxm` | `button.uxm` | | Original ID | `{name}` | `button` | | Original version | `1.0.0` | `1.0.0` | | First copy filename | `{name}-v2.uxm` | `button-v2.uxm` | | First copy ID | `{name}-v2` | `button-v2` | | First copy version | `1.1.0` | `1.1.0` | | Second copy filename | `{name}-v3.uxm` | `button-v3.uxm` | | Second copy ID | `{name}-v3` | `button-v3` | | Second copy version | `1.2.0` | `1.2.0` | ### Skills Decision Tree ``` User requests modification │ ├─ "Add hover/focus/disabled state" │ └─ Use component-expander │ └─ In-place update (NO versioning) │ ├─ "Enhance to X fidelity" │ └─ Use enhancer │ └─ Copy-on-update (create v2) │ ├─ "Create component" (exists) │ └─ Use component-creator │ └─ Ask user, offer copy-on-update │ ├─ "Create screen" (exists) │ └─ Use screen-scaffolder │ └─ Ask user, offer copy-on-update │ └─ "Update/modify .md file" └─ Any skill └─ UXM-first, then copy-on-update ``` --- ## Examples ### Example 1: Enhance Component Fidelity **User request**: "Enhance button to production fidelity" **Current state**: - `button.uxm` exists (v1.0.0, fidelity=sketch) - `button.md` exists **Process**: 1. Parse name: `button` 2. Check existence: `button.uxm` exists ✓ 3. Find versions: Only original (v1) exists 4. Next version: v2 5. Create: `button-v2.uxm` and `button-v2.md` 6. Copy content from `button.uxm` 7. Update: - `id`: `button` → `button-v2` - `version`: `1.0.0` → `1.1.0` - `metadata.fidelity`: `sketch` → `production` - `metadata.modified`: current timestamp - `metadata.created`: preserve from original 8. Apply production-level enhancements 9. Validate both files **Result**: - `button.uxm` unchanged (v1.0.0, sketch) - `button-v2.uxm` created (v1.1.0, production) - `button-v2.md` created - User message: "Enhanced button → button-v2 (fidelity: production). Original preserved." ### Example 2: Create Existing Screen **User request**: "Create a login screen" **Current state**: - `login-screen.uxm` exists (v1.0.0) - `login-screen.md` exists - `login-screen.rendered.md` exists **Process**: 1. Parse name: `login-screen` 2. Check existence: `login-screen.uxm` exists ✓ 3. Ask user: ``` Screen 'login-screen' already exists (v1.0.0). Options: (a) Create new version (login-screen-v2) (b) Create with different name (c) Cancel operation What would you like to do? ``` 4. User chooses: (a) Create new version 5. Find versions: Only original (v1) exists 6. Next version: v2 7. Create THREE files: - `login-screen-v2.uxm` - `login-screen-v2.md` - `login-screen-v2.rendered.md` 8. Copy and update metadata 9. Apply any requested changes **Result**: - Original files unchanged - Three new files created with `-v2` suffix - User message: "Created login-screen-v2. Original login-screen preserved." ### Example 3: User Mentions .md Only **User request**: "Update button.md to use Unicode box drawing" **Current state**: - `button.uxm` exists (v1.0.0) - `button.md` exists (ASCII box drawing) **Process**: 1. Parse name: `button` (strip .md extension) 2. **UXM-first**: Check `button.uxm` exists ✓ 3. Find versions: Only original exists 4. Next version: v2 5. Create: `button-v2.uxm` AND `button-v2.md` 6. Apply Unicode box drawing to `.md` 7. Update `.uxm` metadata **Result**: - Both `button-v2.uxm` and `button-v2.md` created - User message: "Updated both button-v2.uxm and .md with Unicode box drawing (UXM-first approach). Original preserved." --- ## Troubleshooting ### Issue: Can't find highest version **Symptom**: Multiple versions exist but algorithm fails **Debug**: ```bash # List all versions ls -1 ./fluxwing/components/button*.uxm # Should show: button.uxm, button-v2.uxm, button-v3.uxm # Test regex extraction for f in ./fluxwing/components/button-v*.uxm; do echo "$f" | grep -oP 'v\K\d+' done # Should output: 2, 3 ``` **Fix**: Ensure version suffix matches pattern `-v{digits}` exactly. ### Issue: Version number collision **Symptom**: Two processes create same version number **Prevention**: Always re-check highest version immediately before creating new file. **Recovery**: If collision occurs, increment again and retry. ### Issue: Metadata.created not preserved **Symptom**: New version has different created timestamp **Fix**: Always read original's `metadata.created` and copy to new version. ```bash # Extract created timestamp from original originalCreated=$(jq -r '.metadata.created' ./fluxwing/components/button.uxm) # Use in new version jq --arg created "$originalCreated" '.metadata.created = $created' button-v2.uxm ``` --- ## Summary **Copy-on-update ensures**: - ✅ Non-destructive editing - ✅ Component history preserved - ✅ Clear version progression - ✅ UXM-first consistency - ✅ User awareness and control **Remember**: - Start with UXM, even if user mentions .md - Always ask user when component/screen exists - Increment minor version automatically - Preserve created timestamp - Update modified timestamp - Create matching .uxm and .md files together --- **End of Copy-on-Update Versioning Pattern Documentation**