Files
gh-trabian-fluxwing-skills/skills/shared/docs/copy-versioning.md
2025-11-30 09:02:33 +08:00

660 lines
18 KiB
Markdown

# 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**