Source code for sim_panel.products.records
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, Optional
from sim_panel.utils.hashing import sha256_json, sha256_text
[docs]
@dataclass
class ProductRecord:
"""
Canonical product/intervention artifact (JSONL row).
- product_id is internal/stable and should NOT be shown to panelists.
- display_name is panelist-facing (short).
- display_text is panelist-facing (longer), optional and can be LLM-enriched.
- attributes are structured features used for policies/outcomes and for rendering.
Variants allow multiple display_text realizations (e.g., different campaigns).
"""
product_id: str
attributes: Dict[str, Any]
display_name: Optional[str] = None
display_text: Optional[str] = None
schema_version: str = "0.1.0"
display_variant: str = "default"
spec_key: Optional[str] = None # hash of attributes + id + schema_version
text_key: Optional[str] = None # hash of display_text (if present)
meta: Dict[str, Any] = field(default_factory=dict)
provenance: Dict[str, Any] = field(default_factory=dict)
[docs]
def compute_keys(self) -> None:
if self.spec_key is None:
payload = {
"schema_version": self.schema_version,
"product_id": self.product_id,
"attributes": self.attributes,
}
self.spec_key = sha256_json(payload)
if self.display_text is not None and self.text_key is None:
self.text_key = sha256_text(self.display_text)
[docs]
def to_dict(self) -> Dict[str, Any]:
self.compute_keys()
return {
"product_id": self.product_id,
"attributes": self.attributes,
"display_name": self.display_name,
"display_text": self.display_text,
"schema_version": self.schema_version,
"display_variant": self.display_variant,
"spec_key": self.spec_key,
"text_key": self.text_key,
"meta": self.meta,
"provenance": self.provenance,
}
[docs]
@staticmethod
def from_dict(d: Dict[str, Any]) -> "ProductRecord":
rec = ProductRecord(
product_id=d["product_id"],
attributes=d.get("attributes") or {},
display_name=d.get("display_name"),
display_text=d.get("display_text"),
schema_version=d.get("schema_version", "0.1.0"),
display_variant=d.get("display_variant", "default"),
spec_key=d.get("spec_key"),
text_key=d.get("text_key"),
meta=d.get("meta") or {},
provenance=d.get("provenance") or {},
)
rec.compute_keys()
return rec