gabriel / musehub public
musehub_domain_models.py python
123 lines 6.1 KB
Raw
sha256:969ddc5e88776e70af33c016b8777bb721356508ae5f304b3fb46c451494ece7 test(mwp3): Phase 4 — fix adjacent suite regressions, lock … Sonnet 4.6 22 days ago
1 """SQLAlchemy ORM models for the Muse domain plugin registry.
2
3 A Muse domain plugin defines a unique state space (MIDI, code, genomics, climate
4 simulation, 3D design, etc.) and the six interfaces Muse uses to version it.
5 MuseHub hosts a registry of these plugins so that any agent or human can
6 discover, install, and create repositories for any registered domain.
7
8 Namespace scheme: ``@{author_slug}/{slug}`` — mirrors npm scoped packages.
9 Examples: ``@gabriel/midi``, ``@gabriel/code``, ``@deepmind/climate``
10
11 Every domain also carries an immutable content-addressed ``manifest_hash``
12 (SHA-256 of the capabilities JSON) that agents can use to pin exact versions.
13
14 Tables:
15 - musehub_domains: Domain plugin registry
16 - musehub_domain_installs: Which users have installed which domains
17 """
18
19 from datetime import datetime, timezone
20
21 import sqlalchemy as sa
22 from sqlalchemy import Boolean, DateTime, Integer, String, Text, UniqueConstraint
23 from sqlalchemy.orm import Mapped, mapped_column
24 from sqlalchemy.dialects.postgresql import JSONB
25
26 from musehub.db.database import Base
27 from musehub.types.json_types import JSONObject, JSONValue # JSONValue needed for ForwardRef resolution in Mapped[]
28
29 def _utc_now() -> datetime:
30 return datetime.now(tz=timezone.utc)
31
32 class MusehubDomain(Base):
33 """A registered Muse domain plugin in the MuseHub registry.
34
35 Domain plugins define how Muse versions a particular type of state.
36 Two canonical domains ship with MuseHub:
37 - ``@gabriel/midi`` — 21-dimensional MIDI state space
38 - ``@gabriel/code`` — symbol-graph code state space
39
40 Third-party developers register their own domains:
41 - ``@alice/genomics`` — CRISPR genome editing sequences
42 - ``@deepmind/climate`` — climate simulation parameter grids
43
44 ``author_slug`` + ``slug`` form the scoped identity ``@author_slug/slug``,
45 enforced as a unique composite. The ``manifest_hash`` is a SHA-256 of the
46 ``capabilities`` JSON blob — agents can use it to pin to a specific version
47 of the domain definition.
48
49 ``capabilities`` is a JSON object declaring:
50 - ``dimensions``: list of insight dimension specs (name, description, unit)
51 - ``viewer_type``: which primary viewer to use (piano_roll, symbol_graph, etc.)
52 - ``supported_commands``: list of domain-specific CLI commands
53 - ``kinds``: symbol kinds the domain recognises (e.g. ["function", "class", "module"])
54 - ``merge_semantics``: "ot" | "crdt" | "three_way"
55 """
56
57 __tablename__ = "musehub_domains"
58 __table_args__ = (
59 UniqueConstraint("author_slug", "slug", name="uq_musehub_domains_author_slug"),
60 )
61
62 # genesis-addressed: sha256(author_slug NUL slug NUL created_at_iso)
63 domain_id: Mapped[str] = mapped_column(String(128), primary_key=True)
64 # author_user_id may be None for system-seeded built-in domains; references identity_id
65 author_user_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
66 # URL-safe author handle, e.g. "gabriel"
67 author_slug: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
68 # Domain name slug, e.g. "midi" — unique per author
69 slug: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
70 # Human-readable display name, e.g. "MIDI"
71 display_name: Mapped[str] = mapped_column(String(255), nullable=False)
72 # Short description shown in the domain registry
73 description: Mapped[str] = mapped_column(Text, nullable=False, default="")
74 # Semver string, e.g. "1.0.0"
75 version: Mapped[str] = mapped_column(String(32), nullable=False, default="1.0.0", server_default="1.0.0")
76 # SHA-256 of the capabilities JSON — immutable fingerprint for pinning
77 manifest_hash: Mapped[str] = mapped_column(String(128), nullable=False, default="")
78 # JSON capabilities blob — see class docstring for schema
79 capabilities: Mapped[JSONObject] = mapped_column(JSONB, nullable=False, default=dict)
80 # Primary viewer type: "piano_roll" | "symbol_graph" | "sequence_viewer" | "generic"
81 viewer_type: Mapped[str] = mapped_column(String(64), nullable=False, default="generic", server_default="generic")
82 # Number of repos using this domain (denormalised counter, updated async)
83 install_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
84 # True for MuseHub-verified built-in domains (@gabriel/*)
85 is_verified: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sa.false())
86 # True for deprecated domains that still exist but are no longer recommended
87 is_deprecated: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, server_default=sa.false())
88 created_at: Mapped[datetime] = mapped_column(
89 DateTime(timezone=True), nullable=False, default=_utc_now
90 )
91 updated_at: Mapped[datetime] = mapped_column(
92 DateTime(timezone=True), nullable=False, default=_utc_now, onupdate=_utc_now
93 )
94
95 @property
96 def scoped_id(self) -> str:
97 """Return the npm-style scoped identifier, e.g. ``@gabriel/midi``."""
98 return f"@{self.author_slug}/{self.slug}"
99
100 class MusehubDomainInstall(Base):
101 """Records a user's installation/adoption of a domain plugin.
102
103 When a user creates a repository with a particular domain, a domain install
104 row is created linking that user to that domain. This enables:
105 - Per-domain install_count aggregation
106 - User's "installed domains" list on their profile
107 - Notifications when a domain is updated or deprecated
108
109 The unique constraint on (user_id, domain_id) means a user is counted once
110 per domain regardless of how many repos they create with it.
111 """
112
113 __tablename__ = "musehub_domain_installs"
114 __table_args__ = (
115 UniqueConstraint("user_id", "domain_id", name="uq_musehub_domain_installs"),
116 )
117
118 install_id: Mapped[str] = mapped_column(String(128), primary_key=True)
119 user_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
120 domain_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
121 created_at: Mapped[datetime] = mapped_column(
122 DateTime(timezone=True), nullable=False, default=_utc_now
123 )
File History 2 commits
sha256:969ddc5e88776e70af33c016b8777bb721356508ae5f304b3fb46c451494ece7 test(mwp3): Phase 4 — fix adjacent suite regressions, lock … Sonnet 4.6 22 days ago
sha256:1749b9cc5cd2583c56d3261c4c00a342c27435f3946d4bc3e70f76aa2795458a docs(mwp-3): TDD implementation plan for job-enqueue idempo… Opus 4.8 22 days ago