feat(review): add multi-owner contracts and receipts
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
This commit is contained in:
parent
52aefe39e4
commit
598f6418e7
13 changed files with 1401 additions and 9 deletions
|
|
@ -42,6 +42,7 @@ from api.models.fabric_graph import FabricGraphImport, FabricGraphNode, FabricGr
|
|||
from api.models.legacy_meter import LegacyInterface, LegacyInterfaceUsageBucket
|
||||
from api.models.write_idempotency_key import WriteIdempotencyKey
|
||||
from api.models.work_record_identifier_alias import WorkRecordIdentifierAlias
|
||||
from api.models.review_contract import ReviewContract, ReviewReceipt
|
||||
from api.models.suggestion import (
|
||||
Suggestion,
|
||||
SuggestionNote,
|
||||
|
|
@ -83,5 +84,6 @@ __all__ = [
|
|||
"LegacyInterface", "LegacyInterfaceUsageBucket",
|
||||
"WriteIdempotencyKey",
|
||||
"WorkRecordIdentifierAlias",
|
||||
"ReviewContract", "ReviewReceipt",
|
||||
"Suggestion", "SuggestionNote", "SuggestionRelevanceBump", "SuggestionStage",
|
||||
]
|
||||
|
|
|
|||
128
api/models/review_contract.py
Normal file
128
api/models/review_contract.py
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from sqlalchemy import (
|
||||
Boolean,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Index,
|
||||
String,
|
||||
Text,
|
||||
UniqueConstraint,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import JSONB, UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from api.models.base import Base, TimestampMixin, new_uuid7
|
||||
|
||||
|
||||
class ReviewContract(Base, TimestampMixin):
|
||||
"""Replaceable projection of one authoritative review-contract revision."""
|
||||
|
||||
__tablename__ = "review_contracts"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), primary_key=True, default=new_uuid7
|
||||
)
|
||||
contract_key: Mapped[str] = mapped_column(String(160), nullable=False, index=True)
|
||||
schema_version: Mapped[str] = mapped_column(String(40), nullable=False)
|
||||
contract_digest: Mapped[str] = mapped_column(
|
||||
String(64), nullable=False, unique=True
|
||||
)
|
||||
source_repo: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
source_path: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
source_revision: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
document: Mapped[dict] = mapped_column(JSONB, nullable=False)
|
||||
active: Mapped[bool] = mapped_column(
|
||||
Boolean, nullable=False, default=True, index=True
|
||||
)
|
||||
required_for_decision: Mapped[bool] = mapped_column(
|
||||
Boolean, nullable=False, default=False
|
||||
)
|
||||
decision_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("decisions.id", ondelete="RESTRICT"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
workplan_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("workplans.id", ondelete="RESTRICT", onupdate="CASCADE"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
task_id: Mapped[uuid.UUID | None] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("tasks.id", ondelete="RESTRICT", onupdate="CASCADE"),
|
||||
nullable=True,
|
||||
index=True,
|
||||
)
|
||||
projected_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False
|
||||
)
|
||||
|
||||
receipts: Mapped[list["ReviewReceipt"]] = relationship(
|
||||
"ReviewReceipt", back_populates="contract", lazy="selectin"
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"contract_key",
|
||||
"source_repo",
|
||||
"source_path",
|
||||
"source_revision",
|
||||
name="uq_review_contract_source_revision",
|
||||
),
|
||||
Index("ix_review_contract_key_active", "contract_key", "active"),
|
||||
)
|
||||
|
||||
|
||||
class ReviewReceipt(Base, TimestampMixin):
|
||||
"""Immutable evidence submitted against an exact contract digest."""
|
||||
|
||||
__tablename__ = "review_receipts"
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True), primary_key=True, default=new_uuid7
|
||||
)
|
||||
contract_id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
ForeignKey("review_contracts.id", ondelete="RESTRICT"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
owner_id: Mapped[str] = mapped_column(String(160), nullable=False, index=True)
|
||||
actor: Mapped[str] = mapped_column(String(160), nullable=False)
|
||||
disposition: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
contract_digest: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
|
||||
receipt_digest: Mapped[str] = mapped_column(String(64), nullable=False, unique=True)
|
||||
artifact_hashes: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
|
||||
assertion_ids: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
|
||||
checks: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
|
||||
note: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
source_repo: Mapped[str] = mapped_column(String(100), nullable=False)
|
||||
source_path: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
source_revision: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
submitted_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), nullable=False, index=True
|
||||
)
|
||||
document: Mapped[dict] = mapped_column(JSONB, nullable=False)
|
||||
|
||||
contract: Mapped[ReviewContract] = relationship(
|
||||
"ReviewContract", back_populates="receipts"
|
||||
)
|
||||
|
||||
__table_args__ = (
|
||||
UniqueConstraint(
|
||||
"source_repo",
|
||||
"source_path",
|
||||
"source_revision",
|
||||
name="uq_review_receipt_source_revision",
|
||||
),
|
||||
Index(
|
||||
"ix_review_receipt_contract_owner_time",
|
||||
"contract_id",
|
||||
"owner_id",
|
||||
"submitted_at",
|
||||
),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue