docs_muse_merge.html
html
sha256:42bc547653458bb15e283222247af0237872d9cb5c2a72ad2ca1c111ed2c0ca4
feat(9A-4 F7): overseer-run provenance enrichment API for S…
Human
minor
⚠ breaking
76 days ago
| 1 | {% extends "musehub/base.html" %} |
| 2 | |
| 3 | {% block container_extra_class %} page-container{% endblock %} |
| 4 | {% block body_class %}app-shell{% endblock %} |
| 5 | {% block title %}Merge Engine — Muse Developer Docs{% endblock %} |
| 6 | {% block page_json %}{"page":"docs-merge"}{% endblock %} |
| 7 | |
| 8 | {% block content %} |
| 9 | <div class="devdocs"> |
| 10 | <div class="devdocs-layout"> |
| 11 | |
| 12 | {# ── Sidebar ─────────────────────────────────────────────────────────────── #} |
| 13 | <aside class="devdocs-sidebar"> |
| 14 | <nav class="devdocs-nav" aria-label="Docs navigation"> |
| 15 | <div class="devdocs-nav-group"> |
| 16 | <div class="devdocs-nav-group-label">Sections</div> |
| 17 | {% for slug, num, title, desc in phases %} |
| 18 | <a class="devdocs-nav-link devdocs-nav-link--phase{% if slug == current %} devdocs-nav-link--active{% endif %}" |
| 19 | href="/muse/{{ slug }}">{{ num }} {{ title }}</a> |
| 20 | {% endfor %} |
| 21 | </div> |
| 22 | <div class="devdocs-nav-group"> |
| 23 | <div class="devdocs-nav-group-label">On this page</div> |
| 24 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#overview">Overview</a> |
| 25 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#granularity">Three altitudes</a> |
| 26 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#engine-model">Engine model</a> |
| 27 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#strategy">Strategy reference</a> |
| 28 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#history">History modes</a> |
| 29 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#on-conflict">--on-conflict</a> |
| 30 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#explain">--explain</a> |
| 31 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#local-merge">muse merge</a> |
| 32 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#proposal-merge">Proposal merge</a> |
| 33 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#safe-protocol">Safe merge protocol</a> |
| 34 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#harmony">Harmony integration</a> |
| 35 | <a class="devdocs-nav-link devdocs-nav-link--sub" href="#cli">CLI reference</a> |
| 36 | </div> |
| 37 | </nav> |
| 38 | </aside> |
| 39 | |
| 40 | {# ── Main content ─────────────────────────────────────────────────────────── #} |
| 41 | <main class="devdocs-content" id="main-content"> |
| 42 | |
| 43 | <div class="devdocs-breadcrumb"> |
| 44 | <a href="/muse">Developer Docs</a> |
| 45 | <span>›</span> |
| 46 | <span>Merge Engine</span> |
| 47 | </div> |
| 48 | |
| 49 | <div class="devdocs-phase-header"> |
| 50 | <span class="devdocs-phase-num">PHASE 05</span> |
| 51 | <h1 class="devdocs-phase-title">Merge Engine</h1> |
| 52 | <p class="devdocs-phase-desc"> |
| 53 | Muse merges at three altitudes — directory, file, and symbol — and resolves |
| 54 | conflicts at the right level for each one. Where Git applies a single line-level |
| 55 | diff to every file, Muse applies the merge algorithm that matches the content: |
| 56 | recursive three-way merge for code, overlay for config, snapshot for binary |
| 57 | domains, or replay for time-series data. The strategy, history mode, and |
| 58 | conflict fallback are all independently configurable per merge. Harmony sits |
| 59 | underneath, learning from every resolved conflict so future merges need less |
| 60 | human intervention. |
| 61 | </p> |
| 62 | </div> |
| 63 | |
| 64 | <div class="devdocs-callout"> |
| 65 | {{ icon("info", 16, "devdocs-callout-icon") }} |
| 66 | <div> |
| 67 | <strong>Merge ≠ conflict.</strong> Most Muse merges complete without conflicts. |
| 68 | The three-level model means that changes to different symbols in the same file — |
| 69 | the most common parallel-work pattern — are auto-merged without a conflict marker. |
| 70 | </div> |
| 71 | </div> |
| 72 | |
| 73 | {# ── Overview ──────────────────────────────────────────────────────────── #} |
| 74 | <section class="devdocs-section" id="overview"> |
| 75 | <h2>Overview</h2> |
| 76 | <p> |
| 77 | Git merges are line-level: two edits to different lines of the same function are |
| 78 | "no conflict" even if they produce broken code together. Two edits to the |
| 79 | <em>same line</em> always conflict even if they touch different semantic units. |
| 80 | </p> |
| 81 | <p> |
| 82 | Muse flips this: the unit of merging is the <strong>symbol</strong> — a function, |
| 83 | class, variable, or domain-defined atom. Two agents editing different symbols in |
| 84 | the same file never conflict. Two agents editing the same symbol always produce an |
| 85 | inspectable three-way diff at the symbol level, not at an arbitrary line boundary. |
| 86 | </p> |
| 87 | <p> |
| 88 | The practical effect: teams working on the same file in parallel see far fewer |
| 89 | spurious conflicts, and when a real conflict does occur, the diff is semantically |
| 90 | meaningful — it shows exactly which function changed and why, not which line number |
| 91 | happened to collide. |
| 92 | </p> |
| 93 | </section> |
| 94 | |
| 95 | {# ── Three altitudes ───────────────────────────────────────────────────── #} |
| 96 | <section class="devdocs-section" id="granularity"> |
| 97 | <h2>Three altitudes</h2> |
| 98 | <p> |
| 99 | The merge engine descends from coarse to fine, stopping at the level where the |
| 100 | content is cleanly separable. |
| 101 | </p> |
| 102 | |
| 103 | <table class="devdocs-table"> |
| 104 | <thead><tr><th>Altitude</th><th>Unit</th><th>When it fires</th><th>Conflict address example</th></tr></thead> |
| 105 | <tbody> |
| 106 | <tr> |
| 107 | <td><strong>Directory</strong></td> |
| 108 | <td>A directory subtree</td> |
| 109 | <td>One branch adds a directory the other deletes, or two branches diverge on the same directory with overlapping paths</td> |
| 110 | <td><code>src/auth/</code></td> |
| 111 | </tr> |
| 112 | <tr> |
| 113 | <td><strong>File</strong></td> |
| 114 | <td>A whole file</td> |
| 115 | <td>Binary files, files the domain treats as atomic (e.g. <code>.mid</code>, lock files), or files where both branches made changes the domain cannot split into symbols</td> |
| 116 | <td><code>src/config.json</code></td> |
| 117 | </tr> |
| 118 | <tr> |
| 119 | <td><strong>Symbol</strong></td> |
| 120 | <td>A function, class, variable, or domain atom</td> |
| 121 | <td>Code domain, identity domain, or any domain implementing <code>diff_symbols()</code>; two edits to the <em>same</em> symbol are a conflict; two edits to <em>different</em> symbols in the same file are auto-merged</td> |
| 122 | <td><code>src/auth/tokens.py::validate_token</code></td> |
| 123 | </tr> |
| 124 | </tbody> |
| 125 | </table> |
| 126 | |
| 127 | <div class="devdocs-callout"> |
| 128 | {{ icon("info", 16, "devdocs-callout-icon") }} |
| 129 | <div> |
| 130 | A conflict address like <code>src/auth/tokens.py::validate_token</code> uniquely |
| 131 | identifies the exact symbol in conflict. <code>muse conflicts --json</code> returns |
| 132 | the full list after any merge that does not complete cleanly. |
| 133 | </div> |
| 134 | </div> |
| 135 | |
| 136 | <div class="devdocs-code-block"> |
| 137 | <div class="devdocs-code-header"> |
| 138 | <span class="devdocs-code-lang">bash</span> |
| 139 | <span class="devdocs-code-label">list conflict addresses after a partial merge</span> |
| 140 | </div> |
| 141 | <pre><code>muse conflicts --json</code></pre> |
| 142 | </div> |
| 143 | <div class="devdocs-code-block devdocs-code-block--output"> |
| 144 | <div class="devdocs-code-header"> |
| 145 | <span class="devdocs-code-lang">json</span> |
| 146 | <span class="devdocs-code-label">output</span> |
| 147 | </div> |
| 148 | <pre><code>[ |
| 149 | { <span class="tok-key">"path"</span>: <span class="tok-str">"src/auth/tokens.py::validate_token"</span>, <span class="tok-key">"kind"</span>: <span class="tok-str">"symbol"</span> }, |
| 150 | { <span class="tok-key">"path"</span>: <span class="tok-str">"pyproject.toml"</span>, <span class="tok-key">"kind"</span>: <span class="tok-str">"file"</span> } |
| 151 | ]</code></pre> |
| 152 | </div> |
| 153 | </section> |
| 154 | |
| 155 | {# ── Engine model ──────────────────────────────────────────────────────── #} |
| 156 | <section class="devdocs-section" id="engine-model"> |
| 157 | <h2>Engine model</h2> |
| 158 | <p> |
| 159 | Every merge is parameterised by two independent dimensions: the |
| 160 | <strong>diff unit</strong> (how the engine splits content into comparable atoms) |
| 161 | and the <strong>resolution policy</strong> (what the engine does when those atoms |
| 162 | diverge). Named strategies are shorthand for specific combinations of these two |
| 163 | dimensions. |
| 164 | </p> |
| 165 | |
| 166 | <table class="devdocs-table"> |
| 167 | <thead> |
| 168 | <tr> |
| 169 | <th>Named strategy</th> |
| 170 | <th>Diff unit</th> |
| 171 | <th>Resolution policy</th> |
| 172 | <th>Typical use</th> |
| 173 | </tr> |
| 174 | </thead> |
| 175 | <tbody> |
| 176 | <tr> |
| 177 | <td><code>recursive</code></td> |
| 178 | <td>Symbol (code domain) or line (text fallback)</td> |
| 179 | <td>Three-way merge; conflict on divergent edits to the same atom</td> |
| 180 | <td>Source code, structured text</td> |
| 181 | </tr> |
| 182 | <tr> |
| 183 | <td><code>overlay</code></td> |
| 184 | <td>Key (for maps) or element (for sequences)</td> |
| 185 | <td>Ours wins on key collision; additions from both sides kept</td> |
| 186 | <td>Config files, package manifests</td> |
| 187 | </tr> |
| 188 | <tr> |
| 189 | <td><code>snapshot</code></td> |
| 190 | <td>Whole file (atomic)</td> |
| 191 | <td>Conflict if both branches modified the file; no sub-file merge attempted</td> |
| 192 | <td>Binary blobs, MIDI, images</td> |
| 193 | </tr> |
| 194 | <tr> |
| 195 | <td><code>replay</code></td> |
| 196 | <td>Domain-defined event (e.g. note, frame, row)</td> |
| 197 | <td>Events replayed in causal order; duplicates suppressed</td> |
| 198 | <td>Event-sourced domains, time-series</td> |
| 199 | </tr> |
| 200 | <tr> |
| 201 | <td><code>ours</code></td> |
| 202 | <td>Whole file</td> |
| 203 | <td>Always adopt ours; incoming branch changes discarded on conflict</td> |
| 204 | <td>Generated files, lock files (use with a Harmony policy instead)</td> |
| 205 | </tr> |
| 206 | <tr> |
| 207 | <td><code>theirs</code></td> |
| 208 | <td>Whole file</td> |
| 209 | <td>Always adopt theirs; local branch changes discarded on conflict</td> |
| 210 | <td>Vendor files that must match upstream exactly</td> |
| 211 | </tr> |
| 212 | </tbody> |
| 213 | </table> |
| 214 | |
| 215 | <div class="devdocs-callout"> |
| 216 | {{ icon("warn", 16, "devdocs-callout-icon") }} |
| 217 | <div> |
| 218 | <strong><code>ours</code> and <code>theirs</code> silently discard work.</strong> |
| 219 | Prefer a Harmony policy (<code>muse harmony policy-add --action prefer-ours |
| 220 | --path-pattern "*.lock"</code>) so the decision is recorded, auditable, and |
| 221 | automatically applied on future merges. Use <code>ours</code>/<code>theirs</code> |
| 222 | as a strategy only when you have confirmed that one side is entirely superseded. |
| 223 | </div> |
| 224 | </div> |
| 225 | </section> |
| 226 | |
| 227 | {# ── Strategy reference ────────────────────────────────────────────────── #} |
| 228 | <section class="devdocs-section" id="strategy"> |
| 229 | <h2>Strategy reference</h2> |
| 230 | <p> |
| 231 | Pass <code>--strategy</code> to <code>muse merge</code> or |
| 232 | <code>muse hub proposal merge</code>. The default is <code>recursive</code>. |
| 233 | </p> |
| 234 | |
| 235 | <div class="devdocs-code-block"> |
| 236 | <pre><span class="tok-cmt"># recursive — default; symbol-level three-way merge for code</span> |
| 237 | <span class="tok-fn">muse</span> merge feat/auth |
| 238 | |
| 239 | <span class="tok-cmt"># overlay — take additions from both sides; ours wins on key collision</span> |
| 240 | <span class="tok-fn">muse</span> merge feat/config <span class="tok-kw">--strategy</span> overlay |
| 241 | |
| 242 | <span class="tok-cmt"># snapshot — atomic file merge; conflicts if both sides touched the file</span> |
| 243 | <span class="tok-fn">muse</span> merge feat/audio <span class="tok-kw">--strategy</span> snapshot |
| 244 | |
| 245 | <span class="tok-cmt"># replay — causal event ordering; domain must implement replay semantics</span> |
| 246 | <span class="tok-fn">muse</span> merge feat/events <span class="tok-kw">--strategy</span> replay |
| 247 | |
| 248 | <span class="tok-cmt"># ours — always take our version on conflict (⚠ discards incoming work)</span> |
| 249 | <span class="tok-fn">muse</span> merge feat/generated <span class="tok-kw">--strategy</span> ours |
| 250 | |
| 251 | <span class="tok-cmt"># theirs — always take their version on conflict (⚠ discards local work)</span> |
| 252 | <span class="tok-fn">muse</span> merge upstream/vendor <span class="tok-kw">--strategy</span> theirs</pre> |
| 253 | </div> |
| 254 | |
| 255 | <h3 class="devdocs-subsection-title"><a href="#strategy-dry-run">Dry-run before committing</a></h3> |
| 256 | <p> |
| 257 | Always switch to the target branch first. <code>muse merge --dry-run</code> |
| 258 | returns the merge plan without touching the working tree or MERGE_STATE. |
| 259 | </p> |
| 260 | |
| 261 | <div class="devdocs-code-block"> |
| 262 | <pre><span class="tok-fn">muse</span> switch dev |
| 263 | <span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--dry-run</span> <span class="tok-kw">--json</span></pre> |
| 264 | </div> |
| 265 | <div class="devdocs-code-block devdocs-code-block--output"> |
| 266 | <div class="devdocs-code-header"> |
| 267 | <span class="devdocs-code-lang">json</span> |
| 268 | <span class="devdocs-code-label">dry-run output (fast-forward)</span> |
| 269 | </div> |
| 270 | <pre><code>{ |
| 271 | <span class="tok-key">"merge_type"</span>: <span class="tok-str">"fast_forward"</span>, |
| 272 | <span class="tok-key">"fast_forward"</span>: <span class="tok-kw">true</span>, |
| 273 | <span class="tok-key">"conflicts"</span>: [], |
| 274 | <span class="tok-key">"files_added"</span>: <span class="tok-num">3</span>, |
| 275 | <span class="tok-key">"files_modified"</span>: <span class="tok-num">7</span>, |
| 276 | <span class="tok-key">"files_removed"</span>: <span class="tok-num">0</span>, |
| 277 | <span class="tok-key">"commits_to_merge"</span>: <span class="tok-num">12</span> |
| 278 | }</code></pre> |
| 279 | </div> |
| 280 | </section> |
| 281 | |
| 282 | {# ── History modes ─────────────────────────────────────────────────────── #} |
| 283 | <section class="devdocs-section" id="history"> |
| 284 | <h2>History modes</h2> |
| 285 | <p> |
| 286 | <code>--history</code> controls the shape of the commit graph after a successful |
| 287 | merge. This is independent of the conflict resolution strategy. |
| 288 | </p> |
| 289 | |
| 290 | <table class="devdocs-table"> |
| 291 | <thead> |
| 292 | <tr> |
| 293 | <th>Mode</th> |
| 294 | <th>Graph shape</th> |
| 295 | <th>Harmony effect</th> |
| 296 | <th>When to use</th> |
| 297 | </tr> |
| 298 | </thead> |
| 299 | <tbody> |
| 300 | <tr> |
| 301 | <td><code>merge</code> (default)</td> |
| 302 | <td>Two-parent merge commit; full feature branch history preserved</td> |
| 303 | <td>All conflict resolutions from the branch are learned individually</td> |
| 304 | <td>Long-lived features, shared work — preserve full attribution</td> |
| 305 | </tr> |
| 306 | <tr> |
| 307 | <td><code>squash</code></td> |
| 308 | <td>Single commit on target branch; feature branch commits collapsed</td> |
| 309 | <td>One resolution record per conflict path (the squash commit)</td> |
| 310 | <td>Cleanup before merging experimental branches</td> |
| 311 | </tr> |
| 312 | <tr> |
| 313 | <td><code>rebase</code></td> |
| 314 | <td>Feature branch commits replayed linearly on top of target</td> |
| 315 | <td>Each replayed commit can generate independent Harmony records</td> |
| 316 | <td>Linear history preference; CI pipelines that require no merge commits</td> |
| 317 | </tr> |
| 318 | </tbody> |
| 319 | </table> |
| 320 | |
| 321 | <div class="devdocs-code-block"> |
| 322 | <pre><span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--history</span> merge <span class="tok-cmt"># default</span> |
| 323 | <span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--history</span> squash <span class="tok-cmt"># collapse to one commit</span> |
| 324 | <span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--history</span> rebase <span class="tok-cmt"># replay commits linearly</span></pre> |
| 325 | </div> |
| 326 | |
| 327 | <div class="devdocs-callout"> |
| 328 | {{ icon("info", 16, "devdocs-callout-icon") }} |
| 329 | <div> |
| 330 | <strong>Harmony learns from all three modes.</strong> Whether you use merge, |
| 331 | squash, or rebase, Harmony records conflict resolutions from the resulting |
| 332 | commit(s). The key difference is attribution granularity: <code>merge</code> |
| 333 | preserves the full per-commit resolution history; <code>squash</code> collapses |
| 334 | it to one record per conflict path. |
| 335 | </div> |
| 336 | </div> |
| 337 | </section> |
| 338 | |
| 339 | {# ── --on-conflict ─────────────────────────────────────────────────────── #} |
| 340 | <section class="devdocs-section" id="on-conflict"> |
| 341 | <h2>The <code>--on-conflict</code> flag</h2> |
| 342 | <p> |
| 343 | <code>--on-conflict</code> is the conflict <em>fallback</em> policy — what the engine |
| 344 | does when a conflict cannot be auto-resolved by Harmony and requires a decision. |
| 345 | It does not replace Harmony; it fires only when Harmony has nothing to offer. |
| 346 | </p> |
| 347 | |
| 348 | <table class="devdocs-table"> |
| 349 | <thead><tr><th>Value</th><th>Behaviour</th><th>When to use</th></tr></thead> |
| 350 | <tbody> |
| 351 | <tr> |
| 352 | <td><code>escalate</code> (default)</td> |
| 353 | <td>Merge pauses at the conflict. Working tree contains conflict markers. <code>muse conflicts --json</code> lists what needs manual resolution.</td> |
| 354 | <td>Always, unless you have a specific automated pipeline reason to use the others</td> |
| 355 | </tr> |
| 356 | <tr> |
| 357 | <td><code>ours</code></td> |
| 358 | <td>Automatically adopt our version for all unresolved conflicts. Merge completes without pausing.</td> |
| 359 | <td>Automated pipelines where incoming changes must never override ours (e.g. merging back from a deploy branch)</td> |
| 360 | </tr> |
| 361 | <tr> |
| 362 | <td><code>theirs</code></td> |
| 363 | <td>Automatically adopt their version for all unresolved conflicts. Merge completes without pausing.</td> |
| 364 | <td>Automated pipelines where incoming changes always take precedence (e.g. syncing a vendor mirror)</td> |
| 365 | </tr> |
| 366 | </tbody> |
| 367 | </table> |
| 368 | |
| 369 | <div class="devdocs-code-block"> |
| 370 | <pre><span class="tok-cmt"># default — pause for human inspection</span> |
| 371 | <span class="tok-fn">muse</span> merge feat/auth |
| 372 | |
| 373 | <span class="tok-cmt"># CI pipeline — take ours for unresolved conflicts, never block</span> |
| 374 | <span class="tok-fn">muse</span> merge deploy/rc12 <span class="tok-kw">--on-conflict</span> ours |
| 375 | |
| 376 | <span class="tok-cmt"># vendor sync — take theirs for everything unresolved</span> |
| 377 | <span class="tok-fn">muse</span> merge upstream/vendor <span class="tok-kw">--strategy</span> snapshot <span class="tok-kw">--on-conflict</span> theirs</pre> |
| 378 | </div> |
| 379 | |
| 380 | <div class="devdocs-callout"> |
| 381 | {{ icon("warn", 16, "devdocs-callout-icon") }} |
| 382 | <div> |
| 383 | <code>--on-conflict ours</code> and <code>--on-conflict theirs</code> silently |
| 384 | discard work. The defaults (<code>escalate</code>) are safe — they pause the merge |
| 385 | and let you inspect. Only use the non-default values in fully automated pipelines |
| 386 | where you have already audited what will be discarded. |
| 387 | </div> |
| 388 | </div> |
| 389 | </section> |
| 390 | |
| 391 | {# ── --explain ─────────────────────────────────────────────────────────── #} |
| 392 | <section class="devdocs-section" id="explain"> |
| 393 | <h2>The <code>--explain</code> flag</h2> |
| 394 | <p> |
| 395 | <code>muse merge --explain</code> returns a per-path decision trace showing exactly |
| 396 | why each file was merged the way it was — which strategy fired, which Harmony tier |
| 397 | (if any) resolved it automatically, and what the outcome was. |
| 398 | </p> |
| 399 | |
| 400 | <div class="devdocs-code-block"> |
| 401 | <div class="devdocs-code-header"> |
| 402 | <span class="devdocs-code-lang">bash</span> |
| 403 | <span class="devdocs-code-label">merge with full decision trace</span> |
| 404 | </div> |
| 405 | <pre><code>muse merge feat/auth --explain --json</code></pre> |
| 406 | </div> |
| 407 | <div class="devdocs-code-block devdocs-code-block--output"> |
| 408 | <div class="devdocs-code-header"> |
| 409 | <span class="devdocs-code-lang">json</span> |
| 410 | <span class="devdocs-code-label">output — per-path decision trace</span> |
| 411 | </div> |
| 412 | <pre><code>{ |
| 413 | <span class="tok-key">"status"</span>: <span class="tok-str">"ok"</span>, |
| 414 | <span class="tok-key">"explain"</span>: [ |
| 415 | { |
| 416 | <span class="tok-key">"path"</span>: <span class="tok-str">"src/auth/tokens.py::validate_token"</span>, |
| 417 | <span class="tok-key">"altitude"</span>: <span class="tok-str">"symbol"</span>, |
| 418 | <span class="tok-key">"outcome"</span>: <span class="tok-str">"auto_merged"</span>, |
| 419 | <span class="tok-key">"strategy"</span>: <span class="tok-str">"recursive"</span>, |
| 420 | <span class="tok-key">"harmony_tier"</span>: <span class="tok-kw">null</span>, |
| 421 | <span class="tok-key">"note"</span>: <span class="tok-str">"changes were in different symbol regions"</span> |
| 422 | }, |
| 423 | { |
| 424 | <span class="tok-key">"path"</span>: <span class="tok-str">"src/auth/tokens.py::refresh_token"</span>, |
| 425 | <span class="tok-key">"altitude"</span>: <span class="tok-str">"symbol"</span>, |
| 426 | <span class="tok-key">"outcome"</span>: <span class="tok-str">"harmony_applied"</span>, |
| 427 | <span class="tok-key">"strategy"</span>: <span class="tok-str">"recursive"</span>, |
| 428 | <span class="tok-key">"harmony_tier"</span>: <span class="tok-num">2</span>, |
| 429 | <span class="tok-key">"resolution_id"</span>: <span class="tok-str">"7c1a9e3f4d82..."</span>, |
| 430 | <span class="tok-key">"confidence"</span>: <span class="tok-num">1.0</span>, |
| 431 | <span class="tok-key">"note"</span>: <span class="tok-str">"replayed human-verified resolution from 2026-05-14"</span> |
| 432 | }, |
| 433 | { |
| 434 | <span class="tok-key">"path"</span>: <span class="tok-str">"pyproject.toml"</span>, |
| 435 | <span class="tok-key">"altitude"</span>: <span class="tok-str">"file"</span>, |
| 436 | <span class="tok-key">"outcome"</span>: <span class="tok-str">"conflict"</span>, |
| 437 | <span class="tok-key">"strategy"</span>: <span class="tok-str">"overlay"</span>, |
| 438 | <span class="tok-key">"harmony_tier"</span>: <span class="tok-kw">null</span>, |
| 439 | <span class="tok-key">"note"</span>: <span class="tok-str">"both branches modified 'version' key"</span> |
| 440 | } |
| 441 | ] |
| 442 | }</code></pre> |
| 443 | </div> |
| 444 | |
| 445 | <p> |
| 446 | <code>--explain</code> is safe with <code>--dry-run</code> — the full decision trace |
| 447 | is computed without modifying the working tree: |
| 448 | </p> |
| 449 | |
| 450 | <div class="devdocs-code-block"> |
| 451 | <pre><span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--dry-run</span> <span class="tok-kw">--explain</span> <span class="tok-kw">--json</span></pre> |
| 452 | </div> |
| 453 | </section> |
| 454 | |
| 455 | {# ── muse merge ────────────────────────────────────────────────────────── #} |
| 456 | <section class="devdocs-section" id="local-merge"> |
| 457 | <h2><code>muse merge</code> — local merge</h2> |
| 458 | <p> |
| 459 | <code>muse merge <branch></code> merges the named branch into the current branch. |
| 460 | The current branch must be the <em>target</em> — switch to it before merging. |
| 461 | </p> |
| 462 | |
| 463 | <div class="devdocs-code-block"> |
| 464 | <pre><span class="tok-cmt"># always switch to the target branch first</span> |
| 465 | <span class="tok-fn">muse</span> switch dev |
| 466 | <span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--json</span></pre> |
| 467 | </div> |
| 468 | <div class="devdocs-code-block devdocs-code-block--output"> |
| 469 | <div class="devdocs-code-header"> |
| 470 | <span class="devdocs-code-lang">json</span> |
| 471 | <span class="devdocs-code-label">clean merge output</span> |
| 472 | </div> |
| 473 | <pre><code>{ |
| 474 | <span class="tok-key">"status"</span>: <span class="tok-str">"ok"</span>, |
| 475 | <span class="tok-key">"merge_type"</span>: <span class="tok-str">"three_way"</span>, |
| 476 | <span class="tok-key">"auto_resolved"</span>: [<span class="tok-str">"src/auth/tokens.py::refresh_token"</span>], |
| 477 | <span class="tok-key">"conflicts"</span>: [], |
| 478 | <span class="tok-key">"commit_id"</span>: <span class="tok-str">"sha256:4e8b2f1a..."</span> |
| 479 | }</code></pre> |
| 480 | </div> |
| 481 | |
| 482 | <h3>Flags</h3> |
| 483 | <table class="devdocs-table"> |
| 484 | <thead><tr><th>Flag</th><th>Default</th><th>Description</th></tr></thead> |
| 485 | <tbody> |
| 486 | <tr><td><code>--strategy</code></td><td><code>recursive</code></td><td>Merge strategy: <code>recursive</code>, <code>overlay</code>, <code>snapshot</code>, <code>replay</code>, <code>ours</code>, <code>theirs</code></td></tr> |
| 487 | <tr><td><code>--history</code></td><td><code>merge</code></td><td>History mode: <code>merge</code>, <code>squash</code>, <code>rebase</code></td></tr> |
| 488 | <tr><td><code>--on-conflict</code></td><td><code>escalate</code></td><td>Conflict fallback: <code>escalate</code>, <code>ours</code>, <code>theirs</code></td></tr> |
| 489 | <tr><td><code>--dry-run</code></td><td>off</td><td>Compute merge plan without touching working tree or MERGE_STATE</td></tr> |
| 490 | <tr><td><code>--explain</code></td><td>off</td><td>Include per-path decision trace in JSON output</td></tr> |
| 491 | <tr><td><code>--no-harmony-autoupdate</code></td><td>off</td><td>Skip Harmony auto-apply for this merge (still records conflicts on commit)</td></tr> |
| 492 | <tr><td><code>--json</code></td><td>off</td><td>Structured JSON output</td></tr> |
| 493 | </tbody> |
| 494 | </table> |
| 495 | |
| 496 | <h3>Exit codes</h3> |
| 497 | <table class="devdocs-table"> |
| 498 | <thead><tr><th>Exit code</th><th>Meaning</th></tr></thead> |
| 499 | <tbody> |
| 500 | <tr><td><code>0</code></td><td>Merge complete (including fast-forward)</td></tr> |
| 501 | <tr><td><code>1</code></td><td>Merge paused — unresolved conflicts in working tree</td></tr> |
| 502 | <tr><td><code>2</code></td><td>Error — invalid arguments, bad branch reference, or cannot merge a branch into itself</td></tr> |
| 503 | </tbody> |
| 504 | </table> |
| 505 | |
| 506 | <h3 class="devdocs-subsection-title"><a href="#local-merge-resolving">Resolving conflicts</a></h3> |
| 507 | |
| 508 | <p> |
| 509 | When <code>muse merge</code> exits 1, the working tree contains conflict markers. |
| 510 | The conflict address format (<code>file.py::Symbol</code> for symbol-level, |
| 511 | <code>file.py</code> for file-level) is used in both <code>muse conflicts --json</code> |
| 512 | and <code>muse resolve</code>. |
| 513 | </p> |
| 514 | |
| 515 | <div class="devdocs-code-block"> |
| 516 | <pre><span class="tok-cmt"># 1. List what needs resolving</span> |
| 517 | <span class="tok-fn">muse</span> conflicts <span class="tok-kw">--json</span> |
| 518 | |
| 519 | <span class="tok-cmt"># 2. Read the conflicted file — understand all three sections: |
| 520 | # <<<<<<< ours [modified] ← what YOUR branch has |
| 521 | # ||||||| base ← common ancestor |
| 522 | # ======= theirs [modified] ← what the INCOMING branch has |
| 523 | # >>>>>>> end conflict</span> |
| 524 | |
| 525 | <span class="tok-cmt"># 3. Edit the file to the correct merged result incorporating both sides</span> |
| 526 | |
| 527 | <span class="tok-cmt"># 4. Mark resolved — stages automatically</span> |
| 528 | <span class="tok-fn">muse</span> resolve src/auth/tokens.py::validate_token <span class="tok-kw">--json</span> |
| 529 | <span class="tok-cmt"># or resolve all at once:</span> |
| 530 | <span class="tok-fn">muse</span> resolve <span class="tok-kw">--all</span> <span class="tok-kw">--json</span> |
| 531 | |
| 532 | <span class="tok-cmt"># 5. Commit — Harmony records the resolution (human_verified=true, confidence=1.0)</span> |
| 533 | <span class="tok-fn">muse</span> commit -m <span class="tok-str">"merge: resolve validate_token conflict"</span> \ |
| 534 | <span class="tok-kw">--agent-id</span> claude-code <span class="tok-kw">--model-id</span> claude-sonnet-4-6 <span class="tok-kw">--sign</span></pre> |
| 535 | </div> |
| 536 | </section> |
| 537 | |
| 538 | {# ── Proposal merge ────────────────────────────────────────────────────── #} |
| 539 | <section class="devdocs-section" id="proposal-merge"> |
| 540 | <h2>Proposal merge</h2> |
| 541 | <p> |
| 542 | <code>muse hub proposal merge</code> merges a proposal's source branch into its |
| 543 | target branch on the server. It accepts the same strategy, history, and on-conflict |
| 544 | flags as local <code>muse merge</code>. The surface is intentionally identical so |
| 545 | that an automated CI pipeline and a human reviewing a proposal see the same |
| 546 | abstraction. |
| 547 | </p> |
| 548 | |
| 549 | <div class="devdocs-code-block"> |
| 550 | <pre><span class="tok-cmt"># merge proposal af54753d with squash history and overlay strategy</span> |
| 551 | <span class="tok-fn">muse</span> -C ~/ecosystem/musehub hub proposal merge af54753d \ |
| 552 | <span class="tok-kw">--strategy</span> recursive \ |
| 553 | <span class="tok-kw">--history</span> squash \ |
| 554 | <span class="tok-kw">--json</span> | jq <span class="tok-str">'.status'</span> |
| 555 | |
| 556 | <span class="tok-cmt"># check what the merge would do before committing</span> |
| 557 | <span class="tok-fn">muse</span> -C ~/ecosystem/musehub hub proposal merge af54753d \ |
| 558 | <span class="tok-kw">--dry-run</span> <span class="tok-kw">--explain</span> <span class="tok-kw">--json</span></pre> |
| 559 | </div> |
| 560 | |
| 561 | <h3>Strategy × history matrix — pick one of each</h3> |
| 562 | <table class="devdocs-table"> |
| 563 | <thead> |
| 564 | <tr> |
| 565 | <th></th> |
| 566 | <th><code>--history merge</code></th> |
| 567 | <th><code>--history squash</code></th> |
| 568 | <th><code>--history rebase</code></th> |
| 569 | </tr> |
| 570 | </thead> |
| 571 | <tbody> |
| 572 | <tr> |
| 573 | <td><code>--strategy recursive</code></td> |
| 574 | <td>Symbol-level three-way, full history</td> |
| 575 | <td>Symbol-level three-way, collapsed history</td> |
| 576 | <td>Symbol-level three-way, linear history</td> |
| 577 | </tr> |
| 578 | <tr> |
| 579 | <td><code>--strategy overlay</code></td> |
| 580 | <td>Key-level merge, full history</td> |
| 581 | <td>Key-level merge, collapsed</td> |
| 582 | <td>Key-level merge, linear</td> |
| 583 | </tr> |
| 584 | <tr> |
| 585 | <td><code>--strategy snapshot</code></td> |
| 586 | <td>Atomic file, full history</td> |
| 587 | <td>Atomic file, collapsed</td> |
| 588 | <td>Atomic file, linear</td> |
| 589 | </tr> |
| 590 | </tbody> |
| 591 | </table> |
| 592 | |
| 593 | <h3>Proposal merge flags</h3> |
| 594 | <table class="devdocs-table"> |
| 595 | <thead><tr><th>Flag</th><th>Default</th><th>Description</th></tr></thead> |
| 596 | <tbody> |
| 597 | <tr><td><code>--strategy</code></td><td><code>recursive</code></td><td>Same values as <code>muse merge --strategy</code></td></tr> |
| 598 | <tr><td><code>--history</code></td><td><code>merge_commit</code></td><td><code>merge_commit</code>, <code>squash</code>, <code>rebase</code> (alias: <code>merge</code> → <code>merge_commit</code>)</td></tr> |
| 599 | <tr><td><code>--on-conflict</code></td><td><code>escalate</code></td><td>Same values as <code>muse merge --on-conflict</code></td></tr> |
| 600 | <tr><td><code>--dry-run</code></td><td>off</td><td>Return merge plan without writing anything server-side</td></tr> |
| 601 | <tr><td><code>--explain</code></td><td>off</td><td>Include per-path decision trace</td></tr> |
| 602 | <tr><td><code>--json</code></td><td>off</td><td>Structured JSON output</td></tr> |
| 603 | </tbody> |
| 604 | </table> |
| 605 | </section> |
| 606 | |
| 607 | {# ── Safe merge protocol ───────────────────────────────────────────────── #} |
| 608 | <section class="devdocs-section" id="safe-protocol"> |
| 609 | <h2>Safe merge protocol</h2> |
| 610 | <p> |
| 611 | After experiencing 8 accidental reverts from under-inspected merges, this workspace |
| 612 | adopted a four-step pre-merge checklist. Follow it every time — it takes less than |
| 613 | a minute and prevents hours of recovery work. |
| 614 | </p> |
| 615 | |
| 616 | <div class="devdocs-callout"> |
| 617 | {{ icon("warn", 16, "devdocs-callout-icon") }} |
| 618 | <div> |
| 619 | <strong>Create backup branches before every non-trivial merge.</strong> |
| 620 | <code>muse branch feat/my-thing-backup</code> creates a pointer at the current |
| 621 | feature branch HEAD without switching. If the merge goes wrong, the backup |
| 622 | preserves the work. |
| 623 | </div> |
| 624 | </div> |
| 625 | |
| 626 | <h3 class="devdocs-subsection-title"><a href="#safe-step1">Step 1 — Topology check</a></h3> |
| 627 | <p> |
| 628 | Find the merge base. A fast-forward topology means no conflicts are possible. |
| 629 | </p> |
| 630 | |
| 631 | <div class="devdocs-code-block"> |
| 632 | <pre><span class="tok-fn">muse</span> merge-base dev feat/my-thing <span class="tok-kw">--json</span></pre> |
| 633 | </div> |
| 634 | <div class="devdocs-code-block devdocs-code-block--output"> |
| 635 | <div class="devdocs-code-header"> |
| 636 | <span class="devdocs-code-lang">json</span> |
| 637 | <span class="devdocs-code-label">output</span> |
| 638 | </div> |
| 639 | <pre><code>{ |
| 640 | <span class="tok-key">"merge_base"</span>: <span class="tok-str">"sha256:abc123..."</span>, |
| 641 | <span class="tok-key">"commit_a"</span>: <span class="tok-str">"sha256:abc123..."</span>, <span class="tok-cmt">// dev tip</span> |
| 642 | <span class="tok-key">"commit_b"</span>: <span class="tok-str">"sha256:def456..."</span> <span class="tok-cmt">// feat/my-thing tip</span> |
| 643 | }</code></pre> |
| 644 | </div> |
| 645 | <p> |
| 646 | If <code>merge_base == commit_a</code> (dev tip), the merge is a pure fast-forward |
| 647 | — all feature branch commits are linear descendants of dev. No conflict is possible; |
| 648 | skip Step 3 if you're confident. |
| 649 | </p> |
| 650 | |
| 651 | <h3 class="devdocs-subsection-title"><a href="#safe-step2">Step 2 — Inspect unique commits</a></h3> |
| 652 | <p> |
| 653 | List the commits that will be merged, then spot-check the diff for surprising changes. |
| 654 | </p> |
| 655 | |
| 656 | <div class="devdocs-code-block"> |
| 657 | <pre><span class="tok-cmt"># commits on feat/my-thing not yet on dev</span> |
| 658 | <span class="tok-fn">muse</span> rev-list dev..feat/my-thing <span class="tok-kw">--json</span> | jq <span class="tok-str">'.commits[] | {message, committed_at}'</span> |
| 659 | |
| 660 | <span class="tok-cmt"># overall diff summary</span> |
| 661 | <span class="tok-fn">muse</span> diff dev feat/my-thing <span class="tok-kw">--json</span> | jq <span class="tok-str">'keys'</span></pre> |
| 662 | </div> |
| 663 | |
| 664 | <h3 class="devdocs-subsection-title"><a href="#safe-step3">Step 3 — Dry-run merge</a></h3> |
| 665 | <p> |
| 666 | Switch to the target branch <em>first</em>, then dry-run. Running dry-run while |
| 667 | still on the feature branch will error ("Cannot merge a branch into itself"). |
| 668 | </p> |
| 669 | |
| 670 | <div class="devdocs-code-block"> |
| 671 | <pre><span class="tok-fn">muse</span> switch dev <span class="tok-cmt"># ← must switch first</span> |
| 672 | <span class="tok-fn">muse</span> merge feat/my-thing <span class="tok-kw">--dry-run</span> <span class="tok-kw">--explain</span> <span class="tok-kw">--json</span> | jq</pre> |
| 673 | </div> |
| 674 | |
| 675 | <p>Verify:</p> |
| 676 | <ul> |
| 677 | <li><code>"conflicts": []</code> — no conflicts expected</li> |
| 678 | <li><code>"fast_forward": true</code> — pure FF if applicable</li> |
| 679 | <li>The <code>explain</code> list accounts for all files you expect to change</li> |
| 680 | </ul> |
| 681 | |
| 682 | <h3 class="devdocs-subsection-title"><a href="#safe-step4">Step 4 — Merge, test, push</a></h3> |
| 683 | |
| 684 | <div class="devdocs-code-block"> |
| 685 | <pre><span class="tok-cmt"># merge</span> |
| 686 | <span class="tok-fn">muse</span> merge feat/my-thing <span class="tok-kw">--json</span> |
| 687 | |
| 688 | <span class="tok-cmt"># run relevant tests</span> |
| 689 | <span class="tok-fn">muse</span> code test <span class="tok-kw">--json</span> |
| 690 | |
| 691 | <span class="tok-cmt"># push (use --force-with-lease if remote ref needs advancing after FF merge)</span> |
| 692 | <span class="tok-fn">muse</span> push local dev |
| 693 | <span class="tok-cmt"># or if rejected as diverged after a fast-forward:</span> |
| 694 | <span class="tok-fn">muse</span> push local dev <span class="tok-kw">--force-with-lease</span> |
| 695 | |
| 696 | <span class="tok-cmt"># promote dev → main when ready</span> |
| 697 | <span class="tok-fn">muse</span> switch main |
| 698 | <span class="tok-fn">muse</span> merge dev <span class="tok-kw">--dry-run</span> <span class="tok-kw">--json</span> |
| 699 | <span class="tok-fn">muse</span> merge dev <span class="tok-kw">--json</span> |
| 700 | <span class="tok-fn">muse</span> push local main |
| 701 | <span class="tok-fn">muse</span> switch dev</pre> |
| 702 | </div> |
| 703 | |
| 704 | <div class="devdocs-callout"> |
| 705 | {{ icon("info", 16, "devdocs-callout-icon") }} |
| 706 | <div> |
| 707 | <strong><code>--force-with-lease</code> vs <code>--force</code></strong> — after a |
| 708 | fast-forward merge locally, the remote ref may not have been updated (common after |
| 709 | a previous push was rejected). <code>--force-with-lease</code> is safe: it advances |
| 710 | the ref only if the remote tip matches your last fetch. <code>--force</code> skips |
| 711 | that check. Always prefer <code>--force-with-lease</code>. |
| 712 | </div> |
| 713 | </div> |
| 714 | </section> |
| 715 | |
| 716 | {# ── Harmony integration ───────────────────────────────────────────────── #} |
| 717 | <section class="devdocs-section" id="harmony"> |
| 718 | <h2>Harmony integration</h2> |
| 719 | <p> |
| 720 | Harmony is the conflict-resolution memory layer that sits beneath every merge. |
| 721 | It fires automatically — you never call it directly during a merge. The relationship |
| 722 | is: |
| 723 | </p> |
| 724 | |
| 725 | <ul> |
| 726 | <li><strong>Merge engine</strong> detects which paths conflict and at which altitude.</li> |
| 727 | <li><strong>Harmony</strong> checks whether a prior resolution exists for each conflicting |
| 728 | path, and if so, applies it automatically (Tier 1–3). No human intervention needed.</li> |
| 729 | <li>For paths Harmony cannot resolve (Tier 4), the merge pauses and conflict markers |
| 730 | appear in the working tree.</li> |
| 731 | <li>When you manually resolve and commit, Harmony records the outcome with |
| 732 | <code>human_verified = true</code> and <code>confidence = 1.0</code>. The same |
| 733 | conflict auto-resolves on the next merge.</li> |
| 734 | </ul> |
| 735 | |
| 736 | <div class="devdocs-code-block"> |
| 737 | <pre><span class="tok-cmt"># merge — Harmony auto-applies anything it knows</span> |
| 738 | <span class="tok-fn">muse</span> merge feat/auth <span class="tok-kw">--json</span> |
| 739 | <span class="tok-cmt"># ✔ [harmony] auto-resolved: src/auth/tokens.py::refresh_token (Tier 2)</span> |
| 740 | <span class="tok-cmt"># CONFLICT: pyproject.toml (Tier 4 — new)</span> |
| 741 | |
| 742 | <span class="tok-cmt"># resolve manually, commit — Harmony learns</span> |
| 743 | <span class="tok-fn">muse</span> resolve pyproject.toml <span class="tok-kw">--json</span> |
| 744 | <span class="tok-fn">muse</span> commit -m <span class="tok-str">"merge: resolve pyproject.toml version conflict"</span> \ |
| 745 | <span class="tok-kw">--agent-id</span> claude-code <span class="tok-kw">--model-id</span> claude-sonnet-4-6 <span class="tok-kw">--sign</span> |
| 746 | <span class="tok-cmt"># ✅ harmony: recorded resolution for 'pyproject.toml'</span> |
| 747 | |
| 748 | <span class="tok-cmt"># next merge — auto-resolved</span> |
| 749 | <span class="tok-fn">muse</span> merge feat/other <span class="tok-kw">--json</span> |
| 750 | <span class="tok-cmt"># ✔ [harmony] auto-resolved: pyproject.toml (Tier 2)</span></pre> |
| 751 | </div> |
| 752 | |
| 753 | <p> |
| 754 | For the full Harmony reference — confidence thresholds, policies, semantic |
| 755 | fingerprinting, audit log, and escalation — see |
| 756 | <a href="/muse/harmony">Phase 05: Harmony</a>. |
| 757 | </p> |
| 758 | </section> |
| 759 | |
| 760 | {# ── CLI Reference ─────────────────────────────────────────────────────── #} |
| 761 | <section class="devdocs-section" id="cli"> |
| 762 | <h2>CLI reference</h2> |
| 763 | <p>All commands accept <code>--json</code>.</p> |
| 764 | |
| 765 | <table class="devdocs-table"> |
| 766 | <thead><tr><th>Task</th><th>Command</th></tr></thead> |
| 767 | <tbody> |
| 768 | <tr><td>Merge a branch into current</td><td><code>muse merge <branch> --json</code></td></tr> |
| 769 | <tr><td>Dry-run merge plan</td><td><code>muse merge <branch> --dry-run --json</code></td></tr> |
| 770 | <tr><td>Merge with decision trace</td><td><code>muse merge <branch> --explain --json</code></td></tr> |
| 771 | <tr><td>Three-way strategy (default)</td><td><code>muse merge <branch> --strategy recursive</code></td></tr> |
| 772 | <tr><td>Overlay strategy (config)</td><td><code>muse merge <branch> --strategy overlay</code></td></tr> |
| 773 | <tr><td>Snapshot strategy (binary)</td><td><code>muse merge <branch> --strategy snapshot</code></td></tr> |
| 774 | <tr><td>Squash history</td><td><code>muse merge <branch> --history squash</code></td></tr> |
| 775 | <tr><td>Rebase history</td><td><code>muse merge <branch> --history rebase</code></td></tr> |
| 776 | <tr><td>Auto-take ours on conflict</td><td><code>muse merge <branch> --on-conflict ours</code></td></tr> |
| 777 | <tr><td>Find merge base</td><td><code>muse merge-base <a> <b> --json</code></td></tr> |
| 778 | <tr><td>List conflicts after partial merge</td><td><code>muse conflicts --json</code></td></tr> |
| 779 | <tr><td>Mark a path resolved (stages it)</td><td><code>muse resolve <path> --json</code></td></tr> |
| 780 | <tr><td>Mark all conflicts resolved</td><td><code>muse resolve --all --json</code></td></tr> |
| 781 | <tr><td>Commits not yet on target</td><td><code>muse rev-list <target>..<source> --json</code></td></tr> |
| 782 | <tr><td>Merge a proposal (server-side)</td><td><code>muse hub proposal merge <id> --json</code></td></tr> |
| 783 | <tr><td>Proposal merge dry-run</td><td><code>muse hub proposal merge <id> --dry-run --explain --json</code></td></tr> |
| 784 | <tr><td>Skip Harmony for one merge</td><td><code>muse merge <branch> --no-harmony-autoupdate</code></td></tr> |
| 785 | </tbody> |
| 786 | </table> |
| 787 | |
| 788 | <nav class="devdocs-phase-nav" aria-label="Phase navigation"> |
| 789 | <a class="devdocs-phase-nav-btn devdocs-phase-nav-btn--prev" href="/muse/intelligence"> |
| 790 | {{ icon("arrow-left", 14) }} |
| 791 | Phase 04: Code Intelligence |
| 792 | </a> |
| 793 | <a class="devdocs-phase-nav-btn devdocs-phase-nav-btn--next" href="/muse/harmony"> |
| 794 | Phase 06: Harmony |
| 795 | {{ icon("arrow-right", 14) }} |
| 796 | </a> |
| 797 | </nav> |
| 798 | </section> |
| 799 | |
| 800 | </main> |
| 801 | </div>{# /.devdocs-layout #} |
| 802 | </div>{# /.devdocs #} |
| 803 | {% endblock %} |
| 804 | |
| 805 | {% block page_scripts %} |
| 806 | {% endblock %} |
File History
1 commit
sha256:42bc547653458bb15e283222247af0237872d9cb5c2a72ad2ca1c111ed2c0ca4
feat(9A-4 F7): overseer-run provenance enrichment API for S…
Human
minor
⚠
76 days ago