cgcardona / muse public
code-domain-v2.md markdown
989 lines 31.0 KB
dfa7b7aa Add comprehensive docs and supercharged tests for Code Domain V2 (#70) Gabriel Cardona <cgcardona@gmail.com> 1d ago
1 # Code Domain V2 — Complete Reference
2
3 > **Version:** 2.0 (7-phase roadmap)
4 > **Engine:** `muse/plugins/code/` · **No external deps for core analysis**
5 > **Scope:** Every command, module, type, and protocol introduced in the Code Domain V2 roadmap
6
7 ---
8
9 ## Overview
10
11 Code Domain V2 treats a codebase as a **typed, content-addressed symbol graph** — not as a bag of text lines. Every function, class, method, variable, and import becomes a `SymbolRecord` with a stable content-addressed identity (SHA-256). This unlocks operations that are structurally impossible in Git:
12
13 - Track a function through renames and cross-file moves with perfect identity.
14 - Cherry-pick a single named function out of a historical commit.
15 - Detect exact and near-duplicate code across an entire snapshot in O(1).
16 - Predict merge conflicts before writing a single byte.
17 - Enforce architectural invariants as committed rules.
18 - Assign semantic version bumps automatically at commit time.
19 - Coordinate thousands of parallel agents without a central lock server.
20
21 ---
22
23 ## Contents
24
25 1. [Symbol Identity Model](#1-symbol-identity-model)
26 2. [Phase 1 — Provenance & Topology Commands](#2-phase-1--provenance--topology-commands)
27 3. [Phase 2 — Query v2 + Temporal Search](#3-phase-2--query-v2--temporal-search)
28 4. [Phase 3 — Index Infrastructure](#4-phase-3--index-infrastructure)
29 5. [Phase 4 — Symbol Identity V2](#5-phase-4--symbol-identity-v2)
30 6. [Phase 5 — Multi-Agent Coordination Layer](#6-phase-5--multi-agent-coordination-layer)
31 7. [Phase 6 — Merge Engine V2 & Architectural Enforcement](#7-phase-6--merge-engine-v2--architectural-enforcement)
32 8. [Phase 7 — Semantic Versioning](#8-phase-7--semantic-versioning)
33 9. [Call-Graph Tier Commands](#9-call-graph-tier-commands)
34 10. [Architecture Internals](#10-architecture-internals)
35 11. [Type Reference](#11-type-reference)
36
37 ---
38
39 ## 1. Symbol Identity Model
40
41 Every symbol carries four content-addressed hashes and two stable keys:
42
43 | Field | Description |
44 |---|---|
45 | `content_id` | SHA-256 of the full normalized AST (signature + body + metadata). Two symbols are identical iff their `content_id` matches. |
46 | `body_hash` | SHA-256 of the function/class body only (excluding signature and decorators). Matches across renames and decorator changes. |
47 | `signature_id` | SHA-256 of the normalized parameter list and return annotation. Matches across implementation-only changes. |
48 | `metadata_id` *(v2)* | SHA-256 of decorator list + async flag + base classes. Matches when only the implementation or signature changed. |
49 | `canonical_key` *(v2)* | `{file}#{scope}#{kind}#{name}#{lineno}` — stable machine handle for agent-to-agent symbol handoff. |
50 | `qualified_name` | Dotted path within the file (e.g. `MyClass.my_method`). |
51
52 ### Exact Refactor Classification
53
54 Two symbols are classified by comparing their four hashes:
55
56 | Classification | Condition |
57 |---|---|
58 | `unchanged` | `content_id` matches |
59 | `rename` | `body_hash` matches, name differs, same file |
60 | `move` | `content_id` matches, different file, same name |
61 | `rename+move` | `body_hash` matches, different file, different name |
62 | `signature_only` | `body_hash` matches, `signature_id` differs |
63 | `impl_only` | `signature_id` matches, `body_hash` differs |
64 | `metadata_only` | `body_hash` + `signature_id` match, `metadata_id` differs |
65 | `full_rewrite` | Both signature and body changed |
66
67 ---
68
69 ## 2. Phase 1 — Provenance & Topology Commands
70
71 ### `muse lineage ADDRESS`
72
73 Full provenance chain of a named symbol from its first appearance to the present.
74
75 ```
76 muse lineage src/billing.py::compute_total
77 muse lineage src/billing.py::compute_total --commit HEAD~10
78 muse lineage src/billing.py::compute_total --json
79 ```
80
81 **How it works:** Walks all commits in chronological order, scanning `InsertOp`/`DeleteOp`/`ReplaceOp` entries in each `structured_delta`. Rename detection uses `content_id` matching across Insert+Delete pairs within a single commit.
82
83 **Output events:** `created`, `modified`, `renamed_from`, `moved_from`, `deleted`.
84
85 **Flags:**
86 - `--commit REF` — stop history walk at this commit (default: HEAD)
87 - `--json` — emit a JSON array of event objects
88
89 **JSON schema:**
90 ```json
91 [
92 {
93 "event": "created",
94 "commit_id": "a1b2c3d4...",
95 "committed_at": "2026-01-01T00:00:00+00:00",
96 "message": "Initial commit",
97 "address": "src/billing.py::compute_total",
98 "content_id": "sha256..."
99 }
100 ]
101 ```
102
103 ---
104
105 ### `muse api-surface`
106
107 Public API surface of a snapshot — every non-underscore function, class, and method.
108
109 ```
110 muse api-surface
111 muse api-surface --commit v1.0
112 muse api-surface --diff v1.0
113 muse api-surface --json
114 ```
115
116 **With `--diff REF`:** Shows three sections — **Added** (new public symbols), **Removed** (deleted public symbols), **Changed** (same address, different `content_id`).
117
118 **Public** means: `kind` in `{function, class, method, async_function}` and `name` not starting with `_`.
119
120 ---
121
122 ### `muse codemap`
123
124 Semantic topology of the entire codebase at a snapshot.
125
126 ```
127 muse codemap
128 muse codemap --top 10
129 muse codemap --commit HEAD~5
130 muse codemap --json
131 ```
132
133 **What it shows:**
134 - **Modules by size** — ranked by symbol count
135 - **Import graph** — in-degree (how many modules import this one)
136 - **Cycles** — import cycles detected via DFS (a hard architectural smell)
137 - **High-centrality symbols** — functions called from many places (blast-radius risk)
138 - **Boundary files** — high fan-out (imports many), zero fan-in (nothing imports them)
139
140 **Flags:**
141 - `--top N` — show top N entries per section (default: 5)
142 - `--commit REF` — snapshot to analyse
143 - `--json` — structured output
144
145 ---
146
147 ### `muse clones`
148
149 Find exact and near-duplicate symbol clusters across the snapshot.
150
151 ```
152 muse clones
153 muse clones --tier exact
154 muse clones --tier near
155 muse clones --tier both
156 muse clones --commit HEAD~3 --json
157 ```
158
159 **Exact clones:** Same `body_hash` at different addresses. These are literal copy-paste duplicates — same implementation, possibly different name.
160
161 **Near-clones:** Same `signature_id`, different `body_hash`. Same public contract (parameters + return type), diverged implementation — a maintainability risk.
162
163 **Output:** Clusters, one per group, listing all member addresses.
164
165 ---
166
167 ### `muse checkout-symbol ADDRESS --commit REF`
168
169 Restore a single named symbol from a historical commit into the current working tree. Only the target symbol's lines change; everything else is untouched.
170
171 ```
172 muse checkout-symbol src/billing.py::compute_total --commit v1.0
173 muse checkout-symbol src/billing.py::compute_total --commit abc123 --dry-run
174 ```
175
176 **Flags:**
177 - `--commit REF` *(required)* — source commit
178 - `--dry-run` — print the unified diff without writing
179
180 **Safety:** Rejects the operation if the target file cannot be parsed (syntax error) or if the symbol no longer exists at the destination location and the file cannot be safely patched.
181
182 ---
183
184 ### `muse semantic-cherry-pick ADDRESS... --from REF`
185
186 Cherry-pick one or more named symbols from a historical commit. Applies each symbol patch to the working tree at the symbol's current location; appends at the end of the file if the symbol is not present in the current tree.
187
188 ```
189 muse semantic-cherry-pick src/billing.py::compute_total --from v1.0
190 muse semantic-cherry-pick src/billing.py::f1 src/billing.py::f2 --from abc123
191 muse semantic-cherry-pick src/billing.py::compute_total --from v1.0 --dry-run --json
192 ```
193
194 **Flags:**
195 - `--from REF` *(required)* — source commit
196 - `--dry-run` — show what would change without writing
197 - `--json` — structured output with per-symbol patch results
198
199 ---
200
201 ## 3. Phase 2 — Query v2 + Temporal Search
202
203 ### `muse query PREDICATE...`
204
205 Symbol graph predicate DSL — SQL for your codebase.
206
207 ```
208 muse query kind=function language=Python
209 muse query "(kind=function OR kind=method) name^=_"
210 muse query "NOT kind=import file~=billing"
211 muse query kind=function name~=validate --all-commits
212 muse query hash=a3f2c9 --all-commits --first
213 muse query --commit v1.0 kind=class
214 muse query kind=function --json
215 ```
216
217 #### Predicate Grammar (v2)
218
219 ```
220 expr = or_expr
221 or_expr = and_expr ( "OR" and_expr )*
222 and_expr = not_expr ( and_expr )* # implicit AND
223 not_expr = "NOT" primary | primary
224 primary = "(" expr ")" | atom
225 atom = KEY OP VALUE
226 ```
227
228 #### Operators
229
230 | Operator | Meaning |
231 |---|---|
232 | `=` | Exact match (case-insensitive for strings) |
233 | `~=` | Contains substring |
234 | `^=` | Starts with |
235 | `$=` | Ends with |
236 | `!=` | Not equal |
237 | `>=` | Greater than or equal (lineno keys only) |
238 | `<=` | Less than or equal (lineno keys only) |
239
240 #### Keys
241
242 | Key | Type | Description |
243 |---|---|---|
244 | `kind` | string | `function`, `class`, `method`, `variable`, `import`, … |
245 | `language` | string | `Python`, `Go`, `Rust`, `TypeScript`, … |
246 | `name` | string | Bare symbol name |
247 | `qualified_name` | string | Dotted qualified name (e.g. `MyClass.save`) |
248 | `file` | string | File path (relative to repo root) |
249 | `hash` | string | `content_id` prefix (hex) |
250 | `body_hash` | string | `body_hash` prefix |
251 | `signature_id` | string | `signature_id` prefix |
252 | `lineno_gt` | integer | Symbol starts *after* this line number |
253 | `lineno_lt` | integer | Symbol starts *before* this line number |
254
255 #### Flags
256
257 | Flag | Description |
258 |---|---|
259 | `--commit REF` | Query a specific commit (mutually exclusive with `--all-commits`) |
260 | `--all-commits` | Walk all commits, deduplicate by `content_id`, annotate first-seen commit |
261 | `--first` | With `--all-commits`: keep only the first appearance of each unique body |
262 | `--json` | JSON output with `schema_version: 2` wrapper |
263
264 ---
265
266 ### `muse query-history PREDICATE... [--from REF] [--to REF]`
267
268 Temporal symbol search — track matching symbols across a commit range.
269
270 ```
271 muse query-history kind=function language=Python
272 muse query-history name~=validate --from v1.0 --to HEAD
273 muse query-history kind=class --json
274 ```
275
276 **Output:** For each matching symbol address, reports `first_seen`, `last_seen`, `commit_count` (how many commits touched it), and `change_count` (how many times its `content_id` changed).
277
278 **JSON schema:**
279 ```json
280 {
281 "schema_version": 2,
282 "query": "kind=function language=Python",
283 "from_ref": "v1.0",
284 "to_ref": "HEAD",
285 "results": [
286 {
287 "address": "src/billing.py::compute_total",
288 "first_seen": "commit_id...",
289 "last_seen": "commit_id...",
290 "commit_count": 12,
291 "change_count": 3
292 }
293 ]
294 }
295 ```
296
297 ---
298
299 ## 4. Phase 3 — Index Infrastructure
300
301 ### `muse index status`
302
303 Show present/absent/corrupt status and entry counts for all local indexes.
304
305 ```
306 muse index status
307 muse index status --json
308 ```
309
310 ### `muse index rebuild`
311
312 Rebuild one or all indexes by walking the full commit history.
313
314 ```
315 muse index rebuild
316 muse index rebuild --index symbol_history
317 muse index rebuild --index hash_occurrence
318 ```
319
320 **Flags:**
321 - `--index NAME` — rebuild only this index (default: all)
322
323 ### Index Design
324
325 Indexes live under `.muse/indices/` and are:
326 - **Derived** — computed entirely from the commit history.
327 - **Optional** — no command requires them for correctness; they only provide speed.
328 - **Fully rebuildable** — `muse index rebuild` reconstructs them from scratch in one pass.
329 - **Versioned** — `schema_version` field for forward compatibility.
330
331 #### `symbol_history` index
332
333 Maps `symbol_address → list[HistoryEntry]` (chronological). Enables O(1) lineage lookups instead of O(commits × files) scans.
334
335 #### `hash_occurrence` index
336
337 Maps `body_hash → list[symbol_address]`. Enables O(1) clone detection and `muse find-symbol hash=` queries.
338
339 ---
340
341 ## 5. Phase 4 — Symbol Identity V2
342
343 ### New `SymbolRecord` fields
344
345 `SymbolRecord` gains two backward-compatible fields (empty string `""` for pre-v2 records):
346
347 **`metadata_id`**
348 : SHA-256 of the symbol's *metadata wrapper* — decorators + async flag for Python functions, decorator list + base classes for Python classes. Allows distinguishing a decorator change from a body change.
349
350 **`canonical_key`**
351 : `{file}#{scope}#{kind}#{name}#{lineno}` — a stable, unique machine handle for a symbol within a snapshot. Enables agent-to-agent symbol handoff without re-querying. Disambiguates overloaded names and nested scopes.
352
353 ### `muse detect-refactor` (v2 output)
354
355 With `--json`, emits `schema_version: 2` with a richer classification:
356
357 ```json
358 {
359 "schema_version": 2,
360 "from_commit": "abc...",
361 "to_commit": "def...",
362 "total": 3,
363 "events": [
364 {
365 "old_address": "src/billing.py::compute_total",
366 "new_address": "src/billing.py::compute_invoice_total",
367 "old_kind": "function",
368 "new_kind": "function",
369 "exact_classification": "rename",
370 "inferred_refactor": "none",
371 "confidence": 1.0,
372 "evidence": ["body_hash matches a1b2c3d4"],
373 "old_content_id": "ab12cd34",
374 "new_content_id": "ef56gh78",
375 "old_body_hash": "a1b2c3d4",
376 "new_body_hash": "a1b2c3d4"
377 }
378 ]
379 }
380 ```
381
382 **`exact_classification`** values: `rename`, `move`, `rename+move`, `signature_only`, `impl_only`, `metadata_only`, `full_rewrite`, `unchanged`.
383
384 **`inferred_refactor`** values: `extract`, `inline`, `split`, `merge`, `none`.
385
386 ---
387
388 ## 6. Phase 5 — Multi-Agent Coordination Layer
389
390 The coordination layer enables thousands of agents to work on the same codebase simultaneously without stepping on each other. It is **purely advisory** — the VCS engine never reads coordination data for correctness decisions. Agents that ignore it still produce correct commits.
391
392 ### Storage Layout
393
394 ```
395 .muse/coordination/
396 reservations/<uuid>.json advisory symbol lease
397 intents/<uuid>.json declared operation before edit
398 ```
399
400 All records are **write-once** (never mutated) and use TTL-based expiry. Expired records are kept for audit purposes but ignored by all commands.
401
402 ---
403
404 ### `muse reserve ADDRESS... [OPTIONS]`
405
406 Announce intent to edit one or more symbol addresses.
407
408 ```
409 muse reserve src/billing.py::compute_total
410 muse reserve src/billing.py::f1 src/billing.py::f2 --run-id agent-007 --ttl 7200
411 muse reserve src/billing.py::compute_total --op rename
412 muse reserve src/billing.py::compute_total --json
413 ```
414
415 **Flags:**
416 - `--run-id ID` — identifier for this agent/run (default: random UUID)
417 - `--ttl SECONDS` — reservation expiry in seconds (default: 3600)
418 - `--op OPERATION` — declared operation: `rename`, `move`, `extract`, `modify`, `delete`
419 - `--json` — JSON output
420
421 **Conflict detection:** Warns (but never blocks) if any of the requested addresses are already reserved by another active reservation.
422
423 **Reservation schema (v1):**
424 ```json
425 {
426 "schema_version": 1,
427 "reservation_id": "<uuid>",
428 "run_id": "<agent-supplied ID>",
429 "branch": "<current branch>",
430 "addresses": ["src/billing.py::compute_total"],
431 "created_at": "2026-03-18T12:00:00+00:00",
432 "expires_at": "2026-03-18T13:00:00+00:00",
433 "operation": "rename"
434 }
435 ```
436
437 ---
438
439 ### `muse intent ADDRESS... --op OPERATION [OPTIONS]`
440
441 Declare a specific operation before executing it. More precise than a reservation; enables `muse forecast` to produce accurate conflict predictions.
442
443 ```
444 muse intent src/billing.py::compute_total --op rename --detail "rename to compute_invoice_total"
445 muse intent src/billing.py::compute_total --op modify --reservation-id <uuid>
446 ```
447
448 **Flags:**
449 - `--op OPERATION` *(required)* — `rename`, `move`, `extract`, `modify`, `delete`, `refactor`
450 - `--detail TEXT` — free-text description of the planned change
451 - `--reservation-id UUID` — link to an existing reservation
452 - `--run-id ID` — agent identifier
453 - `--json` — JSON output
454
455 **Intent schema (v1):**
456 ```json
457 {
458 "schema_version": 1,
459 "intent_id": "<uuid>",
460 "reservation_id": "<uuid or empty>",
461 "run_id": "<agent ID>",
462 "branch": "<current branch>",
463 "addresses": ["src/billing.py::compute_total"],
464 "operation": "rename",
465 "created_at": "2026-03-18T12:00:00+00:00",
466 "detail": "rename to compute_invoice_total"
467 }
468 ```
469
470 ---
471
472 ### `muse forecast [OPTIONS]`
473
474 Predict merge conflicts from active reservations and intents — **before** writing any code.
475
476 ```
477 muse forecast
478 muse forecast --branch feature-x
479 muse forecast --json
480 ```
481
482 **Conflict types detected:**
483
484 | Type | Confidence | Condition |
485 |---|---|---|
486 | `address_overlap` | 1.0 | Two reservations on the same symbol address |
487 | `blast_radius_overlap` | 0.75 | Reservations on symbols that call each other (via call graph) |
488 | `operation_conflict` | 0.9 | Two reservations declare incompatible operations (e.g. both `rename`) |
489
490 **Flags:**
491 - `--branch BRANCH` — restrict to reservations on this branch
492 - `--json` — structured conflict list
493
494 ---
495
496 ### `muse plan-merge OURS THEIRS [OPTIONS]`
497
498 Dry-run semantic merge plan — classify all symbol conflicts without writing anything.
499
500 ```
501 muse plan-merge main feature-x
502 muse plan-merge HEAD~5 HEAD --json
503 ```
504
505 **Output:** Classifies each diverging symbol into one of:
506 - `no_conflict` — diverged in disjoint symbols
507 - `symbol_edit_overlap` — both sides modified the same symbol
508 - `rename_edit` — one side renamed, the other modified
509 - `delete_use` — one side deleted a symbol still used by the other
510
511 **Flags:**
512 - `--json` — structured output with full classification details
513
514 ---
515
516 ### `muse shard --agents N [OPTIONS]`
517
518 Partition the codebase into N low-coupling work zones for parallel agent assignment.
519
520 ```
521 muse shard --agents 4
522 muse shard --agents 8 --language Python
523 muse shard --agents 4 --json
524 ```
525
526 **Algorithm:** Builds the import graph, finds connected components, greedily merges small components into N balanced shards (by symbol count). Reports cross-shard edges as a coupling score (lower is better).
527
528 **Flags:**
529 - `--agents N` *(required)* — number of shards
530 - `--language LANG` — restrict to files of this language
531 - `--json` — shard assignments as JSON
532
533 ---
534
535 ### `muse reconcile [OPTIONS]`
536
537 Recommend merge ordering and integration strategy from the current coordination state.
538
539 ```
540 muse reconcile
541 muse reconcile --json
542 ```
543
544 **Output:** For each active branch with reservations, recommends:
545 - **Merge order** — branches with fewer predicted conflicts should merge first
546 - **Integration strategy** — `fast-forward`, `rebase`, or `manual` (when conflicts are predicted)
547 - **Conflict hotspots** — addresses that appear in the most reservations
548
549 ---
550
551 ## 7. Phase 6 — Merge Engine V2 & Architectural Enforcement
552
553 ### `ConflictRecord` — Structured Conflict Taxonomy
554
555 `MergeResult` now carries `conflict_records: list[ConflictRecord]` alongside the existing `conflicts: list[str]`. Each `ConflictRecord` provides structured metadata for programmatic conflict handling:
556
557 ```python
558 @dataclass
559 class ConflictRecord:
560 path: str
561 conflict_type: str = "file_level" # see taxonomy below
562 ours_summary: str = ""
563 theirs_summary: str = ""
564 addresses: list[str] = field(default_factory=list)
565 ```
566
567 **`conflict_type` taxonomy:**
568
569 | Value | Meaning |
570 |---|---|
571 | `symbol_edit_overlap` | Both branches modified the same symbol |
572 | `rename_edit` | One branch renamed, the other modified |
573 | `move_edit` | One branch moved, the other modified |
574 | `delete_use` | One branch deleted a symbol still used by the other |
575 | `dependency_conflict` | Conflicting changes to interdependent symbols |
576 | `file_level` | Legacy — no symbol-level information available |
577
578 ---
579
580 ### `muse breakage`
581
582 Detect symbol-level structural breakage in the current working tree vs HEAD.
583
584 ```
585 muse breakage
586 muse breakage --language Python
587 muse breakage --json
588 ```
589
590 **Checks performed:**
591
592 1. **`stale_import`** — a `from X import Y` where `Y` no longer exists in the committed version of `X` (detected via symbol graph, not execution).
593 2. **`missing_interface_method`** — a class body is missing a method that exists in the HEAD snapshot's version of that class.
594
595 **What it does NOT do:** Execute code, install packages, run mypy or a type checker, or access the network. Pure structural analysis.
596
597 **JSON output:**
598 ```json
599 {
600 "breakage_count": 2,
601 "issues": [
602 {
603 "issue_type": "stale_import",
604 "file": "src/billing.py",
605 "description": "imports compute_total from src/utils.py but compute_total was removed"
606 }
607 ]
608 }
609 ```
610
611 ---
612
613 ### `muse invariants`
614
615 Enforce architectural rules declared in `.muse/invariants.toml`.
616
617 ```
618 muse invariants
619 muse invariants --commit HEAD~5
620 muse invariants --json
621 ```
622
623 **Rule types:**
624
625 #### `no_cycles`
626 ```toml
627 [[rules]]
628 type = "no_cycles"
629 name = "no import cycles"
630 ```
631 The import graph must be a DAG. Reports every cycle as a violation.
632
633 #### `forbidden_dependency`
634 ```toml
635 [[rules]]
636 type = "forbidden_dependency"
637 name = "core must not import cli"
638 source_pattern = "muse/core/"
639 forbidden_pattern = "muse/cli/"
640 ```
641 Files matching `source_pattern` must not import from files matching `forbidden_pattern`.
642
643 #### `layer_boundary`
644 ```toml
645 [[rules]]
646 type = "layer_boundary"
647 name = "plugins must not import from cli"
648 lower = "muse/plugins/"
649 upper = "muse/cli/"
650 ```
651 Files in `lower` must not import from files in `upper` (enforces layered architecture).
652
653 #### `required_test`
654 ```toml
655 [[rules]]
656 type = "required_test"
657 name = "all billing functions must have tests"
658 source_pattern = "src/billing.py"
659 test_pattern = "tests/test_billing.py"
660 ```
661 Every public function in `source_pattern` must have a corresponding test function in `test_pattern` (matched by bare name).
662
663 **Bootstrapping:** If `.muse/invariants.toml` does not exist, `muse invariants` creates it with a commented template and exits with a guided onboarding message.
664
665 ---
666
667 ## 8. Phase 7 — Semantic Versioning
668
669 Muse automatically assigns semantic version bumps at commit time based on the `StructuredDelta`.
670
671 ### `SemVerBump`
672
673 ```python
674 SemVerBump = Literal["major", "minor", "patch", "none"]
675 ```
676
677 ### Inference rules (`infer_sem_ver_bump`)
678
679 | Change type | Bump | Breaking? |
680 |---|---|---|
681 | Delete a public symbol | `major` | yes — address added to `breaking_changes` |
682 | Rename a public symbol | `major` | yes — old address added to `breaking_changes` |
683 | `signature_only` change | `major` | yes — callers may break |
684 | Insert a new public symbol | `minor` | no |
685 | `impl_only` change (body only) | `patch` | no |
686 | `metadata_only` change | `none` | no |
687 | Formatting-only change | `none` | no |
688 | Non-public symbol changes | `patch` or `none` | no |
689
690 **Public** = name does not start with `_` and kind is `function`, `class`, `method`, or `async_function`.
691
692 ### Storage
693
694 Both `StructuredDelta` and `CommitRecord` carry:
695 - `sem_ver_bump: SemVerBump` (default `"none"`)
696 - `breaking_changes: list[str]` (default `[]`)
697
698 These fields are backward-compatible — pre-v2 commits read as `"none"` / `[]`.
699
700 ### `muse log` display
701
702 When a commit's `sem_ver_bump` is non-`none`, long-form `muse log` output appends:
703 ```
704 SemVer: MAJOR
705 Breaking: src/billing.py::compute_total, src/billing.py::Invoice (+2 more)
706 ```
707
708 ---
709
710 ## 9. Call-Graph Tier Commands
711
712 ### `muse impact ADDRESS [OPTIONS]`
713
714 Transitive blast-radius analysis — what else breaks if this function changes?
715
716 ```
717 muse impact src/billing.py::compute_total
718 muse impact src/billing.py::compute_total --commit HEAD~5
719 muse impact src/billing.py::compute_total --json
720 ```
721
722 **Algorithm:** BFS over the reverse call graph (Python only via `ast`). Traverses until the transitive closure is exhausted, annotating each affected symbol with its depth.
723
724 **Risk levels:** 🟢 (0–2 callers), 🟡 (3–9 callers), 🔴 (10+ callers).
725
726 ---
727
728 ### `muse dead [OPTIONS]`
729
730 Dead code detection — symbols with no callers and no importers.
731
732 ```
733 muse dead
734 muse dead --kind function
735 muse dead --exclude-tests
736 muse dead --json
737 ```
738
739 **Detection logic:** A symbol is a dead-code candidate when:
740 1. Its bare name appears in no `ast.Call` node in the snapshot **and**
741 2. Its module is not imported anywhere in the snapshot.
742
743 **Distinction:** `definite_dead` (module never imported) vs `soft_dead` (module imported but function never called directly).
744
745 ---
746
747 ### `muse coverage CLASS_ADDRESS [OPTIONS]`
748
749 Class interface call-coverage — which methods of a class are actually called?
750
751 ```
752 muse coverage src/billing.py::Invoice
753 muse coverage src/billing.py::Invoice --show-callers
754 muse coverage src/billing.py::Invoice --json
755 ```
756
757 **Output:** Lists every method of the class, marks which ones appear in `ast.Call` nodes anywhere in the snapshot, and prints a coverage percentage. No test suite required.
758
759 ---
760
761 ### `muse deps ADDRESS_OR_FILE [OPTIONS]`
762
763 Import graph + call-graph analysis.
764
765 ```
766 muse deps src/billing.py
767 muse deps src/billing.py --reverse
768 muse deps src/billing.py::compute_total
769 muse deps src/billing.py::compute_total --reverse
770 muse deps src/billing.py --commit v1.0 --json
771 ```
772
773 **File mode:** Lists all `import`-kind symbols from the file (what does it import?). With `--reverse`: which other files import this one.
774
775 **Symbol mode** (`address` contains `::`): Python-only call extraction — which functions does this function call? With `--reverse`: which functions call this one.
776
777 ---
778
779 ### `muse find-symbol [OPTIONS]`
780
781 Cross-commit, cross-branch symbol search by hash, name, or kind.
782
783 ```
784 muse find-symbol --hash a3f2c9
785 muse find-symbol --name compute_total
786 muse find-symbol --name compute_* --kind function
787 muse find-symbol --hash a3f2c9 --all-branches --first
788 muse find-symbol --name validate --json
789 ```
790
791 **Flags:**
792 - `--hash HEX` — match `content_id` prefix (exact body match across history)
793 - `--name NAME` — exact name or prefix glob with `*`
794 - `--kind KIND` — restrict to symbol kind
795 - `--all-branches` — also scan all branch tips in `.muse/refs/heads/`
796 - `--first` — deduplicate on `content_id`, keeping only the first appearance
797 - `--json` — structured output
798
799 ---
800
801 ### `muse patch ADDRESS SOURCE [OPTIONS]`
802
803 Surgical semantic patch — replace exactly one named symbol in the working tree.
804
805 ```
806 muse patch src/billing.py::compute_total new_impl.py
807 echo "def compute_total(x): return x * 2" | muse patch src/billing.py::compute_total -
808 muse patch src/billing.py::compute_total new_impl.py --dry-run
809 ```
810
811 **Syntax validation:** Before writing, validates the replacement source with:
812 - `ast.parse` for Python
813 - `tree-sitter` CST error-node check for all 11 supported languages
814
815 Rejects the patch and exits non-zero if the source has syntax errors.
816
817 **Flags:**
818 - `--dry-run` — print the unified diff without writing
819 - `--json` — structured output with patch result
820
821 ---
822
823 ## 10. Architecture Internals
824
825 ### Module Map
826
827 ```
828 muse/
829 plugins/code/
830 plugin.py MusicPlugin → CodePlugin (MuseDomainPlugin + StructuredMergePlugin)
831 ast_parser.py Python AST → SymbolRecord; validate_syntax() for all 11 languages
832 symbol_diff.py diff_symbol_trees() — O(n) diffing, rename/move annotation
833 _query.py symbols_for_snapshot(), walk_commits(), language_of()
834 _predicate.py Predicate DSL parser — tokenise → recursive descent → Predicate callable
835 _callgraph.py ForwardGraph, ReverseGraph, build_*, transitive_callers BFS
836 _refactor_classify.py classify_exact(), classify_composite(), RefactorClassification
837 core/
838 coordination.py Reservation, Intent, create/load helpers, .muse/coordination/
839 indices.py SymbolHistoryIndex, HashOccurrenceIndex, save/load/rebuild
840 ```
841
842 ### Language Support
843
844 | Language | Extension(s) | Parser | Symbol types |
845 |---|---|---|---|
846 | Python | `.py` | `ast` (stdlib) | function, async_function, class, method, variable, import |
847 | JavaScript | `.js` `.jsx` `.mjs` `.cjs` | tree-sitter | function, class, method |
848 | TypeScript | `.ts` `.tsx` | tree-sitter | function, class, method, interface, type_alias, enum |
849 | Go | `.go` | tree-sitter | function (method qualified as `Type.Method`) |
850 | Rust | `.rs` | tree-sitter | function (impl method qualified as `Type.method`) |
851 | Java | `.java` | tree-sitter | class, interface, method, constructor, enum |
852 | C | `.c` `.h` | tree-sitter | function_definition |
853 | C++ | `.cpp` `.cc` `.cxx` `.hpp` | tree-sitter | function, class, struct |
854 | C# | `.cs` | tree-sitter | class, interface, struct, method, constructor, enum |
855 | Ruby | `.rb` | tree-sitter | class, module, method, singleton_method |
856 | Kotlin | `.kt` `.kts` | tree-sitter | function, class, method |
857
858 ### Layer Rules
859
860 - `muse/core/*` is domain-agnostic — never imports from `muse/plugins/*`
861 - `muse/cli/commands/*` are thin — delegate all logic to `muse/core/*` or plugin helpers
862 - `muse/plugins/code/*` is the only layer that imports domain-specific AST logic
863 - `muse/core/coordination.py` and `muse/core/indices.py` are domain-agnostic helpers
864
865 ---
866
867 ## 11. Type Reference
868
869 ### `SymbolRecord` (TypedDict)
870
871 ```python
872 class SymbolRecord(TypedDict):
873 kind: str # function | class | method | variable | import | …
874 name: str # bare name
875 qualified_name: str # dotted path (e.g. MyClass.save)
876 lineno: int
877 end_lineno: int
878 content_id: str # SHA-256 of full normalized AST
879 body_hash: str # SHA-256 of body only
880 signature_id: str # SHA-256 of signature only
881 metadata_id: str # SHA-256 of decorators + async + bases (v2, "" for pre-v2)
882 canonical_key: str # {file}#{scope}#{kind}#{name}#{lineno} (v2, "" for pre-v2)
883 ```
884
885 ### `StructuredDelta`
886
887 ```python
888 class StructuredDelta(TypedDict):
889 domain: str
890 ops: list[DomainOp]
891 summary: str
892 sem_ver_bump: SemVerBump # v2 field (default "none")
893 breaking_changes: list[str] # v2 field (default [])
894 ```
895
896 ### `DomainOp` union
897
898 ```python
899 DomainOp = InsertOp | DeleteOp | ReplaceOp | MoveOp | PatchOp
900 ```
901
902 Each op is a `TypedDict` discriminated by a `Literal` `"op"` field.
903
904 ### `ConflictRecord` (dataclass)
905
906 ```python
907 @dataclass
908 class ConflictRecord:
909 path: str
910 conflict_type: str = "file_level"
911 ours_summary: str = ""
912 theirs_summary: str = ""
913 addresses: list[str] = field(default_factory=list)
914 ```
915
916 ### `Reservation`
917
918 ```python
919 class Reservation:
920 reservation_id: str
921 run_id: str
922 branch: str
923 addresses: list[str]
924 created_at: datetime
925 expires_at: datetime
926 operation: str | None
927 def is_active(self) -> bool: ...
928 def to_dict(self) -> dict[str, str | int | list[str] | None]: ...
929 @classmethod
930 def from_dict(cls, d) -> Reservation: ...
931 ```
932
933 ### `Intent`
934
935 ```python
936 class Intent:
937 intent_id: str
938 reservation_id: str
939 run_id: str
940 branch: str
941 addresses: list[str]
942 operation: str
943 created_at: datetime
944 detail: str
945 def to_dict(self) -> dict[str, str | int | list[str]]: ...
946 @classmethod
947 def from_dict(cls, d) -> Intent: ...
948 ```
949
950 ### `SemVerBump`
951
952 ```python
953 SemVerBump = Literal["major", "minor", "patch", "none"]
954 ```
955
956 ### `Predicate`
957
958 ```python
959 Predicate = Callable[[str, SymbolRecord], bool]
960 # first arg: file_path
961 # second arg: SymbolRecord
962 # returns: True if the symbol matches the predicate
963 ```
964
965 ### `ExactClassification`
966
967 ```python
968 ExactClassification = Literal[
969 "rename", "move", "rename+move",
970 "signature_only", "impl_only", "metadata_only",
971 "full_rewrite", "unchanged",
972 ]
973 ```
974
975 ### `InferredRefactor`
976
977 ```python
978 InferredRefactor = Literal["extract", "inline", "split", "merge", "none"]
979 ```
980
981 ---
982
983 ## Further Reading
984
985 - [Plugin Authoring Guide](plugin-authoring-guide.md) — implementing `MuseDomainPlugin`
986 - [Type Contracts](type-contracts.md) — strict typing rules and enforcement
987 - [CRDT Reference](crdt-reference.md) — CRDT and OT merge primitives
988 - [Tour de Force — Code](../demo/tour-de-force-code.md) — full narrative walkthrough of all code commands
989 - [Tour de Force — Music](../demo/tour-de-force-music.md) — music domain reference demo