gabriel / muse public
_shapes.py python
531 lines 18.9 KB
Raw
sha256:649be9ce77a127cd847c4f798d60104dab7fe830cbc928762fafe3deadf38839 chore: point muse-git-backup.sh's MUSE_COPY at the fresh 'm… Sonnet 5 patch 13 days ago
1 """JSON TypedDicts and serialisation helpers for the harmony CLI."""
2
3 from __future__ import annotations
4
5 from typing import Any, TypedDict
6
7 from muse.core.envelope import EnvelopeJson, JsonValue
8 from muse.core.harmony import AuditEvent, ConflictPattern, EscalationRecord, Policy, Resolution
9 from muse.core.validation import sanitize_display
10
11
12 class _HarmonyRecordJson(EnvelopeJson):
13 """JSON output for ``muse harmony record --json``.
14
15 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
16
17 Fields
18 ------
19 pattern_id 64-char hex SHA-256 pattern ID derived from the path, blob
20 fingerprint, and semantic fingerprint.
21 already_existed True when the pattern was already recorded — the existing
22 entry is returned unchanged (idempotent).
23 """
24
25 pattern_id: str
26 already_existed: bool
27
28 class _HarmonyListEntryJson(TypedDict):
29 """One conflict pattern entry in ``muse harmony list --json`` output.
30
31 Nested inside the ``patterns`` list of :class:`_HarmonyListJson`.
32
33 Fields
34 ------
35 pattern_id 64-char hex pattern ID.
36 path Workspace-relative POSIX path of the conflicting file.
37 domain Domain name the pattern belongs to (e.g. ``"midi"``).
38 conflict_type Conflict category (content, structural, metadata, …).
39 resolution_count Number of resolutions saved for this pattern.
40 recorded_at ISO-8601 UTC timestamp when the pattern was first recorded.
41 recorded_by Agent ID or ``"human"`` who recorded the pattern.
42 """
43
44 pattern_id: str
45 path: str
46 domain: str
47 conflict_type: str
48 resolution_count: int
49 recorded_at: str
50 recorded_by: str
51
52 class _HarmonyListJson(EnvelopeJson):
53 """JSON output for ``muse harmony list --json``.
54
55 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
56
57 Fields
58 ------
59 total Total number of patterns returned (after any domain/type filters).
60 patterns Ordered list of pattern entries; see :class:`_HarmonyListEntryJson`.
61 """
62
63 total: int
64 patterns: list[_HarmonyListEntryJson]
65
66 type _PatternDescription = dict[str, JsonValue]
67
68 class _HarmonyPatternDetailJson(TypedDict):
69 """Full conflict pattern detail nested inside :class:`_HarmonyShowJson`.
70
71 Fields
72 ------
73 pattern_id 64-char hex pattern ID.
74 path Workspace-relative POSIX path of the conflicting file.
75 domain Domain name (e.g. ``"midi"``, ``"code"``).
76 conflict_type Conflict category string.
77 blob_fingerprint SHA-256 of ``sorted(ours_id, theirs_id)`` — exact-replay key.
78 semantic_fingerprint Domain-plugin fingerprint — cross-content replay key.
79 Equals ``blob_fingerprint`` when no plugin is active.
80 ours_id 64-char hex object ID for the ours version.
81 theirs_id 64-char hex object ID for the theirs version.
82 description Domain-specific metadata dict (arbitrary JSON object).
83 recorded_at ISO-8601 UTC timestamp when the pattern was first recorded.
84 recorded_by Agent ID or ``"human"`` who recorded the pattern.
85 """
86
87 pattern_id: str
88 path: str
89 domain: str
90 conflict_type: str
91 blob_fingerprint: str
92 semantic_fingerprint: str
93 ours_id: str
94 theirs_id: str
95 description: _PatternDescription
96 recorded_at: str
97 recorded_by: str
98
99 class _HarmonyResolutionDetailJson(TypedDict):
100 """One resolution record — nested in show, best, and similar output.
101
102 Nested inside :class:`_HarmonyShowJson` (resolutions list) and
103 :class:`_HarmonyBestJson` (resolution field).
104
105 Fields
106 ------
107 resolution_id 64-char hex resolution ID.
108 strategy Resolution strategy: ``"manual"``, ``"exact-replay"``,
109 ``"semantic-proposal"``, or ``"policy"``.
110 confidence Reliability score 0.0–1.0 assigned when the resolution was saved.
111 human_verified True when a human confirmed this resolution is correct.
112 Human-verified resolutions always outrank unverified ones.
113 applied_count Number of times this resolution has been auto-applied.
114 resolved_by Provenance dict — ``{"type": "agent"|"human",
115 "agent_id": str|null, "model_id": str|null}``.
116 resolved_at ISO-8601 UTC timestamp when the resolution was saved.
117 rationale Human-readable explanation for why this resolution was chosen.
118 """
119
120 resolution_id: str
121 strategy: str
122 confidence: float
123 human_verified: bool
124 applied_count: int
125 resolved_by: dict[str, str | None]
126 resolved_at: str
127 rationale: str
128
129 class _HarmonyShowJson(EnvelopeJson):
130 """JSON output for ``muse harmony show <pattern_id> --json``.
131
132 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
133
134 Fields
135 ------
136 pattern Full pattern metadata; see :class:`_HarmonyPatternDetailJson`.
137 resolutions All resolutions for this pattern, sorted by quality
138 (human_verified → confidence → applied_count) descending.
139 """
140
141 pattern: _HarmonyPatternDetailJson
142 resolutions: list[_HarmonyResolutionDetailJson]
143
144 class _HarmonyResolveJson(EnvelopeJson):
145 """JSON output for ``muse harmony resolve --json``.
146
147 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
148
149 Fields
150 ------
151 resolution_id 64-char hex ID of the saved (or existing) resolution.
152 pattern_id 64-char hex ID of the parent conflict pattern.
153 already_existed True when this (outcome_blob, strategy, actor) triple was
154 already saved — idempotent; the existing ID is returned.
155 """
156
157 resolution_id: str
158 pattern_id: str
159 already_existed: bool
160
161 class _HarmonyBestJson(EnvelopeJson):
162 """JSON output for ``muse harmony best <pattern_id> --json``.
163
164 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
165
166 Fields
167 ------
168 pattern_id 64-char hex ID of the queried pattern.
169 resolution The highest-quality resolution (human_verified → confidence →
170 applied_count), or ``null`` when no resolutions exist yet.
171 """
172
173 pattern_id: str
174 resolution: _HarmonyResolutionDetailJson | None
175
176 class _HarmonyForgetJson(EnvelopeJson):
177 """JSON output for ``muse harmony forget <pattern_id> --json``.
178
179 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
180
181 Fields
182 ------
183 pattern_id 64-char hex ID of the pattern that was (or was not) removed.
184 removed True when the pattern and all its resolutions were deleted.
185 False when the pattern did not exist.
186 """
187
188 pattern_id: str
189 removed: bool
190
191 class _HarmonyScalarJson(EnvelopeJson):
192 """JSON output for ``muse harmony clear --json``.
193
194 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
195
196 Fields
197 ------
198 removed Total number of conflict patterns deleted from the store.
199 """
200
201 removed: int
202
203 class _HarmonyGcJson(EnvelopeJson):
204 """JSON output for ``muse harmony gc --json``.
205
206 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
207
208 Fields
209 ------
210 removed Number of stale unresolved patterns deleted.
211 age_days Age threshold used — patterns older than this with no resolution
212 were eligible for removal.
213 """
214
215 removed: int
216 age_days: int
217
218 class _HarmonyPolicyAddJson(EnvelopeJson):
219 """JSON output for ``muse harmony policy-add --json``.
220
221 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
222
223 Fields
224 ------
225 policy_id URL-safe identifier of the policy that was saved or replaced.
226 action The resolution action the policy fires: ``"prefer-ours"``,
227 ``"prefer-theirs"``, ``"escalate"``, ``"require-human"``,
228 or ``"delegate"``.
229 scope Policy scope: ``"workspace"``, ``"repo"``, ``"domain"``,
230 or ``"file"``.
231 """
232
233 policy_id: str
234 action: str
235 scope: str
236
237 class _HarmonyPolicyEntryJson(TypedDict):
238 """One policy record nested inside :class:`_HarmonyPolicyListJson`.
239
240 Fields
241 ------
242 policy_id URL-safe policy identifier.
243 description Human-readable explanation of what this policy does.
244 scope Scope level: ``"workspace"``, ``"repo"``, ``"domain"``,
245 or ``"file"``.
246 action Resolution action fired by this policy.
247 confidence Confidence score 0.0–1.0 assigned to policy-driven resolutions.
248 conflict_type Conflict type filter, or ``null`` (fires for all types).
249 domain Domain filter, or ``null`` (fires for all domains).
250 path_pattern fnmatch glob filter on file paths, or ``null``.
251 created_at ISO-8601 UTC timestamp when the policy was created.
252 created_by Creator attribution: agent ID or ``"human"``.
253 """
254
255 policy_id: str
256 description: str
257 scope: str
258 action: str
259 confidence: float
260 conflict_type: str | None
261 domain: str | None
262 path_pattern: str | None
263 created_at: str
264 created_by: str
265
266 class _HarmonyPolicyListJson(EnvelopeJson):
267 """JSON output for ``muse harmony policy-list --json``.
268
269 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
270
271 Fields
272 ------
273 total Total number of policies returned.
274 policies Scope-sorted policy list (workspace → repo → domain → file,
275 then by created_at ascending within each scope).
276 """
277
278 total: int
279 policies: list[_HarmonyPolicyEntryJson]
280
281 class _HarmonyPolicyRemoveJson(EnvelopeJson):
282 """JSON output for ``muse harmony policy-remove <policy_id> --json``.
283
284 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
285
286 Fields
287 ------
288 policy_id URL-safe identifier of the policy that was (or was not) removed.
289 removed True when the policy was deleted; False when it did not exist.
290 """
291
292 policy_id: str
293 removed: bool
294
295 class _HarmonyAuditJson(EnvelopeJson):
296 """JSON output for ``muse harmony audit --json``.
297
298 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
299
300 Fields
301 ------
302 total Total number of entries returned (capped by ``--limit``).
303 entries Audit log entries, newest first; each is a full AuditEvent dict
304 with event_type, occurred_at, actor, pattern_id, and metadata.
305 """
306
307 total: int
308 entries: list[AuditEvent]
309
310 class _HarmonyEscalateJson(EnvelopeJson):
311 """JSON output for ``muse harmony escalate <pattern_id> --json``.
312
313 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
314
315 Fields
316 ------
317 escalation_id 64-char hex ID of the escalation record (deterministic
318 from pattern_id + reason).
319 pattern_id 64-char hex ID of the conflict pattern being escalated.
320 already_existed True when an open escalation for this (pattern_id, reason)
321 pair already existed — idempotent.
322 """
323
324 escalation_id: str
325 pattern_id: str
326 already_existed: bool
327
328 class _HarmonyEscalationEntryJson(TypedDict):
329 """One escalation record nested inside :class:`_HarmonyEscalationsJson`.
330
331 Fields
332 ------
333 escalation_id 64-char hex escalation ID.
334 pattern_id 64-char hex pattern ID that was escalated.
335 reason Human-readable reason for escalation.
336 status ``"open"`` or ``"resolved"``.
337 escalated_at ISO-8601 UTC timestamp when the escalation was recorded.
338 escalated_by Provenance dict for the actor who created the escalation.
339 resolved_at ISO-8601 UTC timestamp when the escalation was closed,
340 or ``null`` if still open.
341 resolved_by Provenance dict for the actor who resolved it, or ``null``.
342 resolution_id 64-char hex resolution ID that closed this escalation,
343 or ``null`` if still open.
344 """
345
346 escalation_id: str
347 pattern_id: str
348 reason: str
349 status: str
350 escalated_at: str
351 escalated_by: dict[str, str | None]
352 resolved_at: str | None
353 resolved_by: dict[str, str | None] | None
354 resolution_id: str | None
355
356 class _HarmonyEscalationsJson(EnvelopeJson):
357 """JSON output for ``muse harmony escalations --json``.
358
359 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
360
361 Fields
362 ------
363 total Total number of escalation records returned.
364 escalations List of escalation entries; see :class:`_HarmonyEscalationEntryJson`.
365 """
366
367 total: int
368 escalations: list[_HarmonyEscalationEntryJson]
369
370 class _HarmonyResolveEscalationJson(EnvelopeJson):
371 """JSON output for ``muse harmony resolve-escalation <esc_id> --json``.
372
373 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
374
375 Fields
376 ------
377 escalation_id 64-char hex ID of the escalation that was closed.
378 resolved True when the escalation was successfully transitioned to
379 RESOLVED status; False when the escalation was not found.
380 """
381
382 escalation_id: str
383 resolved: bool
384
385 class _HarmonyProposalJson(TypedDict):
386 """A single resolution proposal from the engine or similar search.
387
388 Nested inside :class:`_HarmonyEngineJson` (proposal field) and
389 :class:`_HarmonySimilarJson` (proposals list).
390
391 Fields
392 ------
393 pattern_id 64-char hex ID of the base pattern being resolved.
394 strategy How this proposal was derived: ``"policy"``,
395 ``"exact-replay"``, or ``"semantic-proposal"``.
396 proposed_action The concrete action to take (e.g. ``"prefer-ours"``).
397 confidence Confidence score 0.0–1.0 for this proposal.
398 rationale Explanation of why this resolution was proposed.
399 policy_id If strategy is ``"policy"``, the ID of the matching
400 policy; ``null`` otherwise.
401 similar_pattern_id If strategy is ``"semantic-proposal"``, the ID of the
402 similar pattern; ``null`` otherwise.
403 similarity Similarity score 0.0–1.0 to the similar pattern,
404 or ``null`` when not a semantic proposal.
405 requires_confirmation True when the engine recommends human confirmation
406 before applying this resolution automatically.
407 """
408
409 pattern_id: str
410 strategy: str
411 proposed_action: str
412 confidence: float
413 rationale: str
414 policy_id: str | None
415 similar_pattern_id: str | None
416 similarity: float | None
417 requires_confirmation: bool
418
419 class _HarmonyEngineJson(EnvelopeJson):
420 """JSON output for ``muse harmony engine <pattern_id> --json``.
421
422 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
423
424 Fields
425 ------
426 status Engine outcome: ``"applied"`` (auto-applied a saved
427 resolution), ``"proposed"`` (returned a proposal for
428 human confirmation), or ``"escalated"`` (no match found).
429 pattern_id 64-char hex ID of the pattern evaluated.
430 proposal The resolution proposal, or ``null`` when the engine
431 applied or escalated without proposing.
432 applied_resolution_id 64-char hex ID of the auto-applied resolution,
433 or ``null`` when status is not ``"applied"``.
434 escalation_reason Explanation of why escalation was chosen,
435 or ``null`` when status is not ``"escalated"``.
436 """
437
438 status: str
439 pattern_id: str
440 proposal: _HarmonyProposalJson | None
441 applied_resolution_id: str | None
442 escalation_reason: str | None
443
444 class _HarmonySimilarJson(EnvelopeJson):
445 """JSON output for ``muse harmony similar <pattern_id> --json``.
446
447 Inherits the 6 standard envelope fields from :class:`~muse.core.envelope.EnvelopeJson`.
448
449 Fields
450 ------
451 pattern_id 64-char hex ID of the base pattern searched against.
452 total Total number of similar-pattern proposals returned.
453 proposals List of resolution proposals from semantically similar patterns;
454 see :class:`_HarmonyProposalJson`.
455 """
456
457 pattern_id: str
458 total: int
459 proposals: list[_HarmonyProposalJson]
460
461 # ---------------------------------------------------------------------------
462 # Serialisation helpers
463 # ---------------------------------------------------------------------------
464
465 def _pattern_to_list_entry(
466 p: ConflictPattern,
467 resolution_count: int,
468 ) -> _HarmonyListEntryJson:
469 return _HarmonyListEntryJson(
470 pattern_id=p.pattern_id,
471 path=sanitize_display(p.path),
472 domain=sanitize_display(p.domain),
473 conflict_type=p.conflict_type,
474 resolution_count=resolution_count,
475 recorded_at=p.recorded_at.isoformat(),
476 recorded_by=sanitize_display(p.recorded_by),
477 )
478
479 def _pattern_to_detail(p: ConflictPattern) -> _HarmonyPatternDetailJson:
480 return _HarmonyPatternDetailJson(
481 pattern_id=p.pattern_id,
482 path=sanitize_display(p.path),
483 domain=sanitize_display(p.domain),
484 conflict_type=p.conflict_type,
485 blob_fingerprint=p.blob_fingerprint,
486 semantic_fingerprint=p.semantic_fingerprint,
487 ours_id=p.ours_id,
488 theirs_id=p.theirs_id,
489 description=p.description,
490 recorded_at=p.recorded_at.isoformat(),
491 recorded_by=sanitize_display(p.recorded_by),
492 )
493
494 def _resolution_to_detail(r: Resolution) -> _HarmonyResolutionDetailJson:
495 return _HarmonyResolutionDetailJson(
496 resolution_id=r.resolution_id,
497 strategy=r.strategy,
498 confidence=r.confidence,
499 human_verified=r.human_verified,
500 applied_count=r.applied_count,
501 resolved_by=r.resolved_by.to_dict(),
502 resolved_at=r.resolved_at.isoformat(),
503 rationale=r.rationale,
504 )
505
506 def _policy_to_entry(p: Policy) -> _HarmonyPolicyEntryJson:
507 return _HarmonyPolicyEntryJson(
508 policy_id=p.policy_id,
509 description=p.description,
510 scope=p.scope,
511 action=p.action,
512 confidence=p.confidence,
513 conflict_type=p.when.conflict_type,
514 domain=p.when.domain,
515 path_pattern=p.when.path_pattern,
516 created_at=p.created_at.isoformat(),
517 created_by=p.created_by,
518 )
519
520 def _escalation_to_entry(rec: EscalationRecord) -> _HarmonyEscalationEntryJson:
521 return _HarmonyEscalationEntryJson(
522 escalation_id=rec.escalation_id,
523 pattern_id=rec.pattern_id,
524 reason=sanitize_display(rec.reason),
525 status=rec.status,
526 escalated_at=rec.escalated_at.isoformat(),
527 escalated_by=rec.escalated_by.to_dict(),
528 resolved_at=rec.resolved_at.isoformat() if rec.resolved_at is not None else None,
529 resolved_by=rec.resolved_by.to_dict() if rec.resolved_by is not None else None,
530 resolution_id=rec.resolution_id,
531 )
File History 1 commit
sha256:649be9ce77a127cd847c4f798d60104dab7fe830cbc928762fafe3deadf38839 chore: point muse-git-backup.sh's MUSE_COPY at the fresh 'm… Sonnet 5 patch 13 days ago