muse-attributes.md
markdown
| 1 | # `.museattributes` Reference |
| 2 | |
| 3 | `.museattributes` is a per-repository configuration file that declares merge |
| 4 | strategies for specific paths and dimensions. It lives in the repository root, |
| 5 | alongside `muse-work/`. |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## Purpose |
| 10 | |
| 11 | Without `.museattributes`, every conflict in a three-way merge requires manual |
| 12 | resolution. `.museattributes` lets you encode domain knowledge once so |
| 13 | `muse merge` can skip conflict detection for well-understood cases. |
| 14 | |
| 15 | For example: "this team's changes to the structural layer always win" can be |
| 16 | expressed as a single rule rather than being resolved manually on every merge. |
| 17 | |
| 18 | --- |
| 19 | |
| 20 | ## File Format |
| 21 | |
| 22 | ``` |
| 23 | <path-pattern> <dimension> <strategy> |
| 24 | ``` |
| 25 | |
| 26 | - **path-pattern** — an `fnmatch` glob matched against workspace-relative paths |
| 27 | (e.g. `drums/*`, `src/models/**, `*`) |
| 28 | - **dimension** — a domain-defined dimension name, or `*` to match all dimensions |
| 29 | - **strategy** — `ours | theirs | union | auto | manual` |
| 30 | |
| 31 | Lines beginning with `#` and blank lines are ignored. **First matching rule wins.** |
| 32 | |
| 33 | --- |
| 34 | |
| 35 | ## Strategies |
| 36 | |
| 37 | | Strategy | Behavior | |
| 38 | |---|---| |
| 39 | | `ours` | Take the current branch's version unconditionally. Skip conflict detection. | |
| 40 | | `theirs` | Take the incoming branch's version unconditionally. Skip conflict detection. | |
| 41 | | `union` | Include both sides' changes; fall through to three-way merge. | |
| 42 | | `auto` | Let the merge engine decide (default when no rule matches). | |
| 43 | | `manual` | Flag this path/dimension for mandatory human resolution. | |
| 44 | |
| 45 | --- |
| 46 | |
| 47 | ## Music Domain Examples |
| 48 | |
| 49 | ``` |
| 50 | # Drums are always authoritative — take ours on every dimension: |
| 51 | drums/* * ours |
| 52 | |
| 53 | # Accept a collaborator's harmonic changes on key instruments: |
| 54 | keys/* harmonic theirs |
| 55 | bass/* harmonic theirs |
| 56 | |
| 57 | # Require manual review for all structural changes: |
| 58 | * structural manual |
| 59 | |
| 60 | # Default for everything else: |
| 61 | * * auto |
| 62 | ``` |
| 63 | |
| 64 | ### Music Dimensions |
| 65 | |
| 66 | | Dimension | What it covers | |
| 67 | |---|---| |
| 68 | | `melodic` | Note pitch and pitch-class resolution | |
| 69 | | `rhythmic` | Note start-beat and duration resolution | |
| 70 | | `harmonic` | Pitch-bend event resolution | |
| 71 | | `dynamic` | CC and aftertouch event resolution | |
| 72 | | `structural` | Section and region-level structure | |
| 73 | |
| 74 | > **Implementation status:** Dimension names are parsed and validated. Wiring |
| 75 | > into the merge engine's three-way reconciliation is reserved for a future |
| 76 | > release. Writing dimension-specific rules now is safe — they will take effect |
| 77 | > automatically once the merge engine is updated. |
| 78 | |
| 79 | --- |
| 80 | |
| 81 | ## Generic Domain Example |
| 82 | |
| 83 | The `.museattributes` format is not music-specific. Any domain plugin can define |
| 84 | its own dimension names and path patterns. For a hypothetical genomics plugin: |
| 85 | |
| 86 | ``` |
| 87 | # Reference sequence is always canonical: |
| 88 | reference/* * ours |
| 89 | |
| 90 | # Accept collaborator's annotations: |
| 91 | annotations/* semantic theirs |
| 92 | |
| 93 | # All structural edits require manual review: |
| 94 | * structural manual |
| 95 | |
| 96 | # Default: |
| 97 | * * auto |
| 98 | ``` |
| 99 | |
| 100 | The path-pattern and strategy syntax is identical. Only the dimension names |
| 101 | and path conventions are domain-specific. |
| 102 | |
| 103 | --- |
| 104 | |
| 105 | ## CLI |
| 106 | |
| 107 | ```bash |
| 108 | muse attributes [--json] |
| 109 | ``` |
| 110 | |
| 111 | Reads and displays the `.museattributes` rules from the current repository. |
| 112 | |
| 113 | --- |
| 114 | |
| 115 | ## Behavior During `muse merge` |
| 116 | |
| 117 | 1. `load_attributes(repo_path)` reads the file (if present). |
| 118 | 2. `resolve_strategy(attributes, path, dimension)` returns the first matching rule. |
| 119 | 3. `ours` → take the left (current HEAD) snapshot for this path. |
| 120 | 4. `theirs` → take the right (incoming) snapshot for this path. |
| 121 | 5. All other strategies → fall through to three-way merge. |
| 122 | |
| 123 | If `.museattributes` is absent, `muse merge` behaves as if all paths use `auto`. |
| 124 | |
| 125 | --- |
| 126 | |
| 127 | ## Resolution Precedence |
| 128 | |
| 129 | Rules are evaluated top-to-bottom. The first rule where **both** `path-pattern` |
| 130 | and `dimension` match (via `fnmatch`) wins. |
| 131 | |
| 132 | If no rule matches, `auto` is used. |
| 133 | |
| 134 | --- |
| 135 | |
| 136 | ## Notes |
| 137 | |
| 138 | - `ours` and `theirs` are positional: `ours` = the branch merging INTO (current HEAD), |
| 139 | `theirs` = the branch merging FROM (incoming). |
| 140 | - Path patterns follow POSIX conventions (forward slashes). |
| 141 | - The file is optional. Its absence has no effect on merge correctness. |