musehub_domain_models.py
python
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